public async Task <IActionResult> Post([FromBody] UserDefinition userDefinition) { if (userDefinition is null) { throw new ArgumentNullException(nameof(userDefinition)); } var validation = new UserDefinitionValidator().Validate(userDefinition); if (!validation.IsValid) { return(ErrorResult .BadRequest(validation) .ActionResult()); } var teamCloudInstance = await teamCloudRepository .GetAsync() .ConfigureAwait(false); if (teamCloudInstance is null) { return(ErrorResult .NotFound($"No TeamCloud Instance was found.") .ActionResult()); } var newUser = await userService .GetUserAsync(userDefinition) .ConfigureAwait(false); if (newUser is null) { return(ErrorResult .NotFound($"A User with the Email '{userDefinition.Email}' could not be found.") .ActionResult()); } if (teamCloudInstance.Users.Contains(newUser)) { return(ErrorResult .Conflict($"A User with the Email '{userDefinition.Email}' already exists on this TeamCloud Instance. Please try your request again with a unique email or call PUT to update the existing User.") .ActionResult()); } var command = new OrchestratorTeamCloudUserCreateCommand(CurrentUser, newUser); var commandResult = await orchestrator .InvokeAsync(command) .ConfigureAwait(false); if (commandResult.Links.TryGetValue("status", out var statusUrl)) { return(StatusResult .Accepted(commandResult.CommandId.ToString(), statusUrl, commandResult.RuntimeStatus.ToString(), commandResult.CustomStatus) .ActionResult()); } throw new Exception("This shouldn't happen, but we need to decide to do when it does."); }
public async Task <IActionResult> Post([FromBody] UserDefinition userDefinition) { if (userDefinition is null) { throw new ArgumentNullException(nameof(userDefinition)); } var validation = new UserDefinitionTeamCloudAdminValidator().Validate(userDefinition); if (!validation.IsValid) { return(ErrorResult .BadRequest(validation) .ActionResult()); } var adminUsers = await usersRepository .ListAdminsAsync() .AnyAsync() .ConfigureAwait(false); if (adminUsers) { return(ErrorResult .BadRequest($"The TeamCloud instance already has one or more Admin users. To add additional users to the TeamCloud instance POST to api/users.", ResultErrorCode.ValidationError) .ActionResult()); } var userId = await userService .GetUserIdAsync(userDefinition.Identifier) .ConfigureAwait(false); if (string.IsNullOrEmpty(userId)) { return(ErrorResult .NotFound($"The user '{userDefinition.Identifier}' could not be found.") .ActionResult()); } var user = new User { Id = userId, Role = Enum.Parse <TeamCloudUserRole>(userDefinition.Role, true), Properties = userDefinition.Properties, UserType = UserType.User }; // no users exist in the database yet and the cli calls this api implicitly immediatly // after the teamcloud instance is created to add the instance creator as an admin user // thus, we can assume the calling user and the user from the payload are the same var command = new OrchestratorTeamCloudUserCreateCommand(user, user); return(await orchestrator .InvokeAndReturnAccepted(command) .ConfigureAwait(false)); }
public async Task <IActionResult> Post([FromBody] UserDefinition userDefinition) { if (userDefinition is null) { throw new ArgumentNullException(nameof(userDefinition)); } var validation = new UserDefinitionTeamCloudValidator().Validate(userDefinition); if (!validation.IsValid) { return(ErrorResult .BadRequest(validation) .ActionResult()); } var userId = await userService .GetUserIdAsync(userDefinition.Identifier) .ConfigureAwait(false); if (string.IsNullOrEmpty(userId)) { return(ErrorResult .NotFound($"The user '{userDefinition.Identifier}' could not be found.") .ActionResult()); } var user = await usersRepository .GetAsync(userId) .ConfigureAwait(false); if (user != null) { return(ErrorResult .Conflict($"The user '{userDefinition.Identifier}' already exists on this TeamCloud Instance. Please try your request again with a unique user or call PUT to update the existing User.") .ActionResult()); } user = new Model.Internal.Data.User { Id = userId, Role = Enum.Parse <TeamCloudUserRole>(userDefinition.Role, true), Properties = userDefinition.Properties, UserType = UserType.User }; var currentUserForCommand = await userService .CurrentUserAsync() .ConfigureAwait(false); var command = new OrchestratorTeamCloudUserCreateCommand(currentUserForCommand, user); return(await orchestrator .InvokeAndReturnAccepted(command) .ConfigureAwait(false)); }
public async Task InitializeAsync() { var log = loggerFactory.CreateLogger(this.GetType()); if (!hostingEnvironment.IsDevelopment()) { log.LogInformation($"Hosting environment is '{hostingEnvironment.EnvironmentName}' - skip admin initialization"); return; } try { var exists = await usersRepository .ListAdminsAsync() .AnyAsync() .ConfigureAwait(false); if (exists) { log.LogInformation($"Environment is initialized with at least 1 admin user."); return; } var user = new UserDocument { Id = await ResolveAzureCliUserId().ConfigureAwait(false), Role = TeamCloudUserRole.Admin, UserType = UserType.User }; var command = new OrchestratorTeamCloudUserCreateCommand(user, user); var commandResult = await orchestrator .ExecuteAsync(command) .ConfigureAwait(false); if (commandResult.RuntimeStatus == CommandRuntimeStatus.Completed) { log.LogInformation($"Initialized environment with user '{user.Id}' as admin"); } else { log.LogWarning($"Failed to initialize environment with user '{user.Id}': {commandResult.Errors.FirstOrDefault()?.Message}"); } } catch (Exception exc) { log.LogError(exc, $"Failed to process initializer {this.GetType().Name}: {exc.Message}"); } }
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (next is null) { throw new ArgumentNullException(nameof(next)); } // teamcloud needs a at least one admin user to work properly. // to avoid calls that will fail because of a missing user // we will check its existance in this middleware and block // calls until at least one admin user is in place. // as we ensure there is at least one admin user in the delete // and update apis we can keep the HasAdmin state once it is // evaluated to true to avoid unnecessary request to the // teamcloud repository in the future. HasAdmin = HasAdmin || await AdminExistsAsync().ConfigureAwait(false); if (HasAdmin) { await next(context).ConfigureAwait(false); } else { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; var error = ErrorResult.BadRequest("Must POST an Admin user to api/admin/users before calling any other APIs.", ResultErrorCode.ValidationError); var errorJson = JsonConvert.SerializeObject(error); await context.Response .WriteAsync(errorJson) .ConfigureAwait(false); } async Task <bool> AdminExistsAsync() { var exists = await usersRepository .ListAdminsAsync() .AnyAsync() .ConfigureAwait(false); if (!exists && hostingEnvironment.IsDevelopment()) { var objectId = context.User.GetObjectId(); if (!string.IsNullOrEmpty(objectId)) { var user = new UserDocument { Id = objectId, Role = TeamCloudUserRole.Admin, UserType = UserType.User }; var command = new OrchestratorTeamCloudUserCreateCommand(context.GetApplicationBaseUrl(), user, user); _ = await orchestrator .InvokeAsync(command) .ConfigureAwait(false); for (int i = 0; i < 60; i++) { await Task .Delay(1000) .ConfigureAwait(false); exists = await usersRepository .ListAdminsAsync() .AnyAsync() .ConfigureAwait(false); if (exists) { break; } } } } return(exists); } }
public async Task InitializeAsync() { var log = loggerFactory.CreateLogger(this.GetType()); if (!hostingEnvironment.IsDevelopment()) { log.LogInformation($"Hosting environment is '{hostingEnvironment.EnvironmentName}' - skip admin initialization"); return; } try { var exists = await userRepository .ListAdminsAsync() .AnyAsync() .ConfigureAwait(false); if (exists) { log.LogInformation($"Environment is initialized with at least 1 admin user."); return; } var user = new UserDocument { Id = await ResolveAzureCliUserId().ConfigureAwait(false), Role = TeamCloudUserRole.Admin, UserType = UserType.User }; var command = new OrchestratorTeamCloudUserCreateCommand(user, user); var commandResult = (ICommandResult)command.CreateResult(); var commandSendDuration = TimeSpan.FromMinutes(5); var commandSendTimeout = DateTime.UtcNow.Add(commandSendDuration); while (DateTime.UtcNow < commandSendTimeout) { try { commandResult = await orchestrator .InvokeAsync(command) .ConfigureAwait(false); break; } catch (FlurlHttpException exc) when(exc.Call.HttpStatus == System.Net.HttpStatusCode.BadGateway) { log.LogWarning(exc, $"Failed to initialize environment with user '{user.Id}' - will retry in a second"); await Task .Delay(1000) .ConfigureAwait(false); } } var commandResultDuration = TimeSpan.FromMinutes(5); var commandResultTimeout = DateTime.UtcNow.Add(commandResultDuration); while (DateTime.UtcNow < commandResultTimeout && commandResult.RuntimeStatus.IsActive()) { await Task .Delay(1000) .ConfigureAwait(false); commandResult = await orchestrator .QueryAsync(command) .ConfigureAwait(false); } if (commandResult.RuntimeStatus == CommandRuntimeStatus.Completed) { log.LogInformation($"Initialized environment with user '{user.Id}' as admin"); } else { log.LogWarning($"Failed to initialize environment with user '{user.Id}': {commandResult.Errors.FirstOrDefault()?.Message ?? commandResult.RuntimeStatus.ToString()}"); } } catch (Exception exc) { log.LogError(exc, $"Failed to process initializer {this.GetType().Name}: {exc.Message}"); } }