mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-03-11 20:56:32 +00:00
Merge remote-tracking branch 'upstream/master' into 3.1.7
This commit is contained in:
@@ -2,8 +2,8 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Activity
|
||||
@@ -27,16 +27,6 @@ namespace Jellyfin.Server.Implementations.Activity
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Create(ActivityLog entry)
|
||||
{
|
||||
using var dbContext = _provider.CreateContext();
|
||||
dbContext.ActivityLogs.Add(entry);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
EntryCreated?.Invoke(this, new GenericEventArgs<ActivityLogEntry>(ConvertToOldModel(entry)));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task CreateAsync(ActivityLog entry)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log whenever a subtitle download fails.
|
||||
/// </summary>
|
||||
public class SubtitleDownloadFailureLogger : IEventConsumer<SubtitleDownloadFailureEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubtitleDownloadFailureLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public SubtitleDownloadFailureLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(SubtitleDownloadFailureEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("SubtitleDownloadFailureFromForItem"),
|
||||
eventArgs.Provider,
|
||||
GetItemName(eventArgs.Item)),
|
||||
"SubtitleDownloadFailure",
|
||||
Guid.Empty)
|
||||
{
|
||||
ItemId = eventArgs.Item.Id.ToString("N", CultureInfo.InvariantCulture),
|
||||
ShortOverview = eventArgs.Exception.Message
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string GetItemName(BaseItem item)
|
||||
{
|
||||
var name = item.Name;
|
||||
if (item is Episode episode)
|
||||
{
|
||||
if (episode.IndexNumber.HasValue)
|
||||
{
|
||||
name = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Ep{0} - {1}",
|
||||
episode.IndexNumber.Value,
|
||||
name);
|
||||
}
|
||||
|
||||
if (episode.ParentIndexNumber.HasValue)
|
||||
{
|
||||
name = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"S{0}, {1}",
|
||||
episode.ParentIndexNumber.Value,
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
if (item is IHasSeries hasSeries)
|
||||
{
|
||||
name = hasSeries.SeriesName + " - " + name;
|
||||
}
|
||||
|
||||
if (item is IHasAlbumArtist hasAlbumArtist)
|
||||
{
|
||||
var artists = hasAlbumArtist.AlbumArtists;
|
||||
|
||||
if (artists.Count > 0)
|
||||
{
|
||||
name = artists[0] + " - " + name;
|
||||
}
|
||||
}
|
||||
else if (item is IHasArtist hasArtist)
|
||||
{
|
||||
var artists = hasArtist.Artists;
|
||||
|
||||
if (artists.Count > 0)
|
||||
{
|
||||
name = artists[0] + " - " + name;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when there is a failed login attempt.
|
||||
/// </summary>
|
||||
public class AuthenticationFailedLogger : IEventConsumer<GenericEventArgs<AuthenticationRequest>>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationFailedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public AuthenticationFailedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(GenericEventArgs<AuthenticationRequest> eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("FailedLoginAttemptWithUserName"),
|
||||
eventArgs.Argument.Username),
|
||||
"AuthenticationFailed",
|
||||
Guid.Empty)
|
||||
{
|
||||
LogSeverity = LogLevel.Error,
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("LabelIpAddressValue"),
|
||||
eventArgs.Argument.RemoteEndPoint),
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when there is a successful login attempt.
|
||||
/// </summary>
|
||||
public class AuthenticationSucceededLogger : IEventConsumer<GenericEventArgs<AuthenticationResult>>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationSucceededLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public AuthenticationSucceededLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(GenericEventArgs<AuthenticationResult> e)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("AuthenticationSucceededWithUserName"),
|
||||
e.Argument.User.Name),
|
||||
"AuthenticationSucceeded",
|
||||
e.Argument.User.Id)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("LabelIpAddressValue"),
|
||||
e.Argument.SessionInfo.RemoteEndPoint),
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Session
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log whenever a user starts playback.
|
||||
/// </summary>
|
||||
public class PlaybackStartLogger : IEventConsumer<PlaybackStartEventArgs>
|
||||
{
|
||||
private readonly ILogger<PlaybackStartLogger> _logger;
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaybackStartLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public PlaybackStartLogger(ILogger<PlaybackStartLogger> logger, ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PlaybackStartEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.MediaInfo == null)
|
||||
{
|
||||
_logger.LogWarning("PlaybackStart reported with null media info.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventArgs.Item != null && eventArgs.Item.IsThemeMedia)
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventArgs.Users.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var user = eventArgs.Users[0];
|
||||
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserStartedPlayingItemWithValues"),
|
||||
user.Username,
|
||||
GetItemName(eventArgs.MediaInfo),
|
||||
eventArgs.DeviceName),
|
||||
GetPlaybackNotificationType(eventArgs.MediaInfo.MediaType),
|
||||
user.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string GetItemName(BaseItemDto item)
|
||||
{
|
||||
var name = item.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(item.SeriesName))
|
||||
{
|
||||
name = item.SeriesName + " - " + name;
|
||||
}
|
||||
|
||||
if (item.Artists != null && item.Artists.Count > 0)
|
||||
{
|
||||
name = item.Artists[0] + " - " + name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private static string GetPlaybackNotificationType(string mediaType)
|
||||
{
|
||||
if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.AudioPlayback.ToString();
|
||||
}
|
||||
|
||||
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.VideoPlayback.ToString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Session
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an activity log entry whenever a user stops playback.
|
||||
/// </summary>
|
||||
public class PlaybackStopLogger : IEventConsumer<PlaybackStopEventArgs>
|
||||
{
|
||||
private readonly ILogger<PlaybackStopLogger> _logger;
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaybackStopLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public PlaybackStopLogger(ILogger<PlaybackStopLogger> logger, ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PlaybackStopEventArgs eventArgs)
|
||||
{
|
||||
var item = eventArgs.MediaInfo;
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
_logger.LogWarning("PlaybackStopped reported with null media info.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventArgs.Item != null && eventArgs.Item.IsThemeMedia)
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventArgs.Users.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var user = eventArgs.Users[0];
|
||||
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserStoppedPlayingItemWithValues"),
|
||||
user.Username,
|
||||
GetItemName(item),
|
||||
eventArgs.DeviceName),
|
||||
GetPlaybackStoppedNotificationType(item.MediaType),
|
||||
user.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string GetItemName(BaseItemDto item)
|
||||
{
|
||||
var name = item.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(item.SeriesName))
|
||||
{
|
||||
name = item.SeriesName + " - " + name;
|
||||
}
|
||||
|
||||
if (item.Artists != null && item.Artists.Count > 0)
|
||||
{
|
||||
name = item.Artists[0] + " - " + name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private static string GetPlaybackStoppedNotificationType(string mediaType)
|
||||
{
|
||||
if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.AudioPlaybackStopped.ToString();
|
||||
}
|
||||
|
||||
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.VideoPlaybackStopped.ToString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Session;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Session
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log whenever a session ends.
|
||||
/// </summary>
|
||||
public class SessionEndedLogger : IEventConsumer<SessionEndedEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionEndedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public SessionEndedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(SessionEndedEventArgs eventArgs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(eventArgs.Argument.UserName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserOfflineFromDevice"),
|
||||
eventArgs.Argument.UserName,
|
||||
eventArgs.Argument.DeviceName),
|
||||
"SessionEnded",
|
||||
eventArgs.Argument.UserId)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("LabelIpAddressValue"),
|
||||
eventArgs.Argument.RemoteEndPoint),
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Session;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Session
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a session is started.
|
||||
/// </summary>
|
||||
public class SessionStartedLogger : IEventConsumer<SessionStartedEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionStartedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public SessionStartedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(SessionStartedEventArgs eventArgs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(eventArgs.Argument.UserName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserOnlineFromDevice"),
|
||||
eventArgs.Argument.UserName,
|
||||
eventArgs.Argument.DeviceName),
|
||||
"SessionStarted",
|
||||
eventArgs.Argument.UserId)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("LabelIpAddressValue"),
|
||||
eventArgs.Argument.RemoteEndPoint)
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events.System;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.System
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies users when there is a pending restart.
|
||||
/// </summary>
|
||||
public class PendingRestartNotifier : IEventConsumer<PendingRestartEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PendingRestartNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public PendingRestartNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PendingRestartEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendRestartRequiredNotification(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.System
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an activity log entry whenever a task is completed.
|
||||
/// </summary>
|
||||
public class TaskCompletedLogger : IEventConsumer<TaskCompletionEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TaskCompletedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public TaskCompletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(TaskCompletionEventArgs e)
|
||||
{
|
||||
var result = e.Result;
|
||||
var task = e.Task;
|
||||
|
||||
if (task.ScheduledTask is IConfigurableScheduledTask activityTask
|
||||
&& !activityTask.IsLogged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var time = result.EndTimeUtc - result.StartTimeUtc;
|
||||
var runningTime = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("LabelRunningTimeValue"),
|
||||
ToUserFriendlyString(time));
|
||||
|
||||
if (result.Status == TaskCompletionStatus.Failed)
|
||||
{
|
||||
var vals = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(e.Result.ErrorMessage))
|
||||
{
|
||||
vals.Add(e.Result.ErrorMessage);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(e.Result.LongErrorMessage))
|
||||
{
|
||||
vals.Add(e.Result.LongErrorMessage);
|
||||
}
|
||||
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
|
||||
NotificationType.TaskFailed.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
LogSeverity = LogLevel.Error,
|
||||
Overview = string.Join(Environment.NewLine, vals),
|
||||
ShortOverview = runningTime
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ToUserFriendlyString(TimeSpan span)
|
||||
{
|
||||
const int DaysInYear = 365;
|
||||
const int DaysInMonth = 30;
|
||||
|
||||
// Get each non-zero value from TimeSpan component
|
||||
var values = new List<string>();
|
||||
|
||||
// Number of years
|
||||
int days = span.Days;
|
||||
if (days >= DaysInYear)
|
||||
{
|
||||
int years = days / DaysInYear;
|
||||
values.Add(CreateValueString(years, "year"));
|
||||
days %= DaysInYear;
|
||||
}
|
||||
|
||||
// Number of months
|
||||
if (days >= DaysInMonth)
|
||||
{
|
||||
int months = days / DaysInMonth;
|
||||
values.Add(CreateValueString(months, "month"));
|
||||
days = days % DaysInMonth;
|
||||
}
|
||||
|
||||
// Number of days
|
||||
if (days >= 1)
|
||||
{
|
||||
values.Add(CreateValueString(days, "day"));
|
||||
}
|
||||
|
||||
// Number of hours
|
||||
if (span.Hours >= 1)
|
||||
{
|
||||
values.Add(CreateValueString(span.Hours, "hour"));
|
||||
}
|
||||
|
||||
// Number of minutes
|
||||
if (span.Minutes >= 1)
|
||||
{
|
||||
values.Add(CreateValueString(span.Minutes, "minute"));
|
||||
}
|
||||
|
||||
// Number of seconds (include when 0 if no other components included)
|
||||
if (span.Seconds >= 1 || values.Count == 0)
|
||||
{
|
||||
values.Add(CreateValueString(span.Seconds, "second"));
|
||||
}
|
||||
|
||||
// Combine values into string
|
||||
var builder = new StringBuilder();
|
||||
for (int i = 0; i < values.Count; i++)
|
||||
{
|
||||
if (builder.Length > 0)
|
||||
{
|
||||
builder.Append(i == values.Count - 1 ? " and " : ", ");
|
||||
}
|
||||
|
||||
builder.Append(values[i]);
|
||||
}
|
||||
|
||||
// Return result
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a string description of a time-span value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of this item.</param>
|
||||
/// <param name="description">The name of this item (singular form).</param>
|
||||
private static string CreateValueString(int value, string description)
|
||||
{
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"{0:#,##0} {1}",
|
||||
value,
|
||||
value == 1 ? description : string.Format(CultureInfo.InvariantCulture, "{0}s", description));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.System
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies admin users when a task is completed.
|
||||
/// </summary>
|
||||
public class TaskCompletedNotifier : IEventConsumer<TaskCompletionEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TaskCompletedNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public TaskCompletedNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(TaskCompletionEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendMessageToAdminSessions("ScheduledTaskEnded", eventArgs.Result, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies admin users when a plugin installation is cancelled.
|
||||
/// </summary>
|
||||
public class PluginInstallationCancelledNotifier : IEventConsumer<PluginInstallationCancelledEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallationCancelledNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public PluginInstallationCancelledNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PluginInstallationCancelledEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendMessageToAdminSessions("PackageInstallationCancelled", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a package installation fails.
|
||||
/// </summary>
|
||||
public class PluginInstallationFailedLogger : IEventConsumer<InstallationFailedEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallationFailedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public PluginInstallationFailedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(InstallationFailedEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("NameInstallFailed"),
|
||||
eventArgs.InstallationInfo.Name),
|
||||
NotificationType.InstallationFailed.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("VersionNumber"),
|
||||
eventArgs.InstallationInfo.Version),
|
||||
Overview = eventArgs.Exception.Message
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies admin users when a plugin installation fails.
|
||||
/// </summary>
|
||||
public class PluginInstallationFailedNotifier : IEventConsumer<InstallationFailedEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallationFailedNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public PluginInstallationFailedNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(InstallationFailedEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendMessageToAdminSessions("PackageInstallationFailed", eventArgs.InstallationInfo, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a plugin is installed.
|
||||
/// </summary>
|
||||
public class PluginInstalledLogger : IEventConsumer<PluginInstalledEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstalledLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public PluginInstalledLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PluginInstalledEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("PluginInstalledWithName"),
|
||||
eventArgs.Argument.Name),
|
||||
NotificationType.PluginInstalled.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("VersionNumber"),
|
||||
eventArgs.Argument.Version)
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies admin users when a plugin is installed.
|
||||
/// </summary>
|
||||
public class PluginInstalledNotifier : IEventConsumer<PluginInstalledEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstalledNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public PluginInstalledNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PluginInstalledEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendMessageToAdminSessions("PackageInstallationCompleted", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies admin users when a plugin is being installed.
|
||||
/// </summary>
|
||||
public class PluginInstallingNotifier : IEventConsumer<PluginInstallingEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallingNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public PluginInstallingNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PluginInstallingEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendMessageToAdminSessions("PackageInstalling", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a plugin is uninstalled.
|
||||
/// </summary>
|
||||
public class PluginUninstalledLogger : IEventConsumer<PluginUninstalledEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginUninstalledLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public PluginUninstalledLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PluginUninstalledEventArgs e)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("PluginUninstalledWithName"),
|
||||
e.Argument.Name),
|
||||
NotificationType.PluginUninstalled.ToString(),
|
||||
Guid.Empty))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies admin users when a plugin is uninstalled.
|
||||
/// </summary>
|
||||
public class PluginUninstalledNotifier : IEventConsumer<PluginUninstalledEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginUninstalledNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public PluginUninstalledNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PluginUninstalledEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendMessageToAdminSessions("PluginUninstalled", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a plugin is updated.
|
||||
/// </summary>
|
||||
public class PluginUpdatedLogger : IEventConsumer<PluginUpdatedEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginUpdatedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public PluginUpdatedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(PluginUpdatedEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("PluginUpdatedWithName"),
|
||||
eventArgs.Argument.Name),
|
||||
NotificationType.PluginUpdateInstalled.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("VersionNumber"),
|
||||
eventArgs.Argument.Version),
|
||||
Overview = eventArgs.Argument.Changelog
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a user is created.
|
||||
/// </summary>
|
||||
public class UserCreatedLogger : IEventConsumer<UserCreatedEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserCreatedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public UserCreatedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(UserCreatedEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserCreatedWithName"),
|
||||
eventArgs.Argument.Username),
|
||||
"UserCreated",
|
||||
eventArgs.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an entry to the activity log when a user is deleted.
|
||||
/// </summary>
|
||||
public class UserDeletedLogger : IEventConsumer<UserDeletedEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserDeletedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public UserDeletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(UserDeletedEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserDeletedWithName"),
|
||||
eventArgs.Argument.Username),
|
||||
"UserDeleted",
|
||||
Guid.Empty))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies the user's sessions when a user is deleted.
|
||||
/// </summary>
|
||||
public class UserDeletedNotifier : IEventConsumer<UserDeletedEventArgs>
|
||||
{
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserDeletedNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public UserDeletedNotifier(ISessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(UserDeletedEventArgs eventArgs)
|
||||
{
|
||||
await _sessionManager.SendMessageToUserSessions(
|
||||
new List<Guid> { eventArgs.Argument.Id },
|
||||
"UserDeleted",
|
||||
eventArgs.Argument.Id.ToString("N", CultureInfo.InvariantCulture),
|
||||
CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a user is locked out.
|
||||
/// </summary>
|
||||
public class UserLockedOutLogger : IEventConsumer<UserLockedOutEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserLockedOutLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public UserLockedOutLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(UserLockedOutEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserLockedOutWithName"),
|
||||
eventArgs.Argument.Username),
|
||||
NotificationType.UserLockedOut.ToString(),
|
||||
eventArgs.Argument.Id)
|
||||
{
|
||||
LogSeverity = LogLevel.Error
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an entry in the activity log when a user's password is changed.
|
||||
/// </summary>
|
||||
public class UserPasswordChangedLogger : IEventConsumer<UserPasswordChangedEventArgs>
|
||||
{
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserPasswordChangedLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="localizationManager">The localization manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
public UserPasswordChangedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
|
||||
{
|
||||
_localizationManager = localizationManager;
|
||||
_activityManager = activityManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(UserPasswordChangedEventArgs eventArgs)
|
||||
{
|
||||
await _activityManager.CreateAsync(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localizationManager.GetLocalizedString("UserPasswordChangedWithName"),
|
||||
eventArgs.Argument.Username),
|
||||
"UserPasswordChanged",
|
||||
eventArgs.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
|
||||
{
|
||||
/// <summary>
|
||||
/// Notifies a user when their account has been updated.
|
||||
/// </summary>
|
||||
public class UserUpdatedNotifier : IEventConsumer<UserUpdatedEventArgs>
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserUpdatedNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public UserUpdatedNotifier(IUserManager userManager, ISessionManager sessionManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnEvent(UserUpdatedEventArgs e)
|
||||
{
|
||||
await _sessionManager.SendMessageToUserSessions(
|
||||
new List<Guid> { e.Argument.Id },
|
||||
"UserUpdated",
|
||||
_userManager.GetUserDto(e.Argument),
|
||||
CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Jellyfin.Server.Implementations/Events/EventManager.cs
Normal file
60
Jellyfin.Server.Implementations/Events/EventManager.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the firing of events.
|
||||
/// </summary>
|
||||
public class EventManager : IEventManager
|
||||
{
|
||||
private readonly ILogger<EventManager> _logger;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EventManager"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="appHost">The application host.</param>
|
||||
public EventManager(ILogger<EventManager> logger, IServerApplicationHost appHost)
|
||||
{
|
||||
_logger = logger;
|
||||
_appHost = appHost;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Publish<T>(T eventArgs)
|
||||
where T : EventArgs
|
||||
{
|
||||
Task.WaitAll(PublishInternal(eventArgs));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task PublishAsync<T>(T eventArgs)
|
||||
where T : EventArgs
|
||||
{
|
||||
await PublishInternal(eventArgs).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task PublishInternal<T>(T eventArgs)
|
||||
where T : EventArgs
|
||||
{
|
||||
using var scope = _appHost.ServiceProvider.CreateScope();
|
||||
foreach (var service in scope.ServiceProvider.GetServices<IEventConsumer<T>>())
|
||||
{
|
||||
try
|
||||
{
|
||||
await service.OnEvent(eventArgs).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Uncaught exception in EventConsumer {type}: ", service.GetType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using Jellyfin.Data.Events;
|
||||
using Jellyfin.Data.Events.System;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using Jellyfin.Server.Implementations.Events.Consumers.Library;
|
||||
using Jellyfin.Server.Implementations.Events.Consumers.Security;
|
||||
using Jellyfin.Server.Implementations.Events.Consumers.Session;
|
||||
using Jellyfin.Server.Implementations.Events.Consumers.System;
|
||||
using Jellyfin.Server.Implementations.Events.Consumers.Updates;
|
||||
using Jellyfin.Server.Implementations.Events.Consumers.Users;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Session;
|
||||
using MediaBrowser.Controller.Events.Updates;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// A class containing extensions to <see cref="IServiceCollection"/> for eventing.
|
||||
/// </summary>
|
||||
public static class EventingServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the event services to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="collection">The service collection.</param>
|
||||
public static void AddEventServices(this IServiceCollection collection)
|
||||
{
|
||||
// Library consumers
|
||||
collection.AddScoped<IEventConsumer<SubtitleDownloadFailureEventArgs>, SubtitleDownloadFailureLogger>();
|
||||
|
||||
// Security consumers
|
||||
collection.AddScoped<IEventConsumer<GenericEventArgs<AuthenticationRequest>>, AuthenticationFailedLogger>();
|
||||
collection.AddScoped<IEventConsumer<GenericEventArgs<AuthenticationResult>>, AuthenticationSucceededLogger>();
|
||||
|
||||
// Session consumers
|
||||
collection.AddScoped<IEventConsumer<PlaybackStartEventArgs>, PlaybackStartLogger>();
|
||||
collection.AddScoped<IEventConsumer<PlaybackStopEventArgs>, PlaybackStopLogger>();
|
||||
collection.AddScoped<IEventConsumer<SessionEndedEventArgs>, SessionEndedLogger>();
|
||||
collection.AddScoped<IEventConsumer<SessionStartedEventArgs>, SessionStartedLogger>();
|
||||
|
||||
// System consumers
|
||||
collection.AddScoped<IEventConsumer<PendingRestartEventArgs>, PendingRestartNotifier>();
|
||||
collection.AddScoped<IEventConsumer<TaskCompletionEventArgs>, TaskCompletedLogger>();
|
||||
collection.AddScoped<IEventConsumer<TaskCompletionEventArgs>, TaskCompletedNotifier>();
|
||||
|
||||
// Update consumers
|
||||
collection.AddScoped<IEventConsumer<PluginInstallationCancelledEventArgs>, PluginInstallationCancelledNotifier>();
|
||||
collection.AddScoped<IEventConsumer<InstallationFailedEventArgs>, PluginInstallationFailedLogger>();
|
||||
collection.AddScoped<IEventConsumer<InstallationFailedEventArgs>, PluginInstallationFailedNotifier>();
|
||||
collection.AddScoped<IEventConsumer<PluginInstalledEventArgs>, PluginInstalledLogger>();
|
||||
collection.AddScoped<IEventConsumer<PluginInstalledEventArgs>, PluginInstalledNotifier>();
|
||||
collection.AddScoped<IEventConsumer<PluginInstallingEventArgs>, PluginInstallingNotifier>();
|
||||
collection.AddScoped<IEventConsumer<PluginUninstalledEventArgs>, PluginUninstalledLogger>();
|
||||
collection.AddScoped<IEventConsumer<PluginUninstalledEventArgs>, PluginUninstalledNotifier>();
|
||||
collection.AddScoped<IEventConsumer<PluginUpdatedEventArgs>, PluginUpdatedLogger>();
|
||||
|
||||
// User consumers
|
||||
collection.AddScoped<IEventConsumer<UserCreatedEventArgs>, UserCreatedLogger>();
|
||||
collection.AddScoped<IEventConsumer<UserDeletedEventArgs>, UserDeletedLogger>();
|
||||
collection.AddScoped<IEventConsumer<UserDeletedEventArgs>, UserDeletedNotifier>();
|
||||
collection.AddScoped<IEventConsumer<UserLockedOutEventArgs>, UserLockedOutLogger>();
|
||||
collection.AddScoped<IEventConsumer<UserPasswordChangedEventArgs>, UserPasswordChangedLogger>();
|
||||
collection.AddScoped<IEventConsumer<UserUpdatedEventArgs>, UserUpdatedNotifier>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Events;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Users
|
||||
{
|
||||
|
||||
@@ -10,18 +10,20 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Events;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Cryptography;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Users;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -34,6 +36,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
public class UserManager : IUserManager
|
||||
{
|
||||
private readonly JellyfinDbProvider _dbProvider;
|
||||
private readonly IEventManager _eventManager;
|
||||
private readonly ICryptoProvider _cryptoProvider;
|
||||
private readonly INetworkManager _networkManager;
|
||||
private readonly IApplicationHost _appHost;
|
||||
@@ -49,6 +52,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
/// Initializes a new instance of the <see cref="UserManager"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dbProvider">The database provider.</param>
|
||||
/// <param name="eventManager">The event manager.</param>
|
||||
/// <param name="cryptoProvider">The cryptography provider.</param>
|
||||
/// <param name="networkManager">The network manager.</param>
|
||||
/// <param name="appHost">The application host.</param>
|
||||
@@ -56,6 +60,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
/// <param name="logger">The logger.</param>
|
||||
public UserManager(
|
||||
JellyfinDbProvider dbProvider,
|
||||
IEventManager eventManager,
|
||||
ICryptoProvider cryptoProvider,
|
||||
INetworkManager networkManager,
|
||||
IApplicationHost appHost,
|
||||
@@ -63,6 +68,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
ILogger<UserManager> logger)
|
||||
{
|
||||
_dbProvider = dbProvider;
|
||||
_eventManager = eventManager;
|
||||
_cryptoProvider = cryptoProvider;
|
||||
_networkManager = networkManager;
|
||||
_appHost = appHost;
|
||||
@@ -77,21 +83,9 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
_defaultPasswordResetProvider = _passwordResetProviders.OfType<DefaultPasswordResetProvider>().First();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<GenericEventArgs<User>>? OnUserPasswordChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<GenericEventArgs<User>>? OnUserUpdated;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<GenericEventArgs<User>>? OnUserCreated;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<GenericEventArgs<User>>? OnUserDeleted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<GenericEventArgs<User>>? OnUserLockedOut;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<User> Users
|
||||
{
|
||||
@@ -234,7 +228,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
dbContext.Users.Add(newUser);
|
||||
await dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
OnUserCreated?.Invoke(this, new GenericEventArgs<User>(newUser));
|
||||
await _eventManager.PublishAsync(new UserCreatedEventArgs(newUser)).ConfigureAwait(false);
|
||||
|
||||
return newUser;
|
||||
}
|
||||
@@ -293,7 +287,8 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
dbContext.RemoveRange(user.AccessSchedules);
|
||||
dbContext.Users.Remove(user);
|
||||
dbContext.SaveChanges();
|
||||
OnUserDeleted?.Invoke(this, new GenericEventArgs<User>(user));
|
||||
|
||||
_eventManager.Publish(new UserDeletedEventArgs(user));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -319,7 +314,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false);
|
||||
await UpdateUserAsync(user).ConfigureAwait(false);
|
||||
|
||||
OnUserPasswordChanged?.Invoke(this, new GenericEventArgs<User>(user));
|
||||
await _eventManager.PublishAsync(new UserPasswordChangedEventArgs(user)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -338,7 +333,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
user.EasyPassword = newPasswordSha1;
|
||||
UpdateUser(user);
|
||||
|
||||
OnUserPasswordChanged?.Invoke(this, new GenericEventArgs<User>(user));
|
||||
_eventManager.Publish(new UserPasswordChangedEventArgs(user));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -407,13 +402,13 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
EnablePublicSharing = user.HasPermission(PermissionKind.EnablePublicSharing),
|
||||
AccessSchedules = user.AccessSchedules.ToArray(),
|
||||
BlockedTags = user.GetPreference(PreferenceKind.BlockedTags),
|
||||
EnabledChannels = user.GetPreference(PreferenceKind.EnabledChannels),
|
||||
EnabledChannels = user.GetPreference(PreferenceKind.EnabledChannels)?.Select(Guid.Parse).ToArray(),
|
||||
EnabledDevices = user.GetPreference(PreferenceKind.EnabledDevices),
|
||||
EnabledFolders = user.GetPreference(PreferenceKind.EnabledFolders),
|
||||
EnabledFolders = user.GetPreference(PreferenceKind.EnabledFolders)?.Select(Guid.Parse).ToArray(),
|
||||
EnableContentDeletionFromFolders = user.GetPreference(PreferenceKind.EnableContentDeletionFromFolders),
|
||||
SyncPlayAccess = user.SyncPlayAccess,
|
||||
BlockedChannels = user.GetPreference(PreferenceKind.BlockedChannels),
|
||||
BlockedMediaFolders = user.GetPreference(PreferenceKind.BlockedMediaFolders),
|
||||
BlockedChannels = user.GetPreference(PreferenceKind.BlockedChannels)?.Select(Guid.Parse).ToArray(),
|
||||
BlockedMediaFolders = user.GetPreference(PreferenceKind.BlockedMediaFolders)?.Select(Guid.Parse).ToArray(),
|
||||
BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems).Select(Enum.Parse<UnratedItem>).ToArray()
|
||||
}
|
||||
};
|
||||
@@ -740,9 +735,9 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
PreferenceKind.BlockUnratedItems,
|
||||
policy.BlockUnratedItems?.Select(i => i.ToString()).ToArray() ?? Array.Empty<string>());
|
||||
user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags);
|
||||
user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels);
|
||||
user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray());
|
||||
user.SetPreference(PreferenceKind.EnabledDevices, policy.EnabledDevices);
|
||||
user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders);
|
||||
user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray());
|
||||
user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders);
|
||||
|
||||
dbContext.Update(user);
|
||||
@@ -901,7 +896,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
if (maxInvalidLogins.HasValue && user.InvalidLoginAttemptCount >= maxInvalidLogins)
|
||||
{
|
||||
user.SetPermission(PermissionKind.IsDisabled, true);
|
||||
OnUserLockedOut?.Invoke(this, new GenericEventArgs<User>(user));
|
||||
await _eventManager.PublishAsync(new UserLockedOutEventArgs(user)).ConfigureAwait(false);
|
||||
_logger.LogWarning(
|
||||
"Disabling user {Username} due to {Attempts} unsuccessful login attempts.",
|
||||
user.Username,
|
||||
|
||||
Reference in New Issue
Block a user