Skip to content

1724 replace common business service exceptions with serviceresult #1657

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

Open
wants to merge 19 commits into
base: v2-development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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 Common/OJS.Common/Constants/ServiceConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ public static class ExecutionStrategyNames
public static class ErrorCodes
{
public const string NotFound = "NotFound";
public const string AccessDenied = "AccessDenied";
public const string Forbidden = "Forbidden";
public const string Unauthorized = "Unauthorized";
public const string BusinessRuleViolation = "BusinessRuleViolation";
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace OJS.Servers.Infrastructure.Extensions;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using static OJS.Common.Constants.ServiceConstants;
using static OJS.Common.Constants.ServiceConstants.ErrorCodes;

public static class ControllerResultExtensions
{
Expand All @@ -23,11 +23,19 @@ public static IActionResult ToActionResult<T>(this ServiceResult<T> result, ILog
{
if (result.IsSuccess)
{
return new OkObjectResult(result.Data);
return result.Data is VoidResult
? new OkResult()
: new OkObjectResult(result.Data);
}

var activity = Activity.Current;
activity?.SetStatus(ActivityStatusCode.Error, result.ErrorMessage);
if (result.ErrorCode is not NotFound and not Forbidden and not Unauthorized)
{
// Mark activity as failed for all errors except NotFound and AccessDenied, as these are expected.
activity?.SetStatus(ActivityStatusCode.Error, result.ErrorMessage);
}

activity?.SetTag("service_result.error_message", result.ErrorMessage);
activity?.SetTag("service_result.instance_id", result.InstanceId);
activity?.SetTag("service_result.error_code", result.ErrorCode);
activity?.SetTag("service_result.error_context", result.ErrorContext);
Expand All @@ -43,13 +51,16 @@ public static IActionResult ToActionResult<T>(this ServiceResult<T> result, ILog
{
return result.ErrorCode switch
{
ErrorCodes.AccessDenied => CreateResponse("Access denied", StatusCodes.Status403Forbidden, () =>
Unauthorized => CreateResponse("Unauthorized", StatusCodes.Status401Unauthorized, () =>
logger.LogServiceResultAccessDenied(result.InstanceId, result.ErrorMessage)),

ErrorCodes.NotFound => CreateResponse("Not found", StatusCodes.Status404NotFound, () =>
Forbidden => CreateResponse("Action forbidden", StatusCodes.Status403Forbidden, () =>
logger.LogServiceResultAccessDenied(result.InstanceId, result.ErrorMessage)),

NotFound => CreateResponse($"{result.ResourceType ?? "Resource"} not found", StatusCodes.Status404NotFound, () =>
logger.LogServiceResultNotFound(result.InstanceId, result.ErrorMessage)),

ErrorCodes.BusinessRuleViolation => CreateResponse("Business rule violation", StatusCodes.Status422UnprocessableEntity, () =>
BusinessRuleViolation => CreateResponse("Business rule violation", StatusCodes.Status422UnprocessableEntity, () =>
logger.LogServiceResultBusinessRuleViolation(result.InstanceId, result.ErrorMessage)),

_ => CreateResponse("Bad request", StatusCodes.Status400BadRequest, () =>
Expand Down Expand Up @@ -80,8 +91,10 @@ IActionResult CreateResponse(string title, int statusCode, Action logAction)

return statusCode switch
{
StatusCodes.Status404NotFound => new NotFoundObjectResult(details),
StatusCodes.Status400BadRequest => new BadRequestObjectResult(details),
StatusCodes.Status401Unauthorized => new UnauthorizedObjectResult(details),
StatusCodes.Status404NotFound => new NotFoundObjectResult(details),
StatusCodes.Status422UnprocessableEntity => new UnprocessableEntityObjectResult(details),
_ => new ObjectResult(details) { StatusCode = statusCode },
};
}
Expand Down
7 changes: 0 additions & 7 deletions Servers/UI/OJS.Servers.Ui/ClientApp/src/common/url-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@ interface IContestCategoriesUrlParams {
id: number;
}

interface ISubmitContestPasswordParams {
contestId: string;
isOfficial: boolean;
password: string;
}

interface IGetSubmissionsUrlParams {
itemsPerPage: number;
page: number;
Expand Down Expand Up @@ -136,7 +130,6 @@ export type {
IGetByTestId,
IGetByRoleId,
IGetByUserId,
ISubmitContestPasswordParams,
ISubmitContestSolutionParams,
IGetSubmissionsByUserParams,
IRegisterUserForContestParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@ const ContestPasswordForm = (props: IContestPasswordFormProps) => {
const onPasswordSubmit = async () => {
setIsLoading(true);
setErrorMessage('');
const response = await registerUserForContest({ id: Number(id), isOfficial, password, hasConfirmedParticipation });
await registerUserForContest({ id: Number(id), isOfficial, password, hasConfirmedParticipation })
.unwrap()
.then(() => onSuccess())
.catch((err) => setErrorMessage((err as any)?.data?.detail ?? 'Unexpected error.'));

setPassword('');
if ((response as any).error) {
const { data } = (response as any).error;
setErrorMessage(data);
} else {
onSuccess();
}
setIsLoading(false);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { IContestResultsType } from '../../hooks/contests/types';
import {
IContestDetailsUrlParams,
IGetContestResultsParams,
ISubmitContestPasswordParams,
ISubmitContestSolutionParams,
IRegisterUserForContestParams,
} from '../../common/url-types';
Expand Down Expand Up @@ -136,14 +135,6 @@ export const contestsService = createApi({
};
},
}),
submitContestPassword: builder.mutation<void, ISubmitContestPasswordParams>({
query: ({ contestId, isOfficial, password }) => ({
url: `/contests/SubmitContestPassword/${contestId}`,
method: 'POST',
params: { isOfficial },
body: { password },
}),
}),
registerUserForContest: builder.mutation<
{ isRegisteredSuccessfully: boolean },
IRegisterUserForContestParams>({
Expand Down
4 changes: 4 additions & 0 deletions Servers/UI/OJS.Servers.Ui/ClientApp/src/utils/http-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ interface IErrorDataType {
status: number;
detail: string;
extensions: IDictionary<object>;
errorCode: string;
instance: string;
traceId: string | null;
errorContext: object | null;
}

const defaultErrorMessage = 'Something went wrong, please try again!';
Expand Down
Loading