--- source_files: - DataPRO/Users/ChallengeDialog.cs - DataPRO/Users/IUIItems.cs - DataPRO/Users/UIItemHelper.cs - DataPRO/Users/ChallengeDialog.designer.cs - DataPRO/Users/ITagAware.cs - DataPRO/Users/Tags.cs - DataPRO/Users/UserCollection.cs generated_at: "2026-04-17T15:49:59.567576+00:00" model: "zai-org/GLM-5-FP8" schema_version: 1 sha256: "ff967d41cf0dfb7b" --- # Documentation: DTS.Slice.Users Module ## 1. Purpose This module provides user management infrastructure for the DTS.Slice application, including authentication challenges, permission/visibility control for UI items, tag-based entity categorization, and user collection persistence. It handles the interaction between in-memory user objects, UI permission settings, and database storage, supporting both default role-based users and custom user configurations with tag-based access control. --- ## 2. Public Interface ### ChallengeDialog (Form) A Windows Forms dialog prompting for administrator password when elevated privileges are required. **Constructor:** - `ChallengeDialog()` - Initializes the dialog component. **UI Controls (publicly accessible):** - `tbPassword` - TextBox with `PasswordChar = '*'` and `UseSystemPasswordChar = true` - `lblLoginFailedMessage` - Label displaying login failure messages (DarkRed foreground) - `btnContinue` - Button to submit password - `btnCancel` - Button to cancel the operation - `label2` - Instructional label explaining admin access requirement --- ### IUIItems (Interface) Defines the contract for UI items that support role-based permission and visibility settings. | Method | Return Type | Description | |--------|-------------|-------------| | `GetDefaultRolePermission(User.DefaultRoles role)` | `User.UserPermissionLevels` | Gets the default permission level for a given role. | | `GetDefaultRoleVisibility(User.DefaultRoles role)` | `bool` | Gets the default visibility for a given role. | | `SetVisible(bool bShow)` | `void` | Sets the visibility state. | | `SetEnabled(bool bEnabled)` | `void` | Sets the enabled state. | | `GetRequiredPermission()` | `User.UserPermissionLevels` | Gets the required permission level. | | `GetName()` | `string` | Gets the UI item name. | | `GetID()` | `long` | Gets the UI item ID. | | `SetID(long id)` | `void` | Sets the UI item ID. | --- ### UIItemHelper (Class) A data container class for UI item settings. **Constructor:** - `UIItemHelper(long uiItemId, short permission, bool visible, string uiItemName)` **Properties:** | Property | Type | Access | |----------|------|--------| | `UIItemId` | `long` | get; private set; | | `UIItemName` | `string` | get; private set; | | `IsVisible` | `bool` | get; private set; | | `Permission` | `short` | get; private set; | --- ### TagAwareBase (Abstract Class) Abstract base class providing tag management functionality for entities that support tagging. **Enum: TagTypes** - `User`, `Group`, `Template`, `TestSetup`, `Sensors`, `SensorModels` **Abstract Property:** - `TagTypes TagType { get; }` - Must be implemented by derived classes. **Properties:** | Property | Type | Description | |----------|------|-------------| | `TagsBlobBytes` | `byte[]` | Gets/sets tags as a serialized byte array (4 bytes per int). | | `TagIDs` | `int[]` | Gets/sets the array of tag IDs. Never null; defaults to empty array. | **Methods:** | Method | Signature | Description | |--------|-----------|-------------| | `SetTagsFromCommaSeparatedString` | `void SetTagsFromCommaSeparatedString(string tagText)` | Parses comma-separated tags and sets them. | | `SetTags` | `virtual void SetTags(string[] tagsText)` | Sets tags from string array; notifies property change. | | `GetTagsAsCommaSeparatedString` | `string GetTagsAsCommaSeparatedString()` | Returns tags as comma-separated string. | | `GetTagsArray` | `virtual string[] GetTagsArray()` | Returns tag text array from IDs. | | `GetTagIDs` | `virtual int[] GetTagIDs()` | Returns the TagIDs array. | | `RemoveTags` | `virtual void RemoveTags(string[] tagsText)` | Removes specified tags. | | `TagCompatible` | `bool TagCompatible(string tags)` | Checks if any comma-separated tag matches. | | `TagCompatible` | `virtual bool TagCompatible(int[] tags)` | Checks if any tag ID intersects. | | `HasIntersectingTag` | `virtual bool HasIntersectingTag(int[] tags)` | Returns true if any tag ID is in TagIDs. | | `InsertTagsFromCommaSeparatedString` | `void InsertTagsFromCommaSeparatedString(int id, TagTypes tagType, string tags)` | Sets tags and commits to database. | | `Commit` | `void Commit(int id, TagTypes tagType)` | Persists tag assignments to database. | | `GetTagIdList` | `List GetTagIdList(int objectId, TagTypes tagType)` | Retrieves tag IDs for an object from database. | --- ### Tags (Class) Singleton class managing tag definitions with in-memory caching. **Nested Class: Tag** | Member | Type/Signature | Description | |--------|----------------|-------------| | `INVALID_ID` | `const int = -1` | Constant for invalid tag ID. | | `ID` | `int` | Tag identifier. | | `Text` | `string` | Tag display text. | | `IsObsolete` | `bool` | Obsolescence flag. | | `Tag(string tagText, int tagId)` | Constructor | Creates tag with text and ID. | | `Tag(Tag copy)` | Constructor | Copy constructor. | | `Tag(IDataRecord reader)` | Constructor | Constructs from data reader. | | `Tag(DataRow dr)` | Constructor | Constructs from data row. | | `Clone()` | `object` | ICloneable implementation. | **Static Property:** - `TagsInstance` - Singleton instance (lazy-initialized). **Static Methods:** | Method | Return Type | Description | |--------|-------------|-------------| | `AddTag(string tagText)` | `bool` | Adds tag to DB if not in cache; returns false if already exists or null/empty. | | `MigrateTag(string tagText)` | `bool` | Adds tag during migration (commits even if exists). | | `AddRange(string[] tagText)` | `bool[]` | Adds multiple tags with start-trimming; returns null if input is null/empty. | | `GetIDFromTagText(string tagText)` | `int` | Gets tag ID from database by text. | | `GetIDsFromTagText(string[] tagText)` | `int[]` | Gets array of IDs for tag texts; filters out INVALID_ID. | | `GetTagTextFromID(int tagID)` | `string` | Gets tag text from cache by ID; returns null if invalid/not found. | | `GetTagTextFromIDs(int[] tagId)` | `string[]` | Gets tag texts for IDs; skips invalid/null results. | **Instance Methods:** | Method | Signature | Description | |--------|-----------|-------------| | `ContainsTag` | `bool ContainsTag(string text)` | Checks if tag text exists in cache. | | `UpdateList` | `void UpdateList()` | Refreshes cache from database. | --- ### UserCollection (Class) Singleton managing user persistence and retrieval with thread-safe access. **Event:** - `PropertyChanged` - Implements `INotifyPropertyChanged`. **Static Property:** - `UsersList` - Singleton instance (thread-safe, lazy-initialized). **Static Methods:** | Method | Signature | Description | |--------|-----------|-------------| | `GetUserToTagIdLookup` | `Dictionary> GetUserToTagIdLookup()` | Returns mapping of user IDs to tag ID lists. | | `GetAllUsers` | `User[] GetAllUsers(IUIItems[] allItems, int? uid = null)` | Gets all users or single user if uid specified. Auto-creates default users. | | `GetUser` | `User GetUser(int uid, IUIItems[] items)` | Gets user by ID. | | `GetUser` | `User GetUser(string username, IUIItems[] items)` | Gets user by username. | **Instance Methods:** | Method | Signature | Description | |--------|-----------|-------------| | `Commit` | `void Commit(User user, string username, IUIItems[] items)` | Inserts/updates user, settings, permissions, and tags. Raises PropertyChanged. | | `Delete` | `void Delete(User user)` | Deletes a user from database. | | `Delete` | `void Delete(User[] users)` | Deletes multiple users. | --- ## 3. Invariants 1. **TagIDs never null**: `TagIDs` property always returns an array; setter converts null to `new int[0]`. 2. **Tag cache thread-safety**: All access to `_tagsLookup` in `Tags` class is protected by `LOCK_OBJECT`. 3. **UserCollection singleton thread-safety**: Access to `_userList` is protected by `MyLock`. 4. **Invalid tag ID constant**: `Tag.INVALID_ID` is always `-1`. Values ≤ 0 or equal to `INVALID_ID` are treated as invalid. 5. **Tag trimming**: Tags are trimmed at the start (not end) when added via `AddRange`. 6. **Default user auto-creation**: `GetAllUsers` automatically creates default role users and non-default power users if they don't exist in the database. 7. **TagsBlobBytes format**: Serialized as 4-byte integers via `Buffer.BlockCopy`. --- ## 4. Dependencies ### This module depends on: - `System.Windows.Forms` - For `ChallengeDialog` UI components - `System.Data.SqlClient` - For database operations - `DTS.Common.Storage` - For `DbOperations` and `DbOperationsEnum` - `DTS.Common.Utilities.Logging` - For `APILogger` - `DTS.Common.Classes` - Referenced in `UserCollection` - `DTS.Common.Interface.Tags` - Referenced in `UserCollection` - `DTS.Slice.Users.UserSettings` - For `TestSetupDefaults` and `Defaults` - `Common.Base.BasePropertyChanged` - Base class for `TagAwareBase` ### External dependencies inferred: - `User` class (referenced but not in provided source files) - `DbOperations` static class for database command creation - `DbOperations.Connection` for query execution --- ## 5. Gotchas 1. **RemoveTags is not implemented**: `TagAwareBase.RemoveTags(string[] tagsText)` has an empty method body with only a comment `// remove tags!!!` and `-;`. Calling this method does nothing. 2. **Tags cache staleness**: The `_tagsLookup` cache in `Tags` is only populated on construction and when `UpdateList()` is explicitly called. `AddTag` updates the cache, but external tag additions won't be reflected. 3. **GetAllUsers dual-purpose behavior**: The method serves two purposes based on the `uid` parameter. When `uid` is null, it auto-creates default users; when `uid` has a value, it returns only that user without auto-creation. 4. **ChallengeDialog has no event handlers**: The `btnContinue` and `btnCancel` buttons have no click events wired in the designer. The calling code must attach handlers. 5. **Error parameters ignored**: Stored procedure calls retrieve `@errorNumber` and `@errorMessage` output parameters, but the error message is never used—only the error number is checked against zero. 6. **Commented-out code references bug tracker**: A commented-out null check in `SetTagsFromCommaSeparatedString` references `http://fogbugz/fogbugz/default.asp?7176`, suggesting historical bug context. 7. **Tag trimming is asymmetric**: `AddRange` trims only the start of tags (`TrimStart()`), not the end. 8. **UpdateAll does nothing**: `Tags.UpdateAll(Tag tag)` only sets the ID from existing text; the comment indicates rename/edit/delete features are not implemented.