Class AdminService
- Namespace
- Builvero.Application.Services
- Assembly
- Builvero.Application.dll
Provides administrative operations for user management, invitation management, and bulk email communications.
public class AdminService : IAdminService
- Inheritance
-
AdminService
- Implements
- Inherited Members
Remarks
This service handles all administrative tasks including:
- User management (blocking, unblocking, role changes, profile retrieval)
- Invitation code creation and management
- Bulk email sending to users by role (Admin Updates feature)
- Project listing for administrative purposes
Constructors
AdminService(IUserRepository, IInvitationRepository, IProjectRepository, ITokenGenerator, IPasswordHasher, IS3Service, IEmailSender, IHostEnvironment, ILogger<AdminService>)
Initializes a new instance of the AdminService class.
public AdminService(IUserRepository userRepository, IInvitationRepository invitationRepository, IProjectRepository projectRepository, ITokenGenerator tokenGenerator, IPasswordHasher passwordHasher, IS3Service s3Service, IEmailSender emailSender, IHostEnvironment environment, ILogger<AdminService> logger)
Parameters
userRepositoryIUserRepositoryRepository for user data access operations.
invitationRepositoryIInvitationRepositoryRepository for invitation code management.
projectRepositoryIProjectRepositoryRepository for project data access operations.
tokenGeneratorITokenGeneratorService for generating secure tokens and invitation codes.
passwordHasherIPasswordHasherService for hashing and verifying passwords using BCrypt.
s3ServiceIS3ServiceService for S3 operations including presigned URL generation.
emailSenderIEmailSenderService for sending emails via SendGrid.
environmentIHostEnvironmentHost environment information for environment-aware behavior.
loggerILogger<AdminService>Logger for recording service operations and errors.
Methods
BlockUserAsync(Guid, CancellationToken)
Blocks a user account, preventing them from logging in or accessing the platform.
public Task BlockUserAsync(Guid userId, CancellationToken cancellationToken = default)
Parameters
userIdGuidThe unique identifier of the user to block.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task
- Provides administrative operations for user management, invitation management, and bulk email communications.
Remarks
This operation sets the user's status to Blocked and updates the UpdatedAt timestamp. Blocked users cannot authenticate or access any platform features.
Exceptions
- Exception
Thrown when the user is not found.
ChangeUserRoleAsync(Guid, string, CancellationToken)
Changes the role assigned to a user, affecting their permissions and access level.
public Task ChangeUserRoleAsync(Guid userId, string role, CancellationToken cancellationToken = default)
Parameters
userIdGuidThe unique identifier of the user whose role should be changed.
rolestringThe new role as a string (e.g., "Admin", "Moderator", "User"). Must match a UserRole enum value.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task
- Provides administrative operations for user management, invitation management, and bulk email communications.
Remarks
Role changes take effect immediately. Changing a user's role to "Admin" grants them full system access. The role string is case-sensitive and must exactly match an enum value name.
Exceptions
- Exception
Thrown when the role is invalid or the user is not found.
CreateInvitationAsync(Guid, CreateInvitationRequest, string, CancellationToken)
Creates a new invitation code that can be used for user registration.
public Task<InvitationDto> CreateInvitationAsync(Guid createdByUserId, CreateInvitationRequest request, string baseUrl, CancellationToken cancellationToken = default)
Parameters
createdByUserIdGuidThe unique identifier of the admin user creating the invitation.
requestCreateInvitationRequestThe invitation creation request containing max uses, expiration date, and optional label.
baseUrlstringThe base URL of the application, used to construct the full invitation link.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<InvitationDto>
An InvitationDto containing the created invitation details including the generated code and full invitation link.
Remarks
A unique invitation code is automatically generated. The invitation link is constructed as: {baseUrl}/auth/signup.html?invite={code} Invitations can have a maximum number of uses and an optional expiration date. Once created, the invitation is immediately active.
GetInvitationsAsync(int, int, CancellationToken)
Retrieves a paginated list of all invitation codes in the system.
public Task<(List<InvitationDto> Invitations, int TotalCount)> GetInvitationsAsync(int page, int pageSize, CancellationToken cancellationToken = default)
Parameters
pageintThe page number (1-based) to retrieve.
pageSizeintThe number of invitations per page.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<(List<InvitationDto> Invitations, int TotalCount)>
A tuple containing the list of invitations and the total count of all invitations.
Remarks
The invitation status is calculated based on expiration date, max uses, and current usage count. Status values are: "Active", "Exhausted" (used up), or "Expired" (past expiration date).
GetUserProfileAsync(Guid, CancellationToken)
Retrieves the complete profile information for a user, including profile photo with presigned URL.
public Task<ProfileDto> GetUserProfileAsync(Guid userId, CancellationToken cancellationToken = default)
Parameters
userIdGuidThe unique identifier of the user whose profile should be retrieved.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<ProfileDto>
A ProfileDto containing all profile information including education, experience, skills, and builder tags.
Remarks
Profile photo URLs are automatically converted to presigned URLs (15-minute TTL) for secure access. This prevents plain S3 URLs from being exposed. The profile photo object key is also returned for reference.
Exceptions
- Exception
Thrown when the user is not found, user email is missing, or profile is not found.
GetUserProjectsAsync(Guid, CancellationToken)
Retrieves all projects associated with a user, including projects they own and projects they are members of.
public Task<List<ProjectDto>> GetUserProjectsAsync(Guid userId, CancellationToken cancellationToken = default)
Parameters
userIdGuidThe unique identifier of the user whose projects should be retrieved.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<List<ProjectDto>>
A list of ProjectDto objects representing all projects for the user.
Remarks
For each project, the method determines the user's role (Owner or Member) and includes pending invitation and join request counts. Profile photo URLs for owners and members are automatically converted to presigned URLs (15-minute TTL) to prevent plain S3 URL leakage. External URLs (non-S3) are returned as-is without query parameters for consistency.
GetUsersAsync(int, int, string?, string?, string?, CancellationToken)
Retrieves a paginated list of users with optional filtering by search term, status, and role.
public Task<(List<UserListDto> Users, int TotalCount)> GetUsersAsync(int page, int pageSize, string? search = null, string? status = null, string? role = null, CancellationToken cancellationToken = default)
Parameters
pageintThe page number (1-based) to retrieve.
pageSizeintThe number of users per page.
searchstringOptional search term to filter users by email or name.
statusstringOptional status filter (e.g., "Active", "Blocked", "PendingVerification"). Must match UserStatus enum values.
rolestringOptional role filter (e.g., "User", "Admin", "Moderator"). Must match UserRole enum values.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<(List<UserListDto> Users, int TotalCount)>
A tuple containing the list of users and the total count matching the filters.
Remarks
Invalid status or role values are ignored (treated as null). The search term is applied to both email addresses and profile names.
SendAdminUpdatesAsync(List<UserRole>, string, CancellationToken)
Sends bulk email updates to all active users matching the specified roles using the SendGrid AdminUpdates template.
public Task<AdminUpdateSendResult> SendAdminUpdatesAsync(List<UserRole> roles, string htmlContent, CancellationToken cancellationToken = default)
Parameters
rolesList<UserRole>List of user roles to target. At least one role must be specified.
htmlContentstringRaw HTML content for the email body. Must not be empty or whitespace.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<AdminUpdateSendResult>
An AdminUpdateSendResult containing detailed statistics about the email sending operation.
Remarks
This method performs the following operations:
- Queries all active users matching the specified roles
- Automatically excludes users with email addresses containing "demo.builvero.local"
- Sends emails in batches of 100 recipients with a maximum of 10 concurrent sends to avoid rate limiting
- Collects individual failures without aborting the entire operation
The email subject is defined in the SendGrid template and cannot be overridden. The HTML content is sent as-is
to the template's content_html dynamic field. Recipient names are derived from profile full names or email local parts.
Failed email addresses are collected and reported (capped to first 20). Individual failures are logged but do not stop the operation from continuing with other recipients.
Exceptions
- ArgumentException
Thrown when roles list is null/empty or htmlContent is null/empty/whitespace.
- See Also
SendInvitationEmailsAsync(Guid, List<string>, string, Guid, string?, CancellationToken)
Sends invitation emails to multiple recipients for a specific invitation code.
public Task<SendInvitationResponse> SendInvitationEmailsAsync(Guid invitationId, List<string> emails, string baseUrl, Guid senderUserId, string? supportEmail = null, CancellationToken cancellationToken = default)
Parameters
invitationIdGuidThe unique identifier of the invitation to send.
emailsList<string>List of email addresses to send invitations to.
baseUrlstringThe base URL of the frontend application, used to construct invitation links.
senderUserIdGuidThe unique identifier of the admin user sending the invitations.
supportEmailstringOptional support email address to include in invitation emails.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<SendInvitationResponse>
A SendInvitationResponse containing per-email results (sent and failed).
Remarks
This method:
- Validates that the invitation exists
- Normalizes email addresses (lowercase, trim)
- Deduplicates email addresses
- Sends a separate email to each recipient
- Collects per-email results (success/failure)
Each email is sent independently. If one email fails, others will still be attempted. The method returns 200 OK even if some emails fail, with detailed per-email results.
The invitation link is constructed as: {baseUrl}/auth/signup.html?invite={code}
Exceptions
- Exception
Thrown when the invitation is not found.
UnblockUserAsync(Guid, CancellationToken)
Unblocks a user account, restoring their access to the platform.
public Task UnblockUserAsync(Guid userId, CancellationToken cancellationToken = default)
Parameters
userIdGuidThe unique identifier of the user to unblock.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task
- Provides administrative operations for user management, invitation management, and bulk email communications.
Remarks
This operation sets the user's status to Active and updates the UpdatedAt timestamp. The user can immediately log in and access platform features after being unblocked.
Exceptions
- Exception
Thrown when the user is not found.
UpdateInvitationAsync(Guid, UpdateInvitationRequest, CancellationToken)
Updates an existing invitation code's properties (max uses, expiration date, label).
public Task<InvitationDto> UpdateInvitationAsync(Guid invitationId, UpdateInvitationRequest request, CancellationToken cancellationToken = default)
Parameters
invitationIdGuidThe unique identifier of the invitation to update.
requestUpdateInvitationRequestThe update request containing the fields to modify. Only provided fields are updated.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<InvitationDto>
An InvitationDto representing the updated invitation.
Remarks
This method performs partial updates - only fields provided in the request are modified. Max uses cannot be reduced below the current number of times the invitation has been used. The invitation code itself cannot be changed after creation.
Exceptions
- Exception
Thrown when the invitation is not found or max uses is set to less than the current usage count.
UpdateUserAsync(Guid, UpdateUserRequest, CancellationToken)
Updates user account information including email, password, role, and status.
public Task<UserListDto> UpdateUserAsync(Guid userId, UpdateUserRequest request, CancellationToken cancellationToken = default)
Parameters
userIdGuidThe unique identifier of the user to update.
requestUpdateUserRequestThe update request containing the fields to modify. Only provided fields are updated.
cancellationTokenCancellationTokenCancellation token to cancel the operation.
Returns
- Task<UserListDto>
A UserListDto representing the updated user information.
Remarks
This method performs partial updates - only fields provided in the request are modified. Email uniqueness is enforced across all users. Passwords are hashed using BCrypt before storage. Role and status values must match enum values exactly (case-sensitive).
Exceptions
- Exception
Thrown when the user is not found, email is already in use by another user, or invalid role/status values are provided.