using System; using System.Collections.Generic; using System.Linq; using System.Text; using DTS.Common.Classes.Locking; using DTS.Common.Import.Interfaces; using DTS.Common.SharedResource.Strings; using DTS.Common.Storage; using DTS.Common.Utilities.Logging; using DTS.Slice.Users; //FB 36740 namespace DTS.Common.Import.DatabaseLocks { public class LockImportGroups : ILockImport { private readonly User _currentUser; private readonly double _strandedLockTimeoutMinutes; /// /// this is a list of all groups locked by the user /// private readonly List _lockedGroups = new List(); /// /// this is a list of all groups the user attempted to lock but another user has the lock /// private readonly List _contendedGroups = new List(); public bool Contended { get => _contendedGroups.Any(); } public LockImportGroups(User currentUser, double strandedLockTimeoutMinutes) { _currentUser = currentUser; _strandedLockTimeoutMinutes = strandedLockTimeoutMinutes; } public void FreeLock(ref ImportObject importObject) { if (!_lockedGroups.Any()) { return; } foreach (var record in _lockedGroups) { LockManager.FreeLock(record.ItemId, _currentUser.UserName, _currentUser.Id, out var lockError, record.ItemCategory); } } public void SetLock(ref ImportObject importObject, ref StringBuilder message) { _lockedGroups.Clear(); _contendedGroups.Clear(); foreach (var group in importObject.StaticGroups()) { try { if (!LockManager.LockItem(group.Name, group.Id, LockManager.ItemCategories.Group, _currentUser.UserName, _currentUser.Id, out var existingLock, out var lockError)) { if (lockError.ErrorCode == LockError.ITEM_NOT_FOUND) { continue; //lock not needed, doesn't exist in db } var lockOutOfDate = existingLock.LastUpdated.AddMinutes(_strandedLockTimeoutMinutes) < DateTime.Now; var IHaveTheLock = existingLock.LockingUserName == _currentUser.UserName && existingLock.LockingMachineName == Environment.MachineName; if (lockOutOfDate || IHaveTheLock) { //lock is expired (or already belongs to us), either way we can claim it LockManager.FreeLock(existingLock.ItemId, _currentUser.UserName, _currentUser.Id, out lockError, existingLock.ItemCategory); LockManager.LockItem(existingLock.ItemKey, existingLock.ItemId, LockManager.ItemCategories.Group, _currentUser.UserName, _currentUser.Id, out existingLock, out lockError); _lockedGroups.Add(existingLock); } else { //could not lock, we need Admin + confirmation to lock _contendedGroups.Add(existingLock); } } else { //successfully locked _lockedGroups.Add(existingLock); } } catch (Exception ex) { APILogger.Log(ex); } } if (!_contendedGroups.Any()) { return; } message.AppendLine(StringResources.ImportTestSetup_GroupsLocked); foreach (var contended in _contendedGroups) { message.AppendLine($"{contended.ItemKey} by {contended.LockingUserName} on {contended.LockingMachineName}"); } } public bool StealLock(bool proceed) { if (!_contendedGroups.Any()) { return true; } if (!_currentUser.IsAdmin) { return false; } //steal locks if user oks it if (!proceed) { return false; } foreach (var contendedGroup in _contendedGroups) { LockManager.FreeLock(contendedGroup.ItemId, _currentUser.UserName, _currentUser.Id, out var lockError, contendedGroup.ItemCategory); LockManager.LockItem(contendedGroup.ItemKey, contendedGroup.ItemId, LockManager.ItemCategories.Sensor, _currentUser.UserName, _currentUser.Id, out var newLockRecord, out lockError); _lockedGroups.Add(newLockRecord); } return true; } } }