Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attribute and response simplification #130

Merged
merged 4 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion API/Controller/Account/Authenticated/ChangeEmail.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using OpenShock.API.Models.Requests;
using OpenShock.Common.Errors;
using OpenShock.Common.Models;
using OpenShock.Common.Problems;
using OpenShock.Common.Utils;

Expand All @@ -15,7 +16,7 @@ public sealed partial class AuthenticatedAccountController
/// <returns></returns>
/// <exception cref="Exception"></exception>
[HttpPost("email")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
public Task<IActionResult> ChangeEmail(ChangeEmailRequest data)
{
throw new NotImplementedException();
Expand Down
4 changes: 2 additions & 2 deletions API/Controller/Account/Authenticated/ChangePassword.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public sealed partial class AuthenticatedAccountController
/// <returns></returns>
/// <exception cref="Exception"></exception>
[HttpPost("password")]
[ProducesSlimSuccess]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> ChangePassword(ChangePasswordRequest data)
{
if (!PasswordHashingUtils.VerifyPassword(data.OldPassword, CurrentUser.DbUser.PasswordHash).Verified)
Expand All @@ -25,7 +25,7 @@ public async Task<IActionResult> ChangePassword(ChangePasswordRequest data)

var result = await _accountService.ChangePassword(CurrentUser.DbUser.Id, data.NewPassword);

return result.Match(success => RespondSlimSuccess(),
return result.Match(success => Ok(),
notFound => throw new Exception("Unexpected result, apparently our current user does not exist..."));
}
}
6 changes: 3 additions & 3 deletions API/Controller/Account/Authenticated/ChangeUsername.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public sealed partial class AuthenticatedAccountController
/// <returns></returns>
/// <exception cref="Exception"></exception>
[HttpPost("username")]
[ProducesSlimSuccess]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.Conflict, "UsernameTaken")]
[ProducesProblem(HttpStatusCode.BadRequest, "UsernameInvalid")]
[ProducesProblem(HttpStatusCode.Forbidden, "UsernameRecentlyChanged")]
Expand All @@ -25,8 +25,8 @@ public async Task<IActionResult> ChangeUsername(ChangeUsernameRequest data)
var result = await _accountService.ChangeUsername(CurrentUser.DbUser.Id, data.Username,
CurrentUser.DbUser.Rank.IsAllowed(RankType.Staff));

return result.Match(
success => RespondSlimSuccess(),
return result.Match<IActionResult>(
success => Ok(),
error => Problem(error.Value.Match(
taken => AccountError.UsernameTaken,
AccountError.UsernameInvalid,
Expand Down
8 changes: 4 additions & 4 deletions API/Controller/Account/CheckUsername.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public sealed partial class AccountController
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("username/check")]
[ProducesSlimSuccess<UsernameCheckResponse>]
[ProducesResponseType<UsernameCheckResponse>(StatusCodes.Status200OK)]
public async Task<IActionResult> CheckUsername(ChangeUsernameRequest data, CancellationToken cancellationToken)
{
var availability = await _accountService.CheckUsernameAvailability(data.Username, cancellationToken);
return availability.Match(success => RespondSlimSuccess(new UsernameCheckResponse(UsernameAvailability.Available)),
taken => RespondSlimSuccess(new UsernameCheckResponse(UsernameAvailability.Taken)),
invalid => RespondSlimSuccess(new UsernameCheckResponse(UsernameAvailability.Invalid, invalid)));
return availability.Match(success => Ok(new UsernameCheckResponse(UsernameAvailability.Available)),
taken => Ok(new UsernameCheckResponse(UsernameAvailability.Taken)),
invalid => Ok(new UsernameCheckResponse(UsernameAvailability.Invalid, invalid)));
}
}

Expand Down
5 changes: 3 additions & 2 deletions API/Controller/Account/Login.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;
using OpenShock.Common.Utils;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Account;

Expand All @@ -19,7 +20,7 @@ public sealed partial class AccountController
/// <response code="200">User successfully logged in</response>
/// <response code="401">Invalid username or password</response>
[HttpPost("login")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.Unauthorized, "InvalidCredentials")]
[ProducesProblem(HttpStatusCode.Forbidden, "InvalidDomain")]
[MapToApiVersion("1")]
Expand All @@ -41,6 +42,6 @@ public async Task<IActionResult> Login(

HttpContext.SetSessionKeyCookie(loginAction.AsT0.Value, "." + cookieDomainToUse);

return RespondSuccessSimple("Successfully logged in");
return RespondSuccessLegacySimple("Successfully logged in");
}
}
5 changes: 3 additions & 2 deletions API/Controller/Account/LoginV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Services.Turnstile;
using OpenShock.Common.Utils;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Account;

Expand All @@ -20,7 +21,7 @@ public sealed partial class AccountController
/// <response code="200">User successfully logged in</response>
/// <response code="401">Invalid username or password</response>
[HttpPost("login")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.Unauthorized, "InvalidCredentials")]
[ProducesProblem(HttpStatusCode.Forbidden, "InvalidDomain")]
[MapToApiVersion("2")]
Expand Down Expand Up @@ -48,6 +49,6 @@ public async Task<IActionResult> LoginV2(

HttpContext.SetSessionKeyCookie(loginAction.AsT0.Value, "." + cookieDomainToUse);

return RespondSuccessSimple("Successfully logged in");
return RespondSuccessLegacySimple("Successfully logged in");
}
}
4 changes: 2 additions & 2 deletions API/Controller/Account/Logout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace OpenShock.API.Controller.Account;
public sealed partial class AccountController
{
[HttpPost("logout")]
[ProducesSlimSuccess]
[ProducesResponseType(StatusCodes.Status200OK)]
[MapToApiVersion("1")]
public async Task<IActionResult> Logout(
[FromServices] ISessionService sessionService,
Expand All @@ -36,6 +36,6 @@ public async Task<IActionResult> Logout(
}

// its always a success, logout endpoints should be idempotent
return RespondSlimSuccess();
return Ok();
}
}
5 changes: 3 additions & 2 deletions API/Controller/Account/PasswordResetCheckValid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using OpenShock.API.Services.Account;
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Account;

Expand All @@ -18,14 +19,14 @@ public sealed partial class AccountController
/// <response code="200">Valid password reset process</response>
/// <response code="404">Password reset process not found</response>
[HttpHead("recover/{passwordResetId}/{secret}")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.NotFound, "PasswordResetNotFound")]
[MapToApiVersion("1")]
public async Task<IActionResult> PasswordResetCheckValid([FromRoute] Guid passwordResetId, [FromRoute] string secret, CancellationToken cancellationToken)
{
var passwordResetExists = await _accountService.PasswordResetExists(passwordResetId, secret, cancellationToken);
return passwordResetExists.Match(
success => RespondSuccessSimple("Valid password reset process"),
success => RespondSuccessLegacySimple("Valid password reset process"),
notFound => Problem(PasswordResetError.PasswordResetNotFound),
invalid => Problem(PasswordResetError.PasswordResetNotFound)
);
Expand Down
5 changes: 3 additions & 2 deletions API/Controller/Account/PasswordResetComplete.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using OpenShock.API.Services.Account;
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Account;

Expand All @@ -18,7 +19,7 @@ public sealed partial class AccountController
/// <response code="200">Password successfully changed</response>
/// <response code="404">Password reset process not found</response>
[HttpPost("recover/{passwordResetId}/{secret}")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.NotFound, "PasswordResetNotFound")]
[MapToApiVersion("1")]
public async Task<IActionResult> PasswordResetComplete([FromRoute] Guid passwordResetId,
Expand All @@ -27,7 +28,7 @@ public async Task<IActionResult> PasswordResetComplete([FromRoute] Guid password
var passwordResetComplete = await _accountService.PasswordResetComplete(passwordResetId, secret, body.Password);

return passwordResetComplete.Match(
success => RespondSuccessSimple("Password successfully changed"),
success => RespondSuccessLegacySimple("Password successfully changed"),
notFound => Problem(PasswordResetError.PasswordResetNotFound),
invalid => Problem(PasswordResetError.PasswordResetNotFound));
}
Expand Down
2 changes: 1 addition & 1 deletion API/Controller/Account/PasswordResetInitiate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public sealed partial class AccountController
/// </summary>
/// <response code="200">Password reset email sent if the email is associated to an registered account</response>
[HttpPost("reset")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
[MapToApiVersion("1")]
public async Task<BaseResponse<object>> PasswordResetInitiate([FromBody] ResetRequest body)
{
Expand Down
5 changes: 3 additions & 2 deletions API/Controller/Account/Signup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using OpenShock.API.Services.Account;
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Account;

Expand All @@ -17,7 +18,7 @@ public sealed partial class AccountController
/// <response code="200">User successfully signed up</response>
/// <response code="409">Username or email already exists</response>
[HttpPost("signup")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.Conflict, "EmailOrUsernameAlreadyExists")]
[MapToApiVersion("1")]
public async Task<IActionResult> SignUp([FromBody] SignUp body)
Expand All @@ -26,6 +27,6 @@ public async Task<IActionResult> SignUp([FromBody] SignUp body)
if (creationAction.IsT1) return Problem(SignupError.EmailAlreadyExists);


return RespondSuccessSimple("Successfully signed up");
return RespondSuccessLegacySimple("Successfully signed up");
}
}
5 changes: 3 additions & 2 deletions API/Controller/Account/SignupV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Services.Turnstile;
using OpenShock.Common.Utils;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Account;

Expand All @@ -22,7 +23,7 @@ public sealed partial class AccountController
/// <response code="200">User successfully signed up</response>
/// <response code="400">Username or email already exists</response>
[HttpPost("signup")]
[ProducesSuccess]
[ProducesResponseType<BaseResponse<object>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.Conflict, "EmailOrUsernameAlreadyExists")]
[ProducesProblem(HttpStatusCode.Forbidden, "InvalidTurnstileResponse")]
[MapToApiVersion("2")]
Expand All @@ -42,6 +43,6 @@ public async Task<IActionResult> SignUpV2(
if (creationAction.IsT1)
return Problem(SignupError.EmailAlreadyExists);

return RespondSuccessSimple("Successfully signed up");
return RespondSuccessLegacySimple("Successfully signed up");
}
}
4 changes: 2 additions & 2 deletions API/Controller/Admin/DeleteUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed partial class AdminController
/// <response code="200">OK</response>
/// <response code="401">Unauthorized</response>
[HttpDelete("users/{userId}")]
[ProducesSlimSuccess]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> DeleteUser([FromRoute] Guid userId)
{
var user = await _db.Users.Where(x => x.Id == userId).FirstOrDefaultAsync();
Expand All @@ -35,6 +35,6 @@ public async Task<IActionResult> DeleteUser([FromRoute] Guid userId)
_db.Users.Remove(user);
await _db.SaveChangesAsync();

return RespondSlimSuccess();
return Ok();
}
}
10 changes: 4 additions & 6 deletions API/Controller/Admin/GetOnlineDevices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public sealed partial class AdminController
/// <response code="200">All online devices</response>
/// <response code="401">Unauthorized</response>
[HttpGet("monitoring/onlineDevices")]
[ProducesSuccess<IEnumerable<AdminOnlineDeviceResponse>>]
public async Task<BaseResponse<IEnumerable<AdminOnlineDeviceResponse>>> GetOnlineDevices()
[ProducesResponseType<BaseResponse<IEnumerable<AdminOnlineDeviceResponse>>>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetOnlineDevices()
{
var devicesOnline = _redis.RedisCollection<DeviceOnline>(false);

Expand All @@ -39,9 +39,7 @@ public async Task<BaseResponse<IEnumerable<AdminOnlineDeviceResponse>>> GetOnlin
}
}).ToListAsync();

return new BaseResponse<IEnumerable<AdminOnlineDeviceResponse>>
{
Data = allOnlineDevices.Select(x =>
return RespondSuccessLegacy(allOnlineDevices.Select(x =>
{
var dbItem = dbLookup.First(y => y.Id == x.Id);
return new AdminOnlineDeviceResponse
Expand All @@ -57,7 +55,7 @@ public async Task<BaseResponse<IEnumerable<AdminOnlineDeviceResponse>>> GetOnlin
Uptime = x.Uptime
};
})
};
);
}

public sealed class AdminOnlineDeviceResponse
Expand Down
2 changes: 1 addition & 1 deletion API/Controller/Admin/GetUsers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed partial class AdminController
/// <response code="200">Paginated users</response>
/// <response code="401">Unauthorized</response>
[HttpGet("users")]
[ProducesSlimSuccess<Paginated<AdminUsersView>>]
[ProducesResponseType<Paginated<AdminUsersView>>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetUsers(
[FromQuery(Name = "$filter")] string filterQuery = "",
[FromQuery(Name = "$orderby")] string orderbyQuery = "",
Expand Down
5 changes: 3 additions & 2 deletions API/Controller/Device/AssignLCG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using OpenShock.Common.Problems;
using OpenShock.Common.Services.LCGNodeProvisioner;
using OpenShock.Common.Utils;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Device;

Expand All @@ -17,7 +18,7 @@ public sealed partial class DeviceController
/// <response code="200">Successfully assigned LCG node</response>
/// <response code="503">Unable to find suitable LCG node</response>
[HttpGet("assignLCG")]
[ProducesSuccess<LcgNodeResponse>]
[ProducesResponseType<BaseResponse<LcgNodeResponse>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.ServiceUnavailable, "NoLcgNodesAvailable")]
public async Task<IActionResult> GetLiveControlGateway([FromServices] ILCGNodeProvisioner geoLocation,
[FromServices] IWebHostEnvironment env)
Expand All @@ -42,7 +43,7 @@ public async Task<IActionResult> GetLiveControlGateway([FromServices] ILCGNodePr
var closestNode = await geoLocation.GetOptimalNode(countryCode, env.EnvironmentName);
if (closestNode == null) return Problem(AssignLcgError.NoLcgNodesAvailable);

return RespondSuccess(new LcgNodeResponse
return RespondSuccessLegacy(new LcgNodeResponse
{
Fqdn = closestNode.Fqdn,
Country = closestNode.Country
Expand Down
10 changes: 4 additions & 6 deletions API/Controller/Device/GetSelf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public sealed partial class DeviceController
/// </summary>
/// <response code="200">The device information was successfully retrieved.</response>
[HttpGet("self")]
[ProducesSuccess<DeviceSelfResponse>]
public async Task<BaseResponse<DeviceSelfResponse>> GetSelf()
[ProducesResponseType<BaseResponse<DeviceSelfResponse>>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetSelf()
{
var shockers = await _db.Shockers.Where(x => x.Device == CurrentDevice.Id).Select(x => new MinimalShocker
{
Expand All @@ -23,14 +23,12 @@ public async Task<BaseResponse<DeviceSelfResponse>> GetSelf()
Model = x.Model
}).ToArrayAsync();

return new BaseResponse<DeviceSelfResponse>
{
Data = new DeviceSelfResponse
return RespondSuccessLegacy(new DeviceSelfResponse
{
Id = CurrentDevice.Id,
Name = CurrentDevice.Name,
Shockers = shockers
}
};
);
}
}
5 changes: 3 additions & 2 deletions API/Controller/Device/Pair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Net;
using OpenShock.Common.Errors;
using OpenShock.Common.Problems;
using OpenShock.Common.Models;

namespace OpenShock.API.Controller.Device;

Expand All @@ -20,7 +21,7 @@ public sealed partial class DeviceController
[AllowAnonymous]
[HttpGet("pair/{pairCode}", Name = "Pair")]
[HttpGet("~/{version:apiVersion}/pair/{pairCode}", Name = "Pair_DEPRECATED")] // Backwards compatibility
[ProducesSuccess<string>]
[ProducesResponseType<BaseResponse<string>>(StatusCodes.Status200OK)]
[ProducesProblem(HttpStatusCode.NotFound, "PairCodeNotFound")]
public async Task<IActionResult> Pair([FromRoute] string pairCode)
{
Expand All @@ -33,6 +34,6 @@ public async Task<IActionResult> Pair([FromRoute] string pairCode)
var device = await _db.Devices.FirstOrDefaultAsync(x => x.Id == pair.Id);
if (device == null) throw new Exception("Device not found for pair code");

return RespondSuccess(device.Token);
return RespondSuccessLegacy(device.Token);
}
}
Loading
Loading