├── README.md
├── Tarteeb.Api
├── Properties
│ ├── serviceDependencies.json
│ ├── serviceDependencies.local.json
│ ├── launchSettings.json
│ └── ServiceDependencies
│ │ └── local
│ │ └── appInsights1.arm.json
├── Brokers
│ ├── Storages
│ │ ├── IStorageBroker.cs
│ │ ├── StorageBroker.Users.Configurations.cs
│ │ ├── IStorageBroker.Teams.cs
│ │ ├── IStorageBroker.Users.cs
│ │ ├── IStorageBroker.Tickets.cs
│ │ ├── StorageBroker.Teams.cs
│ │ ├── StorageBroker.Tickets.cs
│ │ ├── StorageBroker.Users.cs
│ │ └── StorageBroker.cs
│ ├── DateTimes
│ │ ├── IDateTimeBroker.cs
│ │ └── DateTimeBroker.cs
│ ├── Tokens
│ │ ├── ITokenBroker.cs
│ │ └── TokenBroker.cs
│ └── Loggings
│ │ ├── ILoggingBroker.cs
│ │ └── LoggingBroker.cs
├── Models
│ ├── Foundations
│ │ ├── Tickets
│ │ │ ├── Priority.cs
│ │ │ ├── TicketStatus.cs
│ │ │ ├── Exceptions
│ │ │ │ ├── NullTicketException.cs
│ │ │ │ ├── InvalidTicketException.cs
│ │ │ │ ├── NotFoundTicketException.cs
│ │ │ │ ├── LockedTicketException.cs
│ │ │ │ ├── AlreadyExistsTicketException.cs
│ │ │ │ ├── TicketDependencyException.cs
│ │ │ │ ├── TicketServiceException.cs
│ │ │ │ ├── TicketValidationException.cs
│ │ │ │ ├── InvalidTicketReferenceException.cs
│ │ │ │ ├── FailedTicketStorageException.cs
│ │ │ │ ├── FailedTicketServiceException.cs
│ │ │ │ └── TicketDependencyValidationException.cs
│ │ │ └── Ticket.cs
│ │ ├── Teams
│ │ │ ├── Exceptions
│ │ │ │ ├── NullTeamException.cs
│ │ │ │ ├── InvalidTeamException.cs
│ │ │ │ ├── NotFoundTeamException.cs
│ │ │ │ ├── LockedTeamException.cs
│ │ │ │ ├── AlreadyExistsTeamException.cs
│ │ │ │ ├── TeamDependencyException.cs
│ │ │ │ ├── TeamServiceException.cs
│ │ │ │ ├── TeamValidationException.cs
│ │ │ │ ├── FailedTeamStorageException.cs
│ │ │ │ ├── FailedTeamServiceException.cs
│ │ │ │ └── TeamDependencyValidationException.cs
│ │ │ └── Team.cs
│ │ ├── Tokens
│ │ │ └── TokenConfiguration.cs
│ │ └── Users
│ │ │ ├── Exceptions
│ │ │ ├── NullUserException.cs
│ │ │ ├── InvalidUserException.cs
│ │ │ ├── LockedUserException.cs
│ │ │ ├── UserDependencyException.cs
│ │ │ ├── AlreadyExistsUserException.cs
│ │ │ ├── UserServiceException.cs
│ │ │ ├── UserValidationException.cs
│ │ │ ├── InvalidUserReferenceException.cs
│ │ │ ├── FailedUserStorageException.cs
│ │ │ ├── FailedUserServiceException.cs
│ │ │ ├── UserDependencyValidationException.cs
│ │ │ └── NotFoundUserException.cs
│ │ │ └── User.cs
│ ├── Processings
│ │ └── Users
│ │ │ ├── InvalidUserProcessingException.cs
│ │ │ ├── UserProcessingValidationException.cs
│ │ │ └── UserProcessingDependencyException.cs
│ └── Orchestrations
│ │ └── UserTokens
│ │ ├── UserToken.cs
│ │ └── Exceptions
│ │ ├── InvalidUserCreadentialOrchestrationException.cs
│ │ ├── UserTokenOrchestrationServiceException.cs
│ │ ├── UserTokenOrchestrationDependencyException.cs
│ │ ├── FailedUserTokenOrchestrationException.cs
│ │ └── UserTokenOrchestrationValidationException.cs
├── Services
│ ├── Foundations
│ │ ├── Securities
│ │ │ ├── ISecurityService.cs
│ │ │ ├── SecurityService.cs
│ │ │ ├── SecurityService.Validations.cs
│ │ │ └── SecurityService.Exceptions.cs
│ │ ├── Teams
│ │ │ ├── ITeamService.cs
│ │ │ └── TeamService.cs
│ │ ├── Users
│ │ │ ├── IUserService.cs
│ │ │ └── UserService.cs
│ │ └── Tickets
│ │ │ ├── ITicketService.cs
│ │ │ └── TicketService.cs
│ ├── Processings
│ │ └── Users
│ │ │ ├── IUserProcessingService.cs
│ │ │ ├── UserProcessingService.cs
│ │ │ ├── UserProcessingService.Validations.cs
│ │ │ └── UserProcessingService.Exceptions.cs
│ └── Orchestrations
│ │ ├── IUserSecurityOrchestrationService.cs
│ │ ├── UserSecurityOrchestrationService.Validations.cs
│ │ ├── UserSecurityOrchestrationService.cs
│ │ └── UserSecurityOrchestrationService.Exceptions.cs
├── Controllers
│ ├── HomeController.cs
│ └── AccountsController.cs
├── appsettings.json
├── Migrations
│ ├── 20221110181513_ChangePriority.cs
│ ├── 20230102085421_AddPasswordOnUser.cs
│ ├── 20221110175226_RenameTicketToTickets.cs
│ ├── 20221113120827_AddTeam.cs
│ ├── 20230210045018_UniqueEmail.cs
│ ├── 20221107175023_AddTasks.cs
│ ├── 20221112084050_AddUsers.cs
│ ├── 20221107175023_AddTasks.Designer.cs
│ ├── 20221110181513_ChangePriority.Designer.cs
│ ├── 20221110171741_RenameTaskToTicket.Designer.cs
│ ├── 20221110175226_RenameTicketToTickets.Designer.cs
│ ├── 20221110171741_RenameTaskToTicket.cs
│ └── 20221113120827_AddTeam.Designer.cs
├── Program.cs
└── Tarteeb.Api.csproj
├── Tarteeb.Api.Infrastructure.Build
├── Tarteeb.Api.Infrastructure.Build.csproj
└── Program.cs
├── .github
└── workflows
│ ├── build.yml
│ └── master_tarteeb.yml
├── LICENSE
├── Tarteeb.Api.Tests.Unit
├── Services
│ ├── Foundations
│ │ ├── Securities
│ │ │ ├── SecurityServiceTests.Logic.Create.cs
│ │ │ ├── SecurityServiceTests.cs
│ │ │ └── SecurityServiceTests.Validations.Create.cs
│ │ ├── Users
│ │ │ ├── UserServiceTests.Logic.RetrieveAll.cs
│ │ │ ├── UserServiceTests.Logic.RetrieveById.cs
│ │ │ ├── UserServiceTests.Logic.Add.cs
│ │ │ ├── UserServiceTests.Logic.RemoveById.cs
│ │ │ ├── UserServiceTests.Logic.Modify.cs
│ │ │ ├── UserServiceTests.Exceptions.RetrieveAll.cs
│ │ │ ├── UserServiceTests.Validations.RetrieveById.cs
│ │ │ ├── UserServiceTests.Exceptions.RetrieveById.cs
│ │ │ └── UserServiceTests.Validations.RemoveById.cs
│ │ ├── Teams
│ │ │ ├── TeamServiceTests.Logic.RetrieveAll.cs
│ │ │ ├── TeamServiceTests.Logic.RetrieveById.cs
│ │ │ ├── TeamServiceTests.Logic.Add.cs
│ │ │ ├── TeamServiceTests.Logic.RemoveById.cs
│ │ │ ├── TeamServiceTests.Logic.Modify.cs
│ │ │ ├── TeamServiceTests.Exceptions.RetrieveAll.cs
│ │ │ ├── TeamServiceTests.Validations.RetrieveById.cs
│ │ │ ├── TeamServiceTests.Validations.RemoveById.cs
│ │ │ └── TeamServiceTests.Exceptions.RetrieveById.cs
│ │ └── Tickets
│ │ │ ├── TicketServiceTests.Logic.RetrieveAll.cs
│ │ │ ├── TicketServiceTests.Logic.RetrieveById.cs
│ │ │ ├── TicketServiceTests.Logic.Add.cs
│ │ │ ├── TicketServiceTests.Logic.RemoveById.cs
│ │ │ ├── TicketServiceTests.Logic.Modify.cs
│ │ │ ├── TicketServiceTests.Exceptions.RetrieveAll.cs
│ │ │ └── TicketServiceTests.Validations.RetrieveById.cs
│ ├── Processings
│ │ └── Users
│ │ │ ├── UserProcessingsServiceTests.Logic.cs
│ │ │ ├── UserProcessingsServiceTests.Exceptions.Retrieve.cs
│ │ │ ├── UserProcessingsServiceTests.cs
│ │ │ └── UserProcessingsServiceTests.Validation.Retrieve.cs
│ └── Orchestrations
│ │ ├── UserSecurityOrchestrationServiceTests.Logic.Create.cs
│ │ └── UserSecurityOrchestrationServiceTests.cs
└── Tarteeb.Api.Tests.Unit.csproj
└── Tarteeb.sln
/README.md:
--------------------------------------------------------------------------------
1 | # Tarteeb
2 | A Standard-compliant task management software
3 |
4 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Properties/serviceDependencies.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "secrets1": {
4 | "type": "secrets"
5 | },
6 | "appInsights1": {
7 | "type": "appInsights",
8 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING",
9 | "dynamicId": null
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/IStorageBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | namespace Tarteeb.Api.Brokers.Storages
7 | {
8 | public partial interface IStorageBroker
9 | { }
10 | }
11 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Priority.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | namespace Tarteeb.Api.Models.Foundations.Tickets
7 | {
8 | public enum Priority
9 | {
10 | LOW,
11 | MEDIUM,
12 | HIGH
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Processings/Users/InvalidUserProcessingException.cs:
--------------------------------------------------------------------------------
1 | using Xeptions;
2 |
3 | namespace Tarteeb.Api.Models.Processings.Users
4 | {
5 | public class InvalidUserProcessingException : Xeption
6 | {
7 | public InvalidUserProcessingException()
8 | : base(message: "Invalid email and password, Please correct the errors and try again.")
9 | { }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/DateTimes/IDateTimeBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 |
8 | namespace Tarteeb.Api.Brokers.DateTimes
9 | {
10 | public interface IDateTimeBroker
11 | {
12 | DateTimeOffset GetCurrentDateTime();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Infrastructure.Build/Tarteeb.Api.Infrastructure.Build.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Tokens/ITokenBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Models.Foundations.Users;
7 |
8 | namespace Tarteeb.Api.Brokers.Tokens
9 | {
10 | public interface ITokenBroker
11 | {
12 | string GenerateJWT(User user);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/TicketStatus.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | namespace Tarteeb.Api.Models.Foundations.Tickets
7 | {
8 | public enum TicketStatus
9 | {
10 | UNKNOWN,
11 | TODO,
12 | INPROGRESS,
13 | DONE
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Processings/Users/UserProcessingValidationException.cs:
--------------------------------------------------------------------------------
1 | using Xeptions;
2 |
3 | namespace Tarteeb.Api.Models.Processings.Users
4 | {
5 | public class UserProcessingValidationException : Xeption
6 | {
7 | public UserProcessingValidationException(Xeption innerException)
8 | : base(message: "PostImpression validation error occurred, please try again.", innerException)
9 | { }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Securities/ISecurityService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Models.Foundations.Users;
7 |
8 | namespace Tarteeb.Api.Services.Foundations.Securities;
9 |
10 | public interface ISecurityService
11 | {
12 | string CreateToken(User user);
13 | }
14 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Loggings/ILoggingBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 |
8 | namespace Tarteeb.Api.Brokers.Loggings
9 | {
10 | public interface ILoggingBroker
11 | {
12 | void LogError(Exception exception);
13 | void LogCritical(Exception exception);
14 | }
15 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Orchestrations/UserTokens/UserToken.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 |
8 | namespace Tarteeb.Api.Models.Orchestrations.UserTokens
9 | {
10 | public class UserToken
11 | {
12 | public Guid UserId { get; set; }
13 | public string Token { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/DateTimes/DateTimeBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 |
8 | namespace Tarteeb.Api.Brokers.DateTimes
9 | {
10 | public class DateTimeBroker : IDateTimeBroker
11 | {
12 | public DateTimeOffset GetCurrentDateTime() =>
13 | DateTimeOffset.UtcNow;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/NullTeamException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
9 | {
10 | public class NullTeamException : Xeption
11 | {
12 | public NullTeamException() : base(message: "Team is null.")
13 | { }
14 | }
15 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Processings/Users/IUserProcessingService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Models.Foundations.Users;
7 |
8 | namespace Tarteeb.Api.Services.Processings.Users
9 | {
10 | public interface IUserProcessingService
11 | {
12 | User RetrieveUserByCredentails(string email, string password);
13 | }
14 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tokens/TokenConfiguration.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | namespace Tarteeb.Api.Models.Foundations.Tokens
7 | {
8 | public class TokenConfiguration
9 | {
10 | public string Key { get; set; }
11 | public string Issuer { get; set; }
12 | public string Audience { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/NullTicketException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
9 | {
10 | public class NullTicketException : Xeption
11 | {
12 | public NullTicketException() : base(message: "Ticket is null.")
13 | { }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/NullUserException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
9 | {
10 | public class NullUserException : Xeption
11 | {
12 | public NullUserException()
13 | : base(message: "User is null.")
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Orchestrations/IUserSecurityOrchestrationService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Models.Orchestrations.UserTokens;
7 |
8 | namespace Tarteeb.Api.Services.Orchestrations
9 | {
10 | public interface IUserSecurityOrchestrationService
11 | {
12 | UserToken CreateUserToken(string email, string password);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/InvalidTeamException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
9 | {
10 | public class InvalidTeamException : Xeption
11 | {
12 | public InvalidTeamException()
13 | : base(message: "Team is invalid.")
14 | { }
15 | }
16 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/InvalidUserException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
9 | {
10 | public class InvalidUserException : Xeption
11 | {
12 | public InvalidUserException()
13 | : base(message: "User is invalid.")
14 | { }
15 | }
16 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Properties/serviceDependencies.local.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "secrets1": {
4 | "type": "secrets.user"
5 | },
6 | "appInsights1": {
7 | "secretStore": "LocalSecretsFile",
8 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/tarteeb",
9 | "type": "appInsights.azure",
10 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING",
11 | "dynamicId": null
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/InvalidTicketException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
9 | {
10 | public class InvalidTicketException : Xeption
11 | {
12 | public InvalidTicketException()
13 | : base(message: "Ticket is invalid.")
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Team.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Teams
9 | {
10 | public class Team
11 | {
12 | public Guid Id { get; set; }
13 | public string TeamName { get; set; }
14 | public DateTimeOffset CreatedDate { get; set; }
15 | public DateTimeOffset UpdatedDate { get; set; }
16 | }
17 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/NotFoundTeamException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
10 | {
11 | public class NotFoundTeamException : Xeption
12 | {
13 | public NotFoundTeamException(Guid teamId)
14 | : base(message: $"Couldn't find team with id: {teamId}.")
15 | { }
16 | }
17 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Microsoft.AspNetCore.Mvc;
7 | using RESTFulSense.Controllers;
8 |
9 | namespace Tarteeb.Api.Controllers
10 | {
11 | [ApiController]
12 | [Route("api/[controller]")]
13 | public class HomeController : RESTFulController
14 | {
15 | [HttpGet]
16 | public ActionResult GetHomeMessage() => Ok("Tarteeb is running...");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/LockedTeamException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
10 | {
11 | public class LockedTeamException : Xeption
12 | {
13 | public LockedTeamException(Exception innerException)
14 | : base(message: "Team is locked, please try again.", innerException)
15 | { }
16 | }
17 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/AlreadyExistsTeamException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
10 | {
11 | public class AlreadyExistsTeamException : Xeption
12 | {
13 | public AlreadyExistsTeamException(Exception innerException)
14 | : base(message: "Team already exists.", innerException)
15 | { }
16 | }
17 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/TeamDependencyException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
9 | {
10 | public class TeamDependencyException : Xeption
11 | {
12 | public TeamDependencyException(Xeption innerException)
13 | : base(message: "Team dependency error occurred, contact support.", innerException)
14 | { }
15 | }
16 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/NotFoundTicketException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
10 | {
11 | public class NotFoundTicketException : Xeption
12 | {
13 | public NotFoundTicketException(Guid ticketId)
14 | : base(message: $"Couldn't find ticket with id: {ticketId}.")
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/LockedUserException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
10 | {
11 | public class LockedUserException : Xeption
12 | {
13 | public LockedUserException(Exception innerException)
14 | : base(message: "User is locked, please try again.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/UserDependencyException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
9 | {
10 | public class UserDependencyException : Xeption
11 | {
12 | public UserDependencyException(Xeption innerException)
13 | : base(message: "User dependency error occurred, contact support.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/TeamServiceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
10 | {
11 | public class TeamServiceException : Xeption
12 | {
13 | public TeamServiceException(Exception innerException)
14 | : base(message: "Team service error occurred, contact support.", innerException)
15 | { }
16 | }
17 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/TeamValidationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
9 | {
10 | public class TeamValidationException : Xeption
11 | {
12 | public TeamValidationException(Xeption innerException)
13 | : base(message: "Team validation error occured, fix the errors and try again.", innerException)
14 | { }
15 | }
16 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/LockedTicketException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
10 | {
11 | public class LockedTicketException : Xeption
12 | {
13 | public LockedTicketException(Exception innerException)
14 | : base(message: "Ticket is locked, please try again.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/AlreadyExistsUserException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
10 | {
11 | public partial class AlreadyExistsUserException : Xeption
12 | {
13 | public AlreadyExistsUserException(Exception innerException)
14 | : base(message: "User already exists.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/UserServiceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
10 | {
11 | public class UserServiceException : Xeption
12 | {
13 | public UserServiceException(Exception innerException)
14 | : base(message: "User service error occured, contact support.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/UserValidationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
9 | {
10 | public class UserValidationException : Xeption
11 | {
12 | public UserValidationException(Xeption innerExeption)
13 | : base(message: "User validation error occured, fix the errors and try again.", innerExeption)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Processings/Users/UserProcessingDependencyException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Processings.Users
9 | {
10 | public class UserProcessingDependencyException : Xeption
11 | {
12 | public UserProcessingDependencyException(Xeption innerException)
13 | : base(message: "User dependency error occurred, contact support.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/AlreadyExistsTicketException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
10 | {
11 | public class AlreadyExistsTicketException : Xeption
12 | {
13 | public AlreadyExistsTicketException(Exception innerException)
14 | : base(message: "Ticket already exists.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/TicketDependencyException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
9 | {
10 | public class TicketDependencyException : Xeption
11 | {
12 | public TicketDependencyException(Xeption innerException)
13 | : base(message: "Ticket dependency error occurred, contact support.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/TicketServiceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
10 | {
11 | public class TicketServiceException : Xeption
12 | {
13 | public TicketServiceException(Exception innerException)
14 | : base(message: "Ticket service error occurred, contact support.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/TicketValidationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
9 | {
10 | public class TicketValidationException : Xeption
11 | {
12 | public TicketValidationException(Xeption innerException)
13 | : base(message: "Ticket validation error occured, fix the errors and try again.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/FailedTeamStorageException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
10 | {
11 | public class FailedTeamStorageException : Xeption
12 | {
13 | public FailedTeamStorageException(Exception innerException)
14 | : base(message: "Failed team storage error occurred, contact support.", innerException)
15 | { }
16 | }
17 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/InvalidUserReferenceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
10 | {
11 | public class InvalidUserReferenceException : Xeption
12 | {
13 | public InvalidUserReferenceException(Exception innerException)
14 | : base(message: "Invalid user reference error occured.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/StorageBroker.Users.Configurations.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
7 | using Tarteeb.Api.Models.Foundations.Users;
8 |
9 | namespace Tarteeb.Api.Brokers.Storages
10 | {
11 | public partial class StorageBroker
12 | {
13 | public void ConfigureUserEmail(EntityTypeBuilder builder)
14 | {
15 | builder.HasIndex(user => user.Email).IsUnique();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/FailedUserStorageException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
10 | {
11 | public class FailedUserStorageException : Xeption
12 | {
13 | public FailedUserStorageException(Exception innerException)
14 | : base(message: "Failed user storage error occurred, contact support.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/InvalidTicketReferenceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
10 | {
11 | public class InvalidTicketReferenceException : Xeption
12 | {
13 | public InvalidTicketReferenceException(Exception innerException)
14 | : base(message: "Invalid ticket reference error occurred.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/FailedUserServiceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
10 | {
11 | public class FailedUserServiceException : Xeption
12 | {
13 | public FailedUserServiceException(Exception innerException)
14 | : base(message: "Failed user service error occured, please contact support", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Orchestrations/UserTokens/Exceptions/InvalidUserCreadentialOrchestrationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions
9 | {
10 | public class InvalidUserCredentialOrchestrationException : Xeption
11 | {
12 | public InvalidUserCredentialOrchestrationException()
13 | : base(message: "Credential missing. Fix the error and try again.")
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/FailedTicketStorageException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
10 | {
11 | public class FailedTicketStorageException : Xeption
12 | {
13 | public FailedTicketStorageException(Exception innerException)
14 | : base(message: "Failed ticket storage error occurred, contact support.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "Jwt": {
10 | "Key": "dh%8sadjGfjh&657HVD%NfrUNHG5689",
11 | "Issuer": "https://localhost:7253",
12 | "Audience": "https://localhost:7253"
13 | },
14 | "AllowedHosts": "*",
15 | "ApplicationInsights": {
16 | "ConnectionString": "InstrumentationKey=8eb5f5d8-ad7c-4665-b7d6-df8736747959;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/"
17 | }
18 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/FailedTeamServiceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
10 | {
11 | public class FailedTeamServiceException : Xeption
12 | {
13 | public FailedTeamServiceException(Exception innerException)
14 | : base(message: "Failed team service error occurred, please contact support.",
15 | innerException)
16 | { }
17 | }
18 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/FailedTicketServiceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
10 | {
11 | public class FailedTicketServiceException : Xeption
12 | {
13 | public FailedTicketServiceException(Exception innerException)
14 | : base(message: "Failed ticket service error occurred, please contact support", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/UserDependencyValidationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
9 | {
10 | public class UserDependencyValidationException : Xeption
11 | {
12 | public UserDependencyValidationException(Xeption innerException)
13 | : base(message: "User dependency validation error occurred, fix the error and try again ", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Tarteeb Build Process
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | branches:
8 | - master
9 | jobs:
10 | build:
11 | runs-on: windows-2022
12 | steps:
13 | - name: Check out
14 | uses: actions/checkout@v2
15 | - name: Setup .Net
16 | uses: actions/setup-dotnet@v1
17 | with:
18 | dotnet-version: 7.0.100
19 | include-prerelease: true
20 | - name: Restore Packages
21 | run: dotnet restore
22 | - name: Build Projects
23 | run: dotnet build --no-restore
24 | - name: Run Tests
25 | run: dotnet test --no-build --verbosity normal
26 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221110181513_ChangePriority.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 |
8 | #nullable disable
9 |
10 | namespace Tarteeb.Api.Migrations
11 | {
12 | public partial class ChangePriority : Migration
13 | {
14 | protected override void Up(MigrationBuilder migrationBuilder)
15 | {
16 |
17 | }
18 |
19 | protected override void Down(MigrationBuilder migrationBuilder)
20 | {
21 |
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Exceptions/TicketDependencyValidationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Tickets.Exceptions
9 | {
10 | public class TicketDependencyValidationException : Xeption
11 | {
12 | public TicketDependencyValidationException(Xeption innerException)
13 | : base(message: "Ticket dependency validation error occurred, fix the errors and try again.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Orchestrations/UserTokens/Exceptions/UserTokenOrchestrationServiceException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions
9 | {
10 | public class UserTokenOrchestrationServiceException : Xeption
11 | {
12 | public UserTokenOrchestrationServiceException(Xeption innerException)
13 | : base(message: "User token service error occurred, contact support.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Teams/Exceptions/TeamDependencyValidationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Teams.Exceptions
9 | {
10 | public class TeamDependencyValidationException : Xeption
11 | {
12 | public TeamDependencyValidationException(Xeption innerException)
13 | : base(message: "Team dependency validation error occurred, fix the errors and try again.",
14 | innerException)
15 | { }
16 | }
17 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Orchestrations/UserTokens/Exceptions/UserTokenOrchestrationDependencyException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions
9 | {
10 | public class UserTokenOrchestrationDependencyException : Xeption
11 | {
12 | public UserTokenOrchestrationDependencyException(Xeption innerException)
13 | : base(message: "User token dependency error occurred, contact support.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Orchestrations/UserTokens/Exceptions/FailedUserTokenOrchestrationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions
10 | {
11 | public class FailedUserTokenOrchestrationException: Xeption
12 | {
13 | public FailedUserTokenOrchestrationException(Exception innerException)
14 | : base(message: "Failed user token service error occurred, contact support.", innerException)
15 | { }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Orchestrations/UserTokens/Exceptions/UserTokenOrchestrationValidationException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Xeptions;
7 |
8 | namespace Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions
9 | {
10 | public class UserTokenOrchestrationValidationException : Xeption
11 | {
12 | public UserTokenOrchestrationValidationException(Xeption innerException)
13 | : base(message: "User token validation error occurred, fix the errors and try again.", innerException)
14 | { }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/Exceptions/NotFoundUserException.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Xeptions;
8 |
9 | namespace Tarteeb.Api.Models.Foundations.Users.Exceptions
10 | {
11 | public class NotFoundUserException : Xeption
12 | {
13 | public NotFoundUserException(Guid userId)
14 | : base(message: $"Could not find user with id:{userId}.")
15 | { }
16 |
17 | public NotFoundUserException()
18 | : base(message: "Could not find user with given credentials")
19 | { }
20 | }
21 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/IStorageBroker.Teams.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Models.Foundations.Teams;
10 |
11 | namespace Tarteeb.Api.Brokers.Storages
12 | {
13 | public partial interface IStorageBroker
14 | {
15 | ValueTask InsertTeamAsync(Team team);
16 | IQueryable SelectAllTeams();
17 | ValueTask SelectTeamByIdAsync(Guid id);
18 | ValueTask UpdateTeamAsync(Team team);
19 | ValueTask DeleteTeamAsync(Team team);
20 | }
21 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/IStorageBroker.Users.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Models.Foundations.Users;
10 |
11 | namespace Tarteeb.Api.Brokers.Storages
12 | {
13 | public partial interface IStorageBroker
14 | {
15 | ValueTask InsertUserAsync(User user);
16 | IQueryable SelectAllUsers();
17 | ValueTask SelectUserByIdAsync(Guid id);
18 | ValueTask UpdateUserAsync(User user);
19 | ValueTask DeleteUserAsync(User user);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Program.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | namespace Tarteeb.Api
10 | {
11 | public class Program
12 | {
13 | public static void Main(string[] args) =>
14 | CreateHostBuilder(args).Build().Run();
15 |
16 | public static IHostBuilder CreateHostBuilder(string[] args)
17 | {
18 | return Host.CreateDefaultBuilder(args)
19 | .ConfigureWebHostDefaults(webBuilder =>
20 | webBuilder.UseStartup());
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Teams/ITeamService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Models.Foundations.Teams;
10 |
11 | namespace Tarteeb.Api.Services.Foundations.Teams
12 | {
13 | public interface ITeamService
14 | {
15 | ValueTask AddTeamAsync(Team team);
16 | IQueryable RetrieveAllTeams();
17 | ValueTask RetrieveTeamByIdAsync(Guid teamId);
18 | ValueTask ModifyTeamAsync(Team team);
19 | ValueTask RemoveTeamByIdAsync(Guid teamId);
20 | }
21 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Users/IUserService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Models.Foundations.Users;
10 |
11 | namespace Tarteeb.Api.Services.Foundations.Users
12 | {
13 | public interface IUserService
14 | {
15 | ValueTask AddUserAsync(User user);
16 | IQueryable RetrieveAllUsers();
17 | ValueTask RetrieveUserByIdAsync(Guid userId);
18 | ValueTask ModifyUserAsync(User user);
19 | ValueTask RemoveUserByIdAsync(Guid userId);
20 | }
21 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/IStorageBroker.Tickets.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Models.Foundations.Tickets;
10 |
11 | namespace Tarteeb.Api.Brokers.Storages
12 | {
13 | public partial interface IStorageBroker
14 | {
15 | ValueTask InsertTicketAsync(Ticket ticket);
16 | IQueryable SelectAllTickets();
17 | ValueTask SelectTicketByIdAsync(Guid id);
18 | ValueTask UpdateTicketAsync(Ticket ticket);
19 | ValueTask DeleteTicketAsync(Ticket ticket);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Tickets/ITicketService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Models.Foundations.Tickets;
10 |
11 | namespace Tarteeb.Api.Services.Foundations.Tickets
12 | {
13 | public interface ITicketService
14 | {
15 | ValueTask AddTicketAsync(Ticket ticket);
16 | IQueryable RetrieveAllTickets();
17 | ValueTask RetrieveTicketByIdAsync(Guid ticketId);
18 | ValueTask ModifyTicketAsync(Ticket ticket);
19 | ValueTask RemoveTicketByIdAsync(Guid ticketId);
20 | }
21 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Loggings/LoggingBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace Tarteeb.Api.Brokers.Loggings
10 | {
11 | public class LoggingBroker : ILoggingBroker
12 | {
13 | private ILogger logger;
14 |
15 | public LoggingBroker(ILogger logger) =>
16 | this.logger = logger;
17 |
18 | public void LogError(Exception exception) =>
19 | this.logger.LogError(exception.Message, exception);
20 |
21 | public void LogCritical(Exception exception) =>
22 | this.logger.LogCritical(exception, exception.Message);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Users/User.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Users
9 | {
10 | public class User
11 | {
12 | public Guid Id { get; set; }
13 | public string FirstName { get; set; }
14 | public string LastName { get; set; }
15 | public string PhoneNumber { get; set; }
16 | public string Email { get; set; }
17 | public DateTimeOffset BirthDate { get; set; }
18 | public DateTimeOffset CreatedDate { get; set; }
19 | public DateTimeOffset UpdatedDate { get; set; }
20 | public Guid? ManagerId { get; set; }
21 | public string Password { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20230102085421_AddPasswordOnUser.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | #nullable disable
4 |
5 | namespace Tarteeb.Api.Migrations
6 | {
7 | ///
8 | public partial class AddPasswordOnUser : Migration
9 | {
10 | ///
11 | protected override void Up(MigrationBuilder migrationBuilder)
12 | {
13 | migrationBuilder.AddColumn(
14 | name: "Password",
15 | table: "Users",
16 | type: "nvarchar(max)",
17 | nullable: true);
18 | }
19 |
20 | ///
21 | protected override void Down(MigrationBuilder migrationBuilder)
22 | {
23 | migrationBuilder.DropColumn(
24 | name: "Password",
25 | table: "Users");
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Models/Foundations/Tickets/Ticket.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 |
8 | namespace Tarteeb.Api.Models.Foundations.Tickets
9 | {
10 | public class Ticket
11 | {
12 | public Guid Id { get; set; }
13 | public string Title { get; set; }
14 | public string Description { get; set; }
15 | public Priority Priority { get; set; }
16 | public DateTimeOffset Deadline { get; set; }
17 | public Guid? AssigneeId { get; set; }
18 | public TicketStatus Status { get; set; }
19 | public DateTimeOffset CreatedDate { get; set; }
20 | public DateTimeOffset UpdatedDate { get; set; }
21 | public Guid CreatedUserId { get; set; }
22 | public Guid UpdatedUserId { get; set; }
23 | }
24 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:23173",
8 | "sslPort": 44333
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "swagger",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "Tarteeb.Api": {
21 | "commandName": "Project",
22 | "dotnetRunMessages": "true",
23 | "launchBrowser": true,
24 | "launchUrl": "swagger",
25 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Securities/SecurityService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Brokers.Loggings;
7 | using Tarteeb.Api.Brokers.Tokens;
8 | using Tarteeb.Api.Models.Foundations.Users;
9 |
10 | namespace Tarteeb.Api.Services.Foundations.Securities;
11 |
12 | public partial class SecurityService : ISecurityService
13 | {
14 | private readonly ITokenBroker tokenBroker;
15 | private readonly ILoggingBroker loggingBroker;
16 |
17 | public SecurityService(
18 | ITokenBroker tokenBroker,
19 | ILoggingBroker loggingBroker)
20 | {
21 | this.tokenBroker = tokenBroker;
22 | this.loggingBroker = loggingBroker;
23 | }
24 |
25 | public string CreateToken(User user) =>
26 | TryCatch(() =>
27 | {
28 | ValidateUser(user);
29 |
30 | return tokenBroker.GenerateJWT(user);
31 | });
32 |
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Elbek
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/StorageBroker.Teams.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Microsoft.EntityFrameworkCore;
10 | using Tarteeb.Api.Models.Foundations.Teams;
11 |
12 | namespace Tarteeb.Api.Brokers.Storages
13 | {
14 | public partial class StorageBroker
15 | {
16 | public DbSet Teams { get; set; }
17 |
18 | public async ValueTask InsertTeamAsync(Team team) =>
19 | await InsertAsync(team);
20 |
21 | public IQueryable SelectAllTeams() =>
22 | SelectAll();
23 |
24 | public async ValueTask SelectTeamByIdAsync(Guid id) =>
25 | await SelectAsync(id);
26 |
27 | public async ValueTask UpdateTeamAsync(Team team) =>
28 | await UpdateAsync(team);
29 |
30 | public async ValueTask DeleteTeamAsync(Team team) =>
31 | await DeleteAsync(team);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/StorageBroker.Tickets.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Microsoft.EntityFrameworkCore;
10 | using Tarteeb.Api.Models.Foundations.Tickets;
11 |
12 | namespace Tarteeb.Api.Brokers.Storages
13 | {
14 | public partial class StorageBroker
15 | {
16 | public DbSet Tickets { get; set; }
17 |
18 | public async ValueTask InsertTicketAsync(Ticket ticket) =>
19 | await InsertAsync(ticket);
20 |
21 | public IQueryable SelectAllTickets() =>
22 | SelectAll();
23 |
24 | public async ValueTask SelectTicketByIdAsync(Guid id) =>
25 | await SelectAsync(id);
26 |
27 | public async ValueTask UpdateTicketAsync(Ticket ticket) =>
28 | await UpdateAsync(ticket);
29 |
30 | public async ValueTask DeleteTicketAsync(Ticket ticket) =>
31 | await DeleteAsync(ticket);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/StorageBroker.Users.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Models.Foundations.Users;
10 | using Microsoft.EntityFrameworkCore;
11 |
12 | namespace Tarteeb.Api.Brokers.Storages
13 | {
14 | public partial class StorageBroker
15 | {
16 | public DbSet Users { get; set; }
17 |
18 | public async ValueTask InsertUserAsync(User user) =>
19 | await InsertAsync(user);
20 |
21 | public IQueryable SelectAllUsers() =>
22 | SelectAll();
23 |
24 | public async ValueTask SelectUserByIdAsync(Guid id) =>
25 | await SelectAsync(id);
26 |
27 | public async ValueTask UpdateUserAsync(User user) =>
28 | await UpdateAsync(user);
29 |
30 | public async ValueTask DeleteUserAsync(User user) =>
31 | await DeleteAsync(user);
32 |
33 | protected override void OnModelCreating(ModelBuilder modelBuilder)
34 | {
35 | ConfigureUserEmail(modelBuilder.Entity());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221110175226_RenameTicketToTickets.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | #nullable disable
4 |
5 | namespace Tarteeb.Api.Migrations
6 | {
7 | public partial class RenameTicketToTickets : Migration
8 | {
9 | protected override void Up(MigrationBuilder migrationBuilder)
10 | {
11 | migrationBuilder.DropPrimaryKey(
12 | name: "PK_Ticket",
13 | table: "Ticket");
14 |
15 | migrationBuilder.RenameTable(
16 | name: "Ticket",
17 | newName: "Tickets");
18 |
19 | migrationBuilder.AddPrimaryKey(
20 | name: "PK_Tickets",
21 | table: "Tickets",
22 | column: "Id");
23 | }
24 |
25 | protected override void Down(MigrationBuilder migrationBuilder)
26 | {
27 | migrationBuilder.DropPrimaryKey(
28 | name: "PK_Tickets",
29 | table: "Tickets");
30 |
31 | migrationBuilder.RenameTable(
32 | name: "Tickets",
33 | newName: "Ticket");
34 |
35 | migrationBuilder.AddPrimaryKey(
36 | name: "PK_Ticket",
37 | table: "Ticket",
38 | column: "Id");
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Processings/Users/UserProcessingService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Linq;
7 | using Tarteeb.Api.Brokers.Loggings;
8 | using Tarteeb.Api.Models.Foundations.Users;
9 | using Tarteeb.Api.Services.Foundations.Users;
10 |
11 | namespace Tarteeb.Api.Services.Processings.Users
12 | {
13 | public partial class UserProcessingService : IUserProcessingService
14 | {
15 | private readonly IUserService userService;
16 | private readonly ILoggingBroker loggingBroker;
17 |
18 | public UserProcessingService(IUserService userService, ILoggingBroker loggingBroker)
19 | {
20 | this.userService = userService;
21 | this.loggingBroker = loggingBroker;
22 | }
23 |
24 | public User RetrieveUserByCredentails(string email, string password) =>
25 | TryCatch(() =>
26 | {
27 | ValidateEmailAndPassword(email, password);
28 | IQueryable allUser = this.userService.RetrieveAllUsers();
29 |
30 | return allUser.FirstOrDefault(retrievedUser => retrievedUser.Email.Equals(email)
31 | && retrievedUser.Password.Equals(password));
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Securities/SecurityServiceTests.Logic.Create.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using FluentAssertions;
7 | using Moq;
8 | using Tarteeb.Api.Models.Foundations.Users;
9 | using Xunit;
10 |
11 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations;
12 |
13 | public partial class SecurityServiceTests
14 | {
15 | [Fact]
16 | public void ShouldCreateToken()
17 | {
18 | //given
19 | User randomUser = CreateRandomUser();
20 | User inputUser = randomUser;
21 | string randomString = CreateRandomString();
22 | string createdToken = randomString;
23 | string expectedToken = createdToken;
24 |
25 | this.tokenBrokerMock.Setup(broker =>
26 | broker.GenerateJWT(inputUser)).Returns(expectedToken);
27 |
28 | //when
29 | string actualToken = securityService.CreateToken(inputUser);
30 |
31 | //then
32 | actualToken.Should().BeEquivalentTo(expectedToken);
33 |
34 | this.tokenBrokerMock.Verify(broker =>
35 | broker.GenerateJWT(inputUser), Times.Once);
36 |
37 | this.tokenBrokerMock.VerifyNoOtherCalls();
38 | this.loggingBrokerMock.VerifyNoOtherCalls();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Tarteeb.Api.Tests.Unit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | disable
6 | disable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 | all
22 |
23 |
24 | runtime; build; native; contentfiles; analyzers; buildtransitive
25 | all
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221113120827_AddTeam.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Microsoft.EntityFrameworkCore.Migrations;
8 |
9 | #nullable disable
10 |
11 | namespace Tarteeb.Api.Migrations
12 | {
13 | public partial class AddTeam : Migration
14 | {
15 | protected override void Up(MigrationBuilder migrationBuilder)
16 | {
17 | migrationBuilder.CreateTable(
18 | name: "Teams",
19 | columns: table => new
20 | {
21 | Id = table.Column(type: "uniqueidentifier", nullable: false),
22 | TeamName = table.Column(type: "nvarchar(max)", nullable: true),
23 | CreatedDate = table.Column(type: "datetimeoffset", nullable: false),
24 | UpdatedDate = table.Column(type: "datetimeoffset", nullable: false)
25 | },
26 | constraints: table =>
27 | {
28 | table.PrimaryKey("PK_Teams", x => x.Id);
29 | });
30 | }
31 |
32 | protected override void Down(MigrationBuilder migrationBuilder)
33 | {
34 | migrationBuilder.DropTable(
35 | name: "Teams");
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Users/UserServiceTests.Logic.RetrieveAll.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Linq;
7 | using FluentAssertions;
8 | using Moq;
9 | using Tarteeb.Api.Models.Foundations.Users;
10 | using Xunit;
11 |
12 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Users
13 | {
14 | public partial class UserServiceTests
15 | {
16 | [Fact]
17 | public void ShouldRetrieveAllUsers()
18 | {
19 | // given
20 | IQueryable randomUsers = CreateRandomUsers();
21 | IQueryable storageUsers = randomUsers;
22 | IQueryable expectedUser = storageUsers;
23 |
24 | this.storageBrokerMock.Setup(broker =>
25 | broker.SelectAllUsers()).Returns(storageUsers);
26 |
27 | // when
28 | IQueryable actualUser = this.userService.RetrieveAllUsers();
29 |
30 | // then
31 | actualUser.Should().BeEquivalentTo(expectedUser);
32 |
33 | this.storageBrokerMock.Verify(broker =>
34 | broker.SelectAllUsers(), Times.Once());
35 |
36 | this.storageBrokerMock.VerifyNoOtherCalls();
37 | this.loggingBrokerMock.VerifyNoOtherCalls();
38 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Teams/TeamServiceTests.Logic.RetrieveAll.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Linq;
7 | using FluentAssertions;
8 | using Moq;
9 | using Tarteeb.Api.Models.Foundations.Teams;
10 | using Xunit;
11 |
12 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Teams
13 | {
14 | public partial class TeamServiceTests
15 | {
16 | [Fact]
17 | public void ShouldRetrieveAllTeams()
18 | {
19 | // given
20 | IQueryable randomTeams = CreateRandomTeams();
21 | IQueryable storageTeams = randomTeams;
22 | IQueryable expectedTeams = storageTeams;
23 |
24 | this.storageBrokerMock.Setup(broker =>
25 | broker.SelectAllTeams()).Returns(storageTeams);
26 |
27 | // when
28 | IQueryable actualTeams = this.teamService.RetrieveAllTeams();
29 |
30 | // then
31 | actualTeams.Should().BeEquivalentTo(expectedTeams);
32 |
33 | this.storageBrokerMock.Verify(broker =>
34 | broker.SelectAllTeams(), Times.Once());
35 |
36 | this.storageBrokerMock.VerifyNoOtherCalls();
37 | this.loggingBrokerMock.VerifyNoOtherCalls();
38 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Tickets/TicketServiceTests.Logic.RetrieveAll.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Linq;
7 | using FluentAssertions;
8 | using Moq;
9 | using Tarteeb.Api.Models.Foundations.Tickets;
10 | using Xunit;
11 |
12 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Tickets
13 | {
14 | public partial class TicketServiceTests
15 | {
16 | [Fact]
17 | public void ShouldRetrieveAllTickets()
18 | {
19 | // given
20 | IQueryable randomTickets = CreateRandomTickets();
21 | IQueryable storageTickets = randomTickets;
22 | IQueryable expectedTickets = storageTickets;
23 |
24 | this.storageBrokerMock.Setup(broker =>
25 | broker.SelectAllTickets()).Returns(storageTickets);
26 |
27 | // when
28 | IQueryable actualTicket =
29 | this.ticketService.RetrieveAllTickets();
30 |
31 | // then
32 | actualTicket.Should().BeEquivalentTo(expectedTickets);
33 |
34 | this.storageBrokerMock.Verify(broker =>
35 | broker.SelectAllTickets(), Times.Once);
36 |
37 | this.storageBrokerMock.VerifyNoOtherCalls();
38 | this.loggingBrokerMock.VerifyNoOtherCalls();
39 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20230210045018_UniqueEmail.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | #nullable disable
4 |
5 | namespace Tarteeb.Api.Migrations
6 | {
7 | ///
8 | public partial class UniqueEmail : Migration
9 | {
10 | ///
11 | protected override void Up(MigrationBuilder migrationBuilder)
12 | {
13 | migrationBuilder.AlterColumn(
14 | name: "Email",
15 | table: "Users",
16 | type: "nvarchar(450)",
17 | nullable: true,
18 | oldClrType: typeof(string),
19 | oldType: "nvarchar(max)",
20 | oldNullable: true);
21 |
22 | migrationBuilder.CreateIndex(
23 | name: "IX_Users_Email",
24 | table: "Users",
25 | column: "Email",
26 | unique: true,
27 | filter: "[Email] IS NOT NULL");
28 | }
29 |
30 | ///
31 | protected override void Down(MigrationBuilder migrationBuilder)
32 | {
33 | migrationBuilder.DropIndex(
34 | name: "IX_Users_Email",
35 | table: "Users");
36 |
37 | migrationBuilder.AlterColumn(
38 | name: "Email",
39 | table: "Users",
40 | type: "nvarchar(max)",
41 | nullable: true,
42 | oldClrType: typeof(string),
43 | oldType: "nvarchar(450)",
44 | oldNullable: true);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Processings/Users/UserProcessingsServiceTests.Logic.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using FluentAssertions;
9 | using Moq;
10 | using Tarteeb.Api.Models.Foundations.Users;
11 | using Xunit;
12 |
13 | namespace Tarteeb.Api.Tests.Unit.Services.Processings.Users
14 | {
15 | public partial class UserProcessingsServiceTests
16 | {
17 | [Fact]
18 | public void ShoulRetrieveUserByCredentails()
19 | {
20 | // given
21 | string inputEmail = GetrandomString();
22 | string inputPassword = GetrandomString();
23 | var expectedUser = new User { Email = inputEmail, Password = inputPassword };
24 | var users = new List { expectedUser };
25 |
26 | this.userServiceMock.Setup(service =>
27 | service.RetrieveAllUsers())
28 | .Returns(users.AsQueryable());
29 |
30 | // when
31 | User actualUser = userProcessingsService.
32 | RetrieveUserByCredentails(inputEmail, inputPassword);
33 |
34 | // then
35 | actualUser.Should().BeEquivalentTo(expectedUser);
36 |
37 | this.userServiceMock.Verify(service =>
38 | service.RetrieveAllUsers(), Times.Once);
39 |
40 | this.userServiceMock.VerifyNoOtherCalls();
41 | this.loggingBrokerMock.VerifyNoOtherCalls();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Users/UserServiceTests.Logic.RetrieveById.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Users;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Users
15 | {
16 | public partial class UserServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldRetrieveUserByIdAsync()
20 | {
21 | // given
22 | Guid randomUserId = Guid.NewGuid();
23 | Guid inputUserId = randomUserId;
24 | User randomUser = CreateRandomUser();
25 | User storedUser = randomUser;
26 | User exectedUser = storedUser.DeepClone();
27 |
28 | this.storageBrokerMock.Setup(broker =>
29 | broker.SelectUserByIdAsync(randomUserId)).ReturnsAsync(storedUser);
30 |
31 | // when
32 | User actualUser = await this.userService.RetrieveUserByIdAsync(inputUserId);
33 |
34 | // then
35 | actualUser.Should().BeEquivalentTo(exectedUser);
36 |
37 | this.storageBrokerMock.Verify(broker =>
38 | broker.SelectUserByIdAsync(inputUserId), Times.Once);
39 |
40 | this.storageBrokerMock.VerifyNoOtherCalls();
41 | this.loggingBrokerMock.VerifyNoOtherCalls();
42 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Processings/Users/UserProcessingService.Validations.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Models.Foundations.Users;
7 | using Tarteeb.Api.Models.Processings.Users;
8 |
9 | namespace Tarteeb.Api.Services.Processings.Users
10 | {
11 | public partial class UserProcessingService
12 | {
13 | private static void ValidateEmailAndPassword(string email, string password)
14 | {
15 | Validate(
16 | (Rule: IsInvalid(email), Parameter: nameof(User.Email)),
17 | (Rule: IsInvalid(password), Parameter: nameof(User.Password)));
18 | }
19 |
20 | private static dynamic IsInvalid(string text) => new
21 | {
22 | Condition = string.IsNullOrWhiteSpace(text),
23 | Message = "Text is required"
24 | };
25 |
26 | private static void Validate(params (dynamic Rule, string Parameter)[] validations)
27 | {
28 | var invalidUserProcessingException =
29 | new InvalidUserProcessingException();
30 |
31 | foreach ((dynamic rule, string parameter) in validations)
32 | {
33 | if (rule.Condition)
34 | {
35 | invalidUserProcessingException.UpsertDataList(
36 | key: parameter,
37 | value: rule.Message);
38 | }
39 | }
40 |
41 | invalidUserProcessingException.ThrowIfContainsErrors();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Teams/TeamServiceTests.Logic.RetrieveById.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Teams;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Teams
15 | {
16 | public partial class TeamServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldRetrieveTeamByIdAsync()
20 | {
21 | // given
22 | Guid randomTeamId = Guid.NewGuid();
23 | Guid inputTeamId = randomTeamId;
24 | Team randomTeam = CreateRandomTeam();
25 | Team storageTeam = randomTeam;
26 | Team expectedTeam = storageTeam.DeepClone();
27 |
28 | this.storageBrokerMock.Setup(broker =>
29 | broker.SelectTeamByIdAsync(inputTeamId)).ReturnsAsync(storageTeam);
30 |
31 | // when
32 | Team actualTeam =
33 | await this.teamService.RetrieveTeamByIdAsync(inputTeamId);
34 |
35 | // then
36 | actualTeam.Should().BeEquivalentTo(expectedTeam);
37 |
38 | this.storageBrokerMock.Verify(broker =>
39 | broker.SelectTeamByIdAsync(inputTeamId), Times.Once);
40 |
41 | this.storageBrokerMock.VerifyNoOtherCalls();
42 | this.loggingBrokerMock.VerifyNoOtherCalls();
43 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Tickets/TicketServiceTests.Logic.RetrieveById.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Tickets;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Tickets
15 | {
16 | public partial class TicketServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldRetriveTicketByIdAsync()
20 | {
21 | // given
22 | Guid randomTicketId = Guid.NewGuid();
23 | Guid inputTicketId = randomTicketId;
24 | Ticket randomTicket = CreateRandomTicket();
25 | Ticket storedTicket = randomTicket;
26 | Ticket expectedTicket = storedTicket.DeepClone();
27 |
28 | this.storageBrokerMock.Setup(broker =>
29 | broker.SelectTicketByIdAsync(randomTicketId)).ReturnsAsync(storedTicket);
30 |
31 | // when
32 | Ticket actualTicket =
33 | await this.ticketService.RetrieveTicketByIdAsync(inputTicketId);
34 |
35 | // then
36 | actualTicket.Should().BeEquivalentTo(expectedTicket);
37 |
38 | this.storageBrokerMock.Verify(broker =>
39 | broker.SelectTicketByIdAsync(inputTicketId), Times.Once);
40 |
41 | this.storageBrokerMock.VerifyNoOtherCalls();
42 | this.loggingBrokerMock.VerifyNoOtherCalls();
43 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/.github/workflows/master_tarteeb.yml:
--------------------------------------------------------------------------------
1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
2 | # More GitHub Actions for Azure: https://github.com/Azure/actions
3 |
4 | name: Build and deploy ASP.Net Core app to Azure Web App - tarteeb
5 |
6 | on:
7 | push:
8 | branches:
9 | - master
10 | workflow_dispatch:
11 |
12 | jobs:
13 | build:
14 | runs-on: windows-latest
15 |
16 | steps:
17 | - uses: actions/checkout@v2
18 |
19 | - name: Set up .NET Core
20 | uses: actions/setup-dotnet@v1
21 | with:
22 | dotnet-version: '7.x'
23 | include-prerelease: true
24 |
25 | - name: Build with dotnet
26 | run: dotnet build --configuration Release
27 |
28 | - name: dotnet publish
29 | run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
30 |
31 | - name: Upload artifact for deployment job
32 | uses: actions/upload-artifact@v2
33 | with:
34 | name: .net-app
35 | path: ${{env.DOTNET_ROOT}}/myapp
36 |
37 | deploy:
38 | runs-on: windows-latest
39 | needs: build
40 | environment:
41 | name: 'Production'
42 | url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
43 |
44 | steps:
45 | - name: Download artifact from build job
46 | uses: actions/download-artifact@v2
47 | with:
48 | name: .net-app
49 |
50 | - name: Deploy to Azure Web App
51 | id: deploy-to-webapp
52 | uses: azure/webapps-deploy@v2
53 | with:
54 | app-name: 'tarteeb'
55 | slot-name: 'Production'
56 | publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_53666BE2EF35438DA33DB8DDB1BC8DBC }}
57 | package: .
58 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221107175023_AddTasks.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Microsoft.EntityFrameworkCore.Migrations;
8 |
9 | #nullable disable
10 |
11 | namespace Tarteeb.Api.Migrations
12 | {
13 | public partial class AddTasks : Migration
14 | {
15 | protected override void Up(MigrationBuilder migrationBuilder)
16 | {
17 | migrationBuilder.CreateTable(
18 | name: "Tasks",
19 | columns: table => new
20 | {
21 | Id = table.Column(type: "uniqueidentifier", nullable: false),
22 | Title = table.Column(type: "nvarchar(max)", nullable: true),
23 | Description = table.Column(type: "nvarchar(max)", nullable: true),
24 | AssigneeId = table.Column(type: "uniqueidentifier", nullable: true),
25 | Status = table.Column(type: "int", nullable: false),
26 | CreatedDate = table.Column(type: "datetimeoffset", nullable: false),
27 | UpdatedDate = table.Column(type: "datetimeoffset", nullable: false),
28 | CreatedUserId = table.Column(type: "uniqueidentifier", nullable: false),
29 | UpdatedUserId = table.Column(type: "uniqueidentifier", nullable: false)
30 | },
31 | constraints: table =>
32 | {
33 | table.PrimaryKey("PK_Tasks", x => x.Id);
34 | });
35 | }
36 |
37 | protected override void Down(MigrationBuilder migrationBuilder)
38 | {
39 | migrationBuilder.DropTable(
40 | name: "Tasks");
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221112084050_AddUsers.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Microsoft.EntityFrameworkCore.Migrations;
8 |
9 | #nullable disable
10 |
11 | namespace Tarteeb.Api.Migrations
12 | {
13 | public partial class AddUsers : Migration
14 | {
15 | protected override void Up(MigrationBuilder migrationBuilder)
16 | {
17 | migrationBuilder.CreateTable(
18 | name: "Users",
19 | columns: table => new
20 | {
21 | Id = table.Column(type: "uniqueidentifier", nullable: false),
22 | FirstName = table.Column(type: "nvarchar(max)", nullable: true),
23 | LastName = table.Column(type: "nvarchar(max)", nullable: true),
24 | PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true),
25 | Email = table.Column(type: "nvarchar(max)", nullable: true),
26 | BirthDate = table.Column(type: "datetimeoffset", nullable: false),
27 | CreatedDate = table.Column(type: "datetimeoffset", nullable: false),
28 | UpdatedDate = table.Column(type: "datetimeoffset", nullable: false),
29 | ManagerId = table.Column(type: "uniqueidentifier", nullable: true)
30 | },
31 | constraints: table =>
32 | {
33 | table.PrimaryKey("PK_Users", x => x.Id);
34 | });
35 | }
36 |
37 | protected override void Down(MigrationBuilder migrationBuilder)
38 | {
39 | migrationBuilder.DropTable(
40 | name: "Users");
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Users/UserServiceTests.Logic.Add.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Users;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Users
15 | {
16 | public partial class UserServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldAddUserAsync()
20 | {
21 | // given
22 | DateTimeOffset randomDateTime = GetRandomDateTimeOffset();
23 | User randomUser = CreateRandomUser(randomDateTime);
24 | User inputUser = randomUser;
25 | User persistedUser = inputUser;
26 | User expectedUser = persistedUser.DeepClone();
27 |
28 | this.dateTimeBrokerMock.Setup(broker =>
29 | broker.GetCurrentDateTime()).Returns(randomDateTime);
30 |
31 | this.storageBrokerMock.Setup(broker =>
32 | broker.InsertUserAsync(inputUser))
33 | .ReturnsAsync(persistedUser);
34 |
35 | // when
36 | User actualUser = await this.userService.AddUserAsync(inputUser);
37 |
38 | // then
39 | actualUser.Should().BeEquivalentTo(expectedUser);
40 |
41 | this.dateTimeBrokerMock.Verify(broker =>
42 | broker.GetCurrentDateTime(), Times.Once);
43 |
44 | this.storageBrokerMock.Verify(broker =>
45 | broker.InsertUserAsync(inputUser), Times.Once);
46 |
47 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
48 | this.storageBrokerMock.VerifyNoOtherCalls();
49 | this.loggingBrokerMock.VerifyNoOtherCalls();
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Teams/TeamServiceTests.Logic.Add.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //===============================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Teams;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Teams
15 | {
16 | public partial class TeamServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldAddTeamAsync()
20 | {
21 | // given
22 | DateTimeOffset randomDateTime = GetRandomDateTime();
23 | Team randomTeam = CreateRandomTeam(randomDateTime);
24 | Team inputTeam = randomTeam;
25 | Team persistedTeam = inputTeam;
26 | Team expectedTeam = persistedTeam.DeepClone();
27 |
28 | this.dateTimeBrokerMock.Setup(broker =>
29 | broker.GetCurrentDateTime()).Returns(randomDateTime);
30 |
31 | this.storageBrokerMock.Setup(broker =>
32 | broker.InsertTeamAsync(inputTeam))
33 | .ReturnsAsync(persistedTeam);
34 |
35 | // when
36 | Team actuaTeam = await this.teamService
37 | .AddTeamAsync(inputTeam);
38 |
39 | // then
40 | actuaTeam.Should().BeEquivalentTo(expectedTeam);
41 |
42 | this.dateTimeBrokerMock.Verify(broker =>
43 | broker.GetCurrentDateTime(), Times.Once);
44 |
45 | this.storageBrokerMock.Verify(broker =>
46 | broker.InsertTeamAsync(inputTeam), Times.Once);
47 |
48 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
49 | this.storageBrokerMock.VerifyNoOtherCalls();
50 | this.loggingBrokerMock.VerifyNoOtherCalls();
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Tokens/TokenBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.IdentityModel.Tokens.Jwt;
8 | using System.Security.Claims;
9 | using System.Text;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.IdentityModel.Tokens;
12 | using Tarteeb.Api.Models.Foundations.Tokens;
13 | using Tarteeb.Api.Models.Foundations.Users;
14 |
15 | namespace Tarteeb.Api.Brokers.Tokens
16 | {
17 | public class TokenBroker : ITokenBroker
18 | {
19 | private readonly TokenConfiguration tokenConfiguration;
20 |
21 | public TokenBroker(IConfiguration configuration)
22 | {
23 | this.tokenConfiguration = new TokenConfiguration();
24 | configuration.Bind("Jwt", this.tokenConfiguration);
25 | }
26 |
27 | public string GenerateJWT(User user)
28 | {
29 |
30 | byte[] convertedKeyToBytes =
31 | Encoding.UTF8.GetBytes(this.tokenConfiguration.Key);
32 |
33 | var securityKey =
34 | new SymmetricSecurityKey(convertedKeyToBytes);
35 |
36 | var cridentials =
37 | new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
38 |
39 | var claims = new[]
40 | {
41 | new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
42 | new Claim(ClaimTypes.Email, user.Email)
43 | };
44 |
45 | var token = new JwtSecurityToken(
46 | this.tokenConfiguration.Issuer,
47 | this.tokenConfiguration.Audience,
48 | claims,
49 | expires: DateTime.Now.AddDays(1),
50 | signingCredentials: cridentials);
51 |
52 | return new JwtSecurityTokenHandler().WriteToken(token);
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Tickets/TicketServiceTests.Logic.Add.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Tickets;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Tickets
15 | {
16 | public partial class TicketServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldAddTicketAsync()
20 | {
21 | // given
22 | DateTimeOffset randomDateTime = GetRandomDateTime();
23 | Ticket randomTicket = CreateRandomTicket(randomDateTime);
24 | Ticket inputTicket = randomTicket;
25 | Ticket persistedTicket = inputTicket;
26 | Ticket expectedTicket = persistedTicket.DeepClone();
27 |
28 | this.dateTimeBrokerMock.Setup(broker =>
29 | broker.GetCurrentDateTime()).Returns(randomDateTime);
30 |
31 | this.storageBrokerMock.Setup(broker =>
32 | broker.InsertTicketAsync(inputTicket))
33 | .ReturnsAsync(persistedTicket);
34 |
35 | // when
36 | Ticket actualTicket = await this.ticketService.AddTicketAsync(inputTicket);
37 |
38 | // then
39 | actualTicket.Should().BeEquivalentTo(expectedTicket);
40 |
41 | this.dateTimeBrokerMock.Verify(broker =>
42 | broker.GetCurrentDateTime(), Times.Once);
43 |
44 | this.storageBrokerMock.Verify(broker =>
45 | broker.InsertTicketAsync(inputTicket), Times.Once);
46 |
47 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
48 | this.storageBrokerMock.VerifyNoOtherCalls();
49 | this.loggingBrokerMock.VerifyNoOtherCalls();
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Orchestrations/UserSecurityOrchestrationService.Validations.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Models.Foundations.Users;
7 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
8 | using Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions;
9 |
10 | namespace Tarteeb.Api.Services.Orchestrations
11 | {
12 | public partial class UserSecurityOrchestrationService
13 | {
14 | private static void ValidateEmailAndPassword(string email, string password)
15 | {
16 | Validate(
17 | (Rule: IsInvalid(email), Parameter: nameof(User.Email)),
18 | (Rule: IsInvalid(password), Parameter: nameof(User.Password)));
19 | }
20 |
21 | private void ValidateUserExists(User user)
22 | {
23 | if (user is null)
24 | {
25 | throw new NotFoundUserException();
26 | }
27 | }
28 |
29 | private static dynamic IsInvalid(string text) => new
30 | {
31 | Condition = string.IsNullOrWhiteSpace(text),
32 | Message = "Value is required"
33 | };
34 |
35 | private static void Validate(params (dynamic Rule, string Parameter)[] validations)
36 | {
37 | var invalidUserCreadentialOrchestrationException =
38 | new InvalidUserCredentialOrchestrationException();
39 |
40 | foreach ((dynamic rule, string parameter) in validations)
41 | {
42 | if (rule.Condition)
43 | {
44 | invalidUserCreadentialOrchestrationException.UpsertDataList(
45 | key: parameter,
46 | value: rule.Message);
47 | }
48 | }
49 |
50 | invalidUserCreadentialOrchestrationException.ThrowIfContainsErrors();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Securities/SecurityService.Validations.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Tarteeb.Api.Models.Foundations.Users;
8 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
9 |
10 | namespace Tarteeb.Api.Services.Foundations.Securities
11 | {
12 | public partial class SecurityService
13 | {
14 | private void ValidateUser(User user)
15 | {
16 | ValidateUserNotNull(user);
17 |
18 | Validate(
19 | (Rule: IsInvalid(user.Id), Parameter: nameof(User.Id)),
20 | (Rule: IsInvalid(user.Email), Parameter: nameof(User.Email)));
21 | }
22 |
23 | private static dynamic IsInvalid(string text) => new
24 | {
25 | Condition = string.IsNullOrWhiteSpace(text),
26 | Message = "Text is required"
27 | };
28 |
29 | private static dynamic IsInvalid(Guid id) => new
30 | {
31 | Condition = id == default,
32 | Message = "Id is required"
33 | };
34 |
35 | private static void ValidateUserNotNull(User user)
36 | {
37 | if (user is null)
38 | {
39 | throw new NullUserException();
40 | }
41 | }
42 |
43 | private static void Validate(params (dynamic Rule, string Parameter)[] validations)
44 | {
45 | var invalidUserException = new InvalidUserException();
46 |
47 | foreach ((dynamic rule, string parameter) in validations)
48 | {
49 | if (rule.Condition)
50 | {
51 | invalidUserException.UpsertDataList(
52 | key: parameter,
53 | value: rule.Message);
54 | }
55 | }
56 | invalidUserException.ThrowIfContainsErrors();
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Securities/SecurityServiceTests.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq.Expressions;
8 | using Moq;
9 | using Tarteeb.Api.Brokers.Loggings;
10 | using Tarteeb.Api.Brokers.Tokens;
11 | using Tarteeb.Api.Models.Foundations.Users;
12 | using Tarteeb.Api.Services.Foundations;
13 | using Tarteeb.Api.Services.Foundations.Securities;
14 | using Tynamix.ObjectFiller;
15 | using Xeptions;
16 |
17 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations;
18 |
19 | public partial class SecurityServiceTests
20 | {
21 | private readonly Mock tokenBrokerMock;
22 | private readonly Mock loggingBrokerMock;
23 | private readonly ISecurityService securityService;
24 |
25 | public SecurityServiceTests()
26 | {
27 | this.tokenBrokerMock = new Mock();
28 | this.loggingBrokerMock = new Mock();
29 |
30 | this.securityService = new SecurityService(
31 | tokenBrokerMock.Object,
32 | loggingBrokerMock.Object);
33 | }
34 |
35 | private Expression> SameExceptionAs(Xeption expectedException) =>
36 | actualException => actualException.SameExceptionAs(expectedException);
37 |
38 | private string CreateRandomString() =>
39 | new MnemonicString().GetValue();
40 |
41 | private static User CreateRandomUser() =>
42 | CreateUserFiller(dates: GetRandomDateTimeOffset()).Create();
43 |
44 | private static DateTimeOffset GetRandomDateTimeOffset() =>
45 | new DateTimeRange(earliestDate: DateTime.UnixEpoch).GetValue();
46 |
47 | private static Filler CreateUserFiller(DateTimeOffset dates)
48 | {
49 | var filler = new Filler();
50 |
51 | filler.Setup()
52 | .OnType().Use(dates);
53 |
54 | return filler;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Tarteeb.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | /subscriptions/892dd3c3-3966-40a3-8503-76152027a3e7/resourceGroups/tarteeb/providers/microsoft.insights/components/tarteeb
6 | 2fffb16c-3e15-47b2-a365-20241733061f
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | all
19 | runtime; build; native; contentfiles; analyzers; buildtransitive
20 |
21 |
22 |
23 |
24 | all
25 | runtime; build; native; contentfiles; analyzers; buildtransitive
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Teams/TeamServiceTests.Logic.RemoveById.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Teams;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Teams
15 | {
16 | public partial class TeamServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldRemoveTeamByIdAsync()
20 | {
21 | // given
22 | Guid randomId = Guid.NewGuid();
23 | Guid inputTeamId = randomId;
24 | Team randomTeam = CreateRandomTeam();
25 | Team storageTeam = randomTeam;
26 | Team expectedInputTeam = storageTeam;
27 | Team deletedTeam = expectedInputTeam;
28 | Team expectedTeam = deletedTeam.DeepClone();
29 |
30 | this.storageBrokerMock.Setup(broker =>
31 | broker.SelectTeamByIdAsync(inputTeamId))
32 | .ReturnsAsync(storageTeam);
33 |
34 | this.storageBrokerMock.Setup(broker =>
35 | broker.DeleteTeamAsync(expectedInputTeam))
36 | .ReturnsAsync(deletedTeam);
37 |
38 | // when
39 | Team actualTeam = await this.teamService
40 | .RemoveTeamByIdAsync(inputTeamId);
41 |
42 | // then
43 | actualTeam.Should().BeEquivalentTo(expectedTeam);
44 |
45 | this.storageBrokerMock.Verify(broker =>
46 | broker.SelectTeamByIdAsync(inputTeamId), Times.Once);
47 |
48 | this.storageBrokerMock.Verify(broker =>
49 | broker.DeleteTeamAsync(expectedInputTeam), Times.Once);
50 |
51 | this.storageBrokerMock.VerifyNoOtherCalls();
52 | this.loggingBrokerMock.VerifyNoOtherCalls();
53 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Users/UserServiceTests.Logic.RemoveById.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Users;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Users
15 | {
16 | public partial class UserServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldRemoveUserByIdAsync()
20 | {
21 | // given
22 | Guid randomId = Guid.NewGuid();
23 | Guid inputUserId = randomId;
24 | User randomUser = CreateRandomUser();
25 | User storageUser = randomUser;
26 | User expectedInputUser = storageUser;
27 | User deletedUser = expectedInputUser;
28 | User expectedUser = deletedUser.DeepClone();
29 |
30 | this.storageBrokerMock.Setup(broker =>
31 | broker.SelectUserByIdAsync(inputUserId))
32 | .ReturnsAsync(storageUser);
33 |
34 | this.storageBrokerMock.Setup(broker =>
35 | broker.DeleteUserAsync(expectedInputUser))
36 | .ReturnsAsync(deletedUser);
37 |
38 | // when
39 | User actualUser = await this.userService
40 | .RemoveUserByIdAsync(inputUserId);
41 |
42 | // then
43 | actualUser.Should().BeEquivalentTo(expectedUser);
44 |
45 | this.storageBrokerMock.Verify(broker =>
46 | broker.SelectUserByIdAsync(inputUserId), Times.Once);
47 |
48 | this.storageBrokerMock.Verify(broker =>
49 | broker.DeleteUserAsync(expectedInputUser), Times.Once);
50 |
51 | this.storageBrokerMock.VerifyNoOtherCalls();
52 | this.loggingBrokerMock.VerifyNoOtherCalls();
53 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Securities/SecurityService.Exceptions.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
8 | using Xeptions;
9 |
10 | namespace Tarteeb.Api.Services.Foundations.Securities
11 | {
12 | public partial class SecurityService
13 | {
14 | private delegate string ReturningTokenFunction();
15 |
16 | private string TryCatch(ReturningTokenFunction returningTokenFunction)
17 | {
18 | try
19 | {
20 | return returningTokenFunction();
21 | }
22 | catch (NullUserException nullUserException)
23 | {
24 | throw CreateAndLogValidationException(nullUserException);
25 | }
26 | catch (InvalidUserException invalidUserException)
27 | {
28 | throw CreateAndLogValidationException(invalidUserException);
29 | }
30 | catch (Exception serviceException)
31 | {
32 | var failedUserServiceException =
33 | new FailedUserServiceException(serviceException);
34 |
35 | throw CreateAndLogServiceException(failedUserServiceException);
36 | }
37 |
38 | }
39 |
40 | private UserValidationException CreateAndLogValidationException(Xeption exception)
41 | {
42 | var userValidationException =
43 | new UserValidationException(exception);
44 |
45 | this.loggingBroker.LogError(userValidationException);
46 |
47 | return userValidationException;
48 | }
49 |
50 | private UserServiceException CreateAndLogServiceException(Xeption exception)
51 | {
52 | var userServiceException =
53 | new UserServiceException(exception);
54 |
55 | this.loggingBroker.LogError(userServiceException);
56 |
57 | return userServiceException;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Orchestrations/UserSecurityOrchestrationService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Linq;
7 | using Tarteeb.Api.Brokers.Loggings;
8 | using Tarteeb.Api.Models.Foundations.Users;
9 | using Tarteeb.Api.Models.Orchestrations.UserTokens;
10 | using Tarteeb.Api.Services.Foundations.Securities;
11 | using Tarteeb.Api.Services.Foundations.Users;
12 |
13 | namespace Tarteeb.Api.Services.Orchestrations
14 | {
15 | public partial class UserSecurityOrchestrationService : IUserSecurityOrchestrationService
16 | {
17 | private readonly IUserService userService;
18 | private readonly ISecurityService securityService;
19 | private readonly ILoggingBroker loggingBroker;
20 |
21 | public UserSecurityOrchestrationService(
22 | IUserService userService,
23 | ISecurityService securityService,
24 | ILoggingBroker loggingBroker)
25 | {
26 | this.userService = userService;
27 | this.securityService = securityService;
28 | this.loggingBroker = loggingBroker;
29 | }
30 |
31 | public UserToken CreateUserToken(string email, string password) =>
32 | TryCatch(() =>
33 | {
34 | ValidateEmailAndPassword(email, password);
35 | User maybeUser = RetrieveUserByEmailAndPassword(email, password);
36 | ValidateUserExists(maybeUser);
37 | string token = this.securityService.CreateToken(maybeUser);
38 |
39 | return new UserToken
40 | {
41 | UserId = maybeUser.Id,
42 | Token = token
43 | };
44 | });
45 |
46 | private User RetrieveUserByEmailAndPassword(string email, string password)
47 | {
48 | IQueryable allUser = this.userService.RetrieveAllUsers();
49 |
50 | return allUser.FirstOrDefault(retrievedUser => retrievedUser.Email.Equals(email)
51 | && retrievedUser.Password.Equals(password));
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Tickets/TicketServiceTests.Logic.RemoveById.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Tickets;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Tickets
15 | {
16 | public partial class TicketServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldRemoveTicketByIdAsync()
20 | {
21 | // given
22 | Guid randomId = Guid.NewGuid();
23 | Guid inputTicketId = randomId;
24 | Ticket randomTicket = CreateRandomTicket();
25 | Ticket storageTicket = randomTicket;
26 | Ticket expectedInputTicket = storageTicket;
27 | Ticket deletedTicket = expectedInputTicket;
28 | Ticket expectedTicket = deletedTicket.DeepClone();
29 |
30 | this.storageBrokerMock.Setup(broker =>
31 | broker.SelectTicketByIdAsync(inputTicketId))
32 | .ReturnsAsync(storageTicket);
33 |
34 | this.storageBrokerMock.Setup(broker =>
35 | broker.DeleteTicketAsync(expectedInputTicket))
36 | .ReturnsAsync(deletedTicket);
37 |
38 | // when
39 | Ticket actualTicket = await this.ticketService
40 | .RemoveTicketByIdAsync(inputTicketId);
41 |
42 | // then
43 | actualTicket.Should().BeEquivalentTo(expectedTicket);
44 |
45 | this.storageBrokerMock.Verify(broker =>
46 | broker.SelectTicketByIdAsync(inputTicketId), Times.Once);
47 |
48 | this.storageBrokerMock.Verify(broker =>
49 | broker.DeleteTicketAsync(expectedInputTicket), Times.Once);
50 |
51 | this.storageBrokerMock.VerifyNoOtherCalls();
52 | this.loggingBrokerMock.VerifyNoOtherCalls();
53 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Processings/Users/UserProcessingsServiceTests.Exceptions.Retrieve.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using FluentAssertions;
8 | using Moq;
9 | using Tarteeb.Api.Models.Processings.Users;
10 | using Xeptions;
11 | using Xunit;
12 |
13 | namespace Tarteeb.Api.Tests.Unit.Services.Processings.Users
14 | {
15 | public partial class UserProcessingsServiceTests
16 | {
17 | [Theory]
18 | [MemberData(nameof(UserDependencyExceptions))]
19 | public void ShoudThrowDependencyExceptionOnRetrieveIfDependencyErrorOccursAndLogItAsync(
20 | Xeption dependencyException)
21 | {
22 | // given
23 | string someString = GetrandomString();
24 |
25 | var expectedUserProcessingDependencyException =
26 | new UserProcessingDependencyException(dependencyException);
27 |
28 | this.userServiceMock.Setup(service => service.RetrieveAllUsers())
29 | .Throws(dependencyException);
30 |
31 | // when
32 | Action retrieveUserByAction = () =>
33 | this.userProcessingsService.RetrieveUserByCredentails(email: someString, password: someString);
34 |
35 | UserProcessingDependencyException actualUserProcessingDependencyException =
36 | Assert.Throws(retrieveUserByAction);
37 |
38 | // then
39 | actualUserProcessingDependencyException.Should().BeEquivalentTo(
40 | expectedUserProcessingDependencyException);
41 |
42 | this.userServiceMock.Verify(service => service.RetrieveAllUsers(), Times.Once);
43 |
44 | this.loggingBrokerMock.Verify(broker =>
45 | broker.LogError(It.Is(SameExceptionAs(
46 | expectedUserProcessingDependencyException))),
47 | Times.Once);
48 |
49 | this.userServiceMock.VerifyNoOtherCalls();
50 | this.loggingBrokerMock.VerifyNoOtherCalls();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Processings/Users/UserProcessingService.Exceptions.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Tarteeb.Api.Models.Foundations.Users;
7 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
8 | using Tarteeb.Api.Models.Processings.Users;
9 | using Xeptions;
10 |
11 | namespace Tarteeb.Api.Services.Processings.Users
12 | {
13 | public partial class UserProcessingService
14 | {
15 | private delegate User ReturningUserFunction();
16 |
17 | private User TryCatch(ReturningUserFunction returningUserFunction)
18 | {
19 | try
20 | {
21 | return returningUserFunction();
22 | }
23 | catch (InvalidUserProcessingException invalidUserProcessingException)
24 | {
25 | throw CreateAndLogValidationException(invalidUserProcessingException);
26 | }
27 | catch (UserDependencyException userDependencyException)
28 | {
29 | throw CreateAndLogDependencyException(userDependencyException);
30 | }
31 | catch (UserServiceException userServiceException)
32 | {
33 | throw CreateAndLogDependencyException(userServiceException);
34 | }
35 | }
36 |
37 | private UserProcessingValidationException CreateAndLogValidationException(Xeption exception)
38 | {
39 | var userProcessingValidationException =
40 | new UserProcessingValidationException(exception);
41 |
42 | this.loggingBroker.LogError(userProcessingValidationException);
43 |
44 | return userProcessingValidationException;
45 | }
46 |
47 | private UserProcessingDependencyException CreateAndLogDependencyException(Xeption exception)
48 | {
49 | var userProcessingDependencyException = new UserProcessingDependencyException(exception);
50 | this.loggingBroker.LogError(userProcessingDependencyException);
51 |
52 | return userProcessingDependencyException;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Infrastructure.Build/Program.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //===============================
5 |
6 | using ADotNet.Clients;
7 | using ADotNet.Models.Pipelines.GithubPipelines.DotNets;
8 | using ADotNet.Models.Pipelines.GithubPipelines.DotNets.Tasks;
9 | using ADotNet.Models.Pipelines.GithubPipelines.DotNets.Tasks.SetupDotNetTaskV1s;
10 |
11 | var githubPipeline = new GithubPipeline
12 | {
13 | Name = "Tarteeb Build Process",
14 |
15 | OnEvents = new Events
16 | {
17 | Push = new PushEvent
18 | {
19 | Branches = new string[] { "master" }
20 | },
21 |
22 | PullRequest = new PullRequestEvent
23 | {
24 | Branches = new string[] { "master" }
25 | }
26 | },
27 |
28 | Jobs = new Jobs
29 | {
30 | Build = new BuildJob
31 | {
32 | RunsOn = BuildMachines.Windows2022,
33 |
34 | Steps = new List
35 | {
36 | new CheckoutTaskV2
37 | {
38 | Name = "Check out"
39 | },
40 |
41 | new SetupDotNetTaskV1
42 | {
43 | Name = "Setup .Net",
44 |
45 | TargetDotNetVersion = new TargetDotNetVersion
46 | {
47 | DotNetVersion = "7.0.100",
48 | IncludePrerelease = true
49 | }
50 | },
51 |
52 | new RestoreTask
53 | {
54 | Name = "Restore Packages"
55 | },
56 |
57 | new DotNetBuildTask
58 | {
59 | Name = "Build Projects"
60 | },
61 |
62 | new TestTask
63 | {
64 | Name = "Run Tests"
65 | }
66 | }
67 | }
68 | }
69 | };
70 |
71 | var adotnetClient = new ADotNetClient();
72 |
73 | adotnetClient.SerializeAndWriteToFile(
74 | adoPipeline: githubPipeline,
75 | path: "../../../../.github/workflows/build.yml");
76 |
--------------------------------------------------------------------------------
/Tarteeb.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32825.248
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tarteeb.Api", "Tarteeb.Api\Tarteeb.Api.csproj", "{B9288356-F87C-4D2F-835C-43C8E0D1F379}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tarteeb.Api.Infrastructure.Build", "Tarteeb.Api.Infrastructure.Build\Tarteeb.Api.Infrastructure.Build.csproj", "{DF3F7A6B-D6B0-4BC5-8567-AD7009146848}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tarteeb.Api.Tests.Unit", "Tarteeb.Api.Tests.Unit\Tarteeb.Api.Tests.Unit.csproj", "{3498A3E3-475F-4442-9B9F-60C572DC9B67}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {B9288356-F87C-4D2F-835C-43C8E0D1F379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {B9288356-F87C-4D2F-835C-43C8E0D1F379}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {B9288356-F87C-4D2F-835C-43C8E0D1F379}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {B9288356-F87C-4D2F-835C-43C8E0D1F379}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {DF3F7A6B-D6B0-4BC5-8567-AD7009146848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {DF3F7A6B-D6B0-4BC5-8567-AD7009146848}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {DF3F7A6B-D6B0-4BC5-8567-AD7009146848}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {DF3F7A6B-D6B0-4BC5-8567-AD7009146848}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {3498A3E3-475F-4442-9B9F-60C572DC9B67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {3498A3E3-475F-4442-9B9F-60C572DC9B67}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {3498A3E3-475F-4442-9B9F-60C572DC9B67}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {3498A3E3-475F-4442-9B9F-60C572DC9B67}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {72C341B3-EBED-4C92-A7F7-549182919620}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Orchestrations/UserSecurityOrchestrationServiceTests.Logic.Create.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Linq;
7 | using FluentAssertions;
8 | using Moq;
9 | using Tarteeb.Api.Models.Foundations.Users;
10 | using Tarteeb.Api.Models.Orchestrations.UserTokens;
11 | using Xunit;
12 |
13 | namespace Tarteeb.Api.Tests.Unit.Services.Orchestrations
14 | {
15 | public partial class UserSecurityOrchestrationServiceTests
16 | {
17 | [Fact]
18 | public void ShoudCreateUserToken()
19 | {
20 | // given
21 | string randomString = GetRandomString();
22 | string token = randomString;
23 | User randomUser = CreateRandomUser();
24 | User existingUser = randomUser;
25 |
26 | IQueryable randomUsers =
27 | CreateRandomUsersIncluding(existingUser);
28 |
29 | IQueryable retrievedUsers = randomUsers;
30 |
31 | UserToken expectedUserToken = new UserToken
32 | {
33 | UserId = existingUser.Id,
34 | Token = token
35 | };
36 |
37 | this.userServiceMock.Setup(service =>
38 | service.RetrieveAllUsers()).Returns(retrievedUsers);
39 |
40 | this.securityServiceMock.Setup(service =>
41 | service.CreateToken(existingUser)).Returns(token);
42 |
43 | // when
44 | UserToken actualUserToken = this.userSecurityOrchestrationService
45 | .CreateUserToken(existingUser.Email, existingUser.Password);
46 |
47 | // then
48 | actualUserToken.Should().BeEquivalentTo(expectedUserToken);
49 |
50 | this.userServiceMock.Verify(service => service.RetrieveAllUsers(),
51 | Times.Once);
52 |
53 | this.securityServiceMock.Verify(service => service.CreateToken(
54 | existingUser), Times.Once);
55 |
56 | this.userServiceMock.VerifyNoOtherCalls();
57 | this.securityServiceMock.VerifyNoOtherCalls();
58 | this.loggingBrokerMock.VerifyNoOtherCalls();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Processings/Users/UserProcessingsServiceTests.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq.Expressions;
8 | using Moq;
9 | using Tarteeb.Api.Brokers.Loggings;
10 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
11 | using Tarteeb.Api.Services.Foundations.Users;
12 | using Tarteeb.Api.Services.Processings.Users;
13 | using Tynamix.ObjectFiller;
14 | using Xeptions;
15 | using Xunit;
16 |
17 | namespace Tarteeb.Api.Tests.Unit.Services.Processings.Users
18 | {
19 | public partial class UserProcessingsServiceTests
20 | {
21 | private readonly Mock userServiceMock;
22 | private readonly Mock loggingBrokerMock;
23 | private readonly IUserProcessingService userProcessingsService;
24 |
25 | public UserProcessingsServiceTests()
26 | {
27 | this.userServiceMock = new Mock();
28 | this.loggingBrokerMock = new Mock();
29 |
30 | this.userProcessingsService = new UserProcessingService(
31 | userService: this.userServiceMock.Object,
32 | loggingBroker: this.loggingBrokerMock.Object);
33 | }
34 |
35 | public static TheoryData UserDependencyExceptions()
36 | {
37 | var someInnerException = new Xeption();
38 |
39 | return new TheoryData
40 | {
41 | new UserDependencyException(someInnerException),
42 | new UserServiceException(someInnerException)
43 | };
44 | }
45 |
46 | private static string GetrandomString() =>
47 | new MnemonicString(wordCount: GetRandomNumber()).GetValue();
48 |
49 | private static Expression> SameExceptionAs(Xeption expectedException) =>
50 | actualException => actualException.SameExceptionAs(expectedException);
51 |
52 | private static int GetRandomNumber() =>
53 | new IntRange(min: 2, max: 10).GetValue();
54 |
55 | private static DateTimeOffset GetRandomDate() =>
56 | new DateTimeRange(earliestDate: DateTime.UnixEpoch).GetValue();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221107175023_AddTasks.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Tarteeb.Api.Brokers.Storages;
9 |
10 | #nullable disable
11 |
12 | namespace Tarteeb.Api.Migrations
13 | {
14 | [DbContext(typeof(StorageBroker))]
15 | [Migration("20221107175023_AddTasks")]
16 | partial class AddTasks
17 | {
18 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
19 | {
20 | #pragma warning disable 612, 618
21 | modelBuilder
22 | .HasAnnotation("ProductVersion", "6.0.10")
23 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
24 |
25 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
26 |
27 | modelBuilder.Entity("Tarteeb.Api.Models.Tasks.Task", b =>
28 | {
29 | b.Property("Id")
30 | .ValueGeneratedOnAdd()
31 | .HasColumnType("uniqueidentifier");
32 |
33 | b.Property("AssigneeId")
34 | .HasColumnType("uniqueidentifier");
35 |
36 | b.Property("CreatedDate")
37 | .HasColumnType("datetimeoffset");
38 |
39 | b.Property("CreatedUserId")
40 | .HasColumnType("uniqueidentifier");
41 |
42 | b.Property("Description")
43 | .HasColumnType("nvarchar(max)");
44 |
45 | b.Property("Status")
46 | .HasColumnType("int");
47 |
48 | b.Property("Title")
49 | .HasColumnType("nvarchar(max)");
50 |
51 | b.Property("UpdatedDate")
52 | .HasColumnType("datetimeoffset");
53 |
54 | b.Property("UpdatedUserId")
55 | .HasColumnType("uniqueidentifier");
56 |
57 | b.HasKey("Id");
58 |
59 | b.ToTable("Tasks");
60 | });
61 | #pragma warning restore 612, 618
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Teams/TeamServiceTests.Logic.Modify.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Teams;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Teams
15 | {
16 | public partial class TeamServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldModifyTeamAsync()
20 | {
21 | // given
22 | DateTimeOffset randomDate = GetRandomDateTime();
23 | Team randomTeam = CreateRandomModifyTeam(randomDate);
24 | Team inputTeam = randomTeam;
25 | Team storageTeam = inputTeam.DeepClone();
26 | storageTeam.UpdatedDate = randomTeam.CreatedDate;
27 | Team updatedTeam = inputTeam;
28 | Team exceptedTeam = updatedTeam.DeepClone();
29 | Guid TeamId = inputTeam.Id;
30 |
31 | this.dateTimeBrokerMock.Setup(broker =>
32 | broker.GetCurrentDateTime()).Returns(randomDate);
33 |
34 | this.storageBrokerMock.Setup(broker =>
35 | broker.SelectTeamByIdAsync(TeamId))
36 | .ReturnsAsync(storageTeam);
37 |
38 | this.storageBrokerMock.Setup(broker =>
39 | broker.UpdateTeamAsync(inputTeam))
40 | .ReturnsAsync(updatedTeam);
41 |
42 | // when
43 | Team actualTeam =
44 | await this.teamService.ModifyTeamAsync(inputTeam);
45 |
46 | // then
47 | actualTeam.Should().BeEquivalentTo(exceptedTeam);
48 |
49 | this.dateTimeBrokerMock.Verify(broker =>
50 | broker.GetCurrentDateTime(), Times.Once);
51 |
52 | this.storageBrokerMock.Verify(broker =>
53 | broker.SelectTeamByIdAsync(TeamId), Times.Once);
54 |
55 | this.storageBrokerMock.Verify(broker =>
56 | broker.UpdateTeamAsync(inputTeam), Times.Once);
57 |
58 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
59 | this.storageBrokerMock.VerifyNoOtherCalls();
60 | this.loggingBrokerMock.VerifyNoOtherCalls();
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Users/UserServiceTests.Logic.Modify.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Users;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Users
15 | {
16 | public partial class UserServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldModifyUserAsync()
20 | {
21 | // given
22 | DateTimeOffset randomDate = GetRandomDateTimeOffset();
23 | User randomUser = CreateRandomModifyUser(randomDate);
24 | User inputUser = randomUser;
25 | User storageUser = inputUser.DeepClone();
26 | storageUser.UpdatedDate = randomUser.CreatedDate;
27 | User updatedUser = inputUser;
28 | User exceptedUser = updatedUser.DeepClone();
29 | Guid userId = inputUser.Id;
30 |
31 | this.dateTimeBrokerMock.Setup(broker =>
32 | broker.GetCurrentDateTime()).Returns(randomDate);
33 |
34 | this.storageBrokerMock.Setup(broker =>
35 | broker.SelectUserByIdAsync(userId))
36 | .ReturnsAsync(storageUser);
37 |
38 | this.storageBrokerMock.Setup(broker =>
39 | broker.UpdateUserAsync(inputUser))
40 | .ReturnsAsync(updatedUser);
41 |
42 | // when
43 | User actualUser =
44 | await this.userService.ModifyUserAsync(inputUser);
45 |
46 | // then
47 | actualUser.Should().BeEquivalentTo(exceptedUser);
48 |
49 | this.dateTimeBrokerMock.Verify(broker =>
50 | broker.GetCurrentDateTime(), Times.Once);
51 |
52 | this.storageBrokerMock.Verify(broker =>
53 | broker.SelectUserByIdAsync(userId), Times.Once);
54 |
55 | this.storageBrokerMock.Verify(broker =>
56 | broker.UpdateUserAsync(inputUser), Times.Once);
57 |
58 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
59 | this.storageBrokerMock.VerifyNoOtherCalls();
60 | this.loggingBrokerMock.VerifyNoOtherCalls();
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Processings/Users/UserProcessingsServiceTests.Validation.Retrieve.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using FluentAssertions;
8 | using Moq;
9 | using Tarteeb.Api.Models.Foundations.Users;
10 | using Tarteeb.Api.Models.Processings.Users;
11 | using Xunit;
12 |
13 | namespace Tarteeb.Api.Tests.Unit.Services.Processings.Users
14 | {
15 | public partial class UserProcessingsServiceTests
16 | {
17 | [Fact]
18 | public void ShouldThrowValidationExceptionOnUpsertIfEmailAndPasswordAreInvalidAndLogItAsync()
19 | {
20 | //given
21 | string invalidEmail = string.Empty;
22 | string invalidPassword = string.Empty;
23 | var invalidUserProcessingException = new InvalidUserProcessingException();
24 |
25 | invalidUserProcessingException.AddData(
26 | key: nameof(User.Email),
27 | values: "Text is required");
28 |
29 | invalidUserProcessingException.AddData(
30 | key: nameof(User.Password),
31 | values: "Text is required");
32 |
33 | var expectedUserProcessingValidationException =
34 | new UserProcessingValidationException(invalidUserProcessingException);
35 |
36 | //when
37 | Action retrieveUserByAction = () =>
38 | this.userProcessingsService.RetrieveUserByCredentails(invalidEmail, invalidPassword);
39 |
40 | UserProcessingValidationException actualUserProcessingValidationException =
41 | Assert.Throws(retrieveUserByAction);
42 |
43 | //then
44 | actualUserProcessingValidationException.Should().BeEquivalentTo(
45 | expectedUserProcessingValidationException);
46 |
47 | this.loggingBrokerMock.Verify(broker =>
48 | broker.LogError(It.Is(SameExceptionAs(
49 | expectedUserProcessingValidationException))), Times.Once);
50 |
51 | this.userServiceMock.Verify(service =>
52 | service.RetrieveAllUsers(), Times.Never);
53 |
54 | this.loggingBrokerMock.VerifyNoOtherCalls();
55 | this.userServiceMock.VerifyNoOtherCalls();
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Tickets/TicketServiceTests.Logic.Modify.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //===============================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Force.DeepCloner;
10 | using Moq;
11 | using Tarteeb.Api.Models.Foundations.Tickets;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Tickets
15 | {
16 | public partial class TicketServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldModifyTicketAsync()
20 | {
21 | // given
22 | DateTimeOffset randomDate = GetRandomDateTime();
23 | Ticket randomTicket = CreateRandomModifyTicket(randomDate);
24 | Ticket inputTicket = randomTicket;
25 | Ticket storageTicket = inputTicket.DeepClone();
26 | storageTicket.UpdatedDate = randomTicket.CreatedDate;
27 | Ticket updatedTicket = inputTicket;
28 | Ticket expectedTicket = updatedTicket.DeepClone();
29 | Guid ticketId = inputTicket.Id;
30 |
31 | this.dateTimeBrokerMock.Setup(broker =>
32 | broker.GetCurrentDateTime()).Returns(randomDate);
33 |
34 | this.storageBrokerMock.Setup(broker =>
35 | broker.SelectTicketByIdAsync(ticketId)).ReturnsAsync(storageTicket);
36 |
37 | this.storageBrokerMock.Setup(broker =>
38 | broker.UpdateTicketAsync(inputTicket)).ReturnsAsync(updatedTicket);
39 |
40 | // when
41 | Ticket actualTicket =
42 | await this.ticketService.ModifyTicketAsync(inputTicket);
43 |
44 | // then
45 | actualTicket.Should().BeEquivalentTo(expectedTicket);
46 |
47 | this.dateTimeBrokerMock.Verify(broker =>
48 | broker.GetCurrentDateTime(), Times.Once);
49 |
50 | this.storageBrokerMock.Verify(broker =>
51 | broker.SelectTicketByIdAsync(ticketId), Times.Once);
52 |
53 | this.storageBrokerMock.Verify(broker =>
54 | broker.UpdateTicketAsync(inputTicket), Times.Once);
55 |
56 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
57 | this.storageBrokerMock.VerifyNoOtherCalls();
58 | this.loggingBrokerMock.VerifyNoOtherCalls();
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Controllers/AccountsController.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using Microsoft.AspNetCore.Mvc;
7 | using RESTFulSense.Controllers;
8 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
9 | using Tarteeb.Api.Models.Orchestrations.UserTokens;
10 | using Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions;
11 | using Tarteeb.Api.Services.Orchestrations;
12 |
13 | namespace Tarteeb.Api.Controllers
14 | {
15 | [ApiController]
16 | [Route("api/[controller]/[action]")]
17 | public class AccountsController : RESTFulController
18 | {
19 | private readonly IUserSecurityOrchestrationService userSecurityOrchestrationService;
20 |
21 | public AccountsController(IUserSecurityOrchestrationService userSecurityOrchestrationService) =>
22 | this.userSecurityOrchestrationService = userSecurityOrchestrationService;
23 |
24 | [HttpGet]
25 | public ActionResult Login(string email, string password)
26 | {
27 | try
28 | {
29 | return this.userSecurityOrchestrationService.CreateUserToken(email, password);
30 | }
31 | catch (UserTokenOrchestrationValidationException userTokenOrchestrationValidationException)
32 | when (userTokenOrchestrationValidationException.InnerException is InvalidUserException)
33 |
34 | {
35 | return BadRequest(userTokenOrchestrationValidationException.InnerException);
36 | }
37 | catch (UserTokenOrchestrationValidationException userTokenOrchestrationValidationException)
38 | when (userTokenOrchestrationValidationException.InnerException is NotFoundUserException)
39 | {
40 | return NotFound(userTokenOrchestrationValidationException.InnerException);
41 | }
42 | catch (UserTokenOrchestrationDependencyException userTokenOrchestrationDependencyException)
43 | {
44 | return InternalServerError(userTokenOrchestrationDependencyException.InnerException);
45 | }
46 | catch (UserTokenOrchestrationServiceException userTokenOrchestrationServiceException)
47 | {
48 | return InternalServerError(userTokenOrchestrationServiceException.InnerException);
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Brokers/Storages/StorageBroker.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 | using EFxceptions;
9 | using Microsoft.EntityFrameworkCore;
10 | using Microsoft.Extensions.Configuration;
11 |
12 | namespace Tarteeb.Api.Brokers.Storages
13 | {
14 | public partial class StorageBroker : EFxceptionsContext, IStorageBroker
15 | {
16 | private readonly IConfiguration configuration;
17 |
18 | public StorageBroker(IConfiguration configuration)
19 | {
20 | this.configuration = configuration;
21 | this.Database.Migrate();
22 | }
23 |
24 | private async ValueTask InsertAsync(T @object)
25 | {
26 | var broker = new StorageBroker(this.configuration);
27 |
28 | broker.Entry(@object).State = EntityState.Added;
29 | await broker.SaveChangesAsync();
30 |
31 | return @object;
32 | }
33 |
34 | private IQueryable SelectAll() where T : class
35 | {
36 | var broker = new StorageBroker(this.configuration);
37 |
38 | return broker.Set();
39 | }
40 |
41 | private async ValueTask SelectAsync(params object[] objectIds) where T : class
42 | {
43 | var broker = new StorageBroker(this.configuration);
44 |
45 | return await broker.FindAsync(objectIds);
46 | }
47 |
48 | private async ValueTask UpdateAsync(T @object)
49 | {
50 | var broker = new StorageBroker(this.configuration);
51 | broker.Entry(@object).State = EntityState.Modified;
52 | await broker.SaveChangesAsync();
53 |
54 | return @object;
55 | }
56 |
57 | private async ValueTask DeleteAsync(T @object)
58 | {
59 | var broker = new StorageBroker(this.configuration);
60 | broker.Entry(@object).State = EntityState.Deleted;
61 | await broker.SaveChangesAsync();
62 |
63 | return @object;
64 | }
65 |
66 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
67 | {
68 | string connectionString =
69 | this.configuration.GetConnectionString(name: "DefaultConnection");
70 |
71 | optionsBuilder.UseSqlServer(connectionString);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Properties/ServiceDependencies/local/appInsights1.arm.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "resourceGroupName": {
6 | "type": "string",
7 | "defaultValue": "tarteeb",
8 | "metadata": {
9 | "_parameterType": "resourceGroup",
10 | "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
11 | }
12 | },
13 | "resourceGroupLocation": {
14 | "type": "string",
15 | "defaultValue": "eastus",
16 | "metadata": {
17 | "_parameterType": "location",
18 | "description": "Location of the resource group. Resource groups could have different location than resources."
19 | }
20 | },
21 | "resourceLocation": {
22 | "type": "string",
23 | "defaultValue": "[parameters('resourceGroupLocation')]",
24 | "metadata": {
25 | "_parameterType": "location",
26 | "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
27 | }
28 | }
29 | },
30 | "resources": [
31 | {
32 | "type": "Microsoft.Resources/resourceGroups",
33 | "name": "[parameters('resourceGroupName')]",
34 | "location": "[parameters('resourceGroupLocation')]",
35 | "apiVersion": "2019-10-01"
36 | },
37 | {
38 | "type": "Microsoft.Resources/deployments",
39 | "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('tarteeb', subscription().subscriptionId)))]",
40 | "resourceGroup": "[parameters('resourceGroupName')]",
41 | "apiVersion": "2019-10-01",
42 | "dependsOn": [
43 | "[parameters('resourceGroupName')]"
44 | ],
45 | "properties": {
46 | "mode": "Incremental",
47 | "template": {
48 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
49 | "contentVersion": "1.0.0.0",
50 | "resources": [
51 | {
52 | "name": "tarteeb",
53 | "type": "microsoft.insights/components",
54 | "location": "[parameters('resourceLocation')]",
55 | "kind": "web",
56 | "properties": {},
57 | "apiVersion": "2015-05-01"
58 | }
59 | ]
60 | }
61 | }
62 | }
63 | ],
64 | "metadata": {
65 | "_dependencyType": "appInsights.azure"
66 | }
67 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221110181513_ChangePriority.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Tarteeb.Api.Brokers.Storages;
9 |
10 | #nullable disable
11 |
12 | namespace Tarteeb.Api.Migrations
13 | {
14 | [DbContext(typeof(StorageBroker))]
15 | [Migration("20221110181513_ChangePriority")]
16 | partial class ChangePriority
17 | {
18 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
19 | {
20 | #pragma warning disable 612, 618
21 | modelBuilder
22 | .HasAnnotation("ProductVersion", "6.0.10")
23 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
24 |
25 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
26 |
27 | modelBuilder.Entity("Tarteeb.Api.Models.Tickets.Ticket", b =>
28 | {
29 | b.Property("Id")
30 | .ValueGeneratedOnAdd()
31 | .HasColumnType("uniqueidentifier");
32 |
33 | b.Property("AssigneeId")
34 | .HasColumnType("uniqueidentifier");
35 |
36 | b.Property("CreatedDate")
37 | .HasColumnType("datetimeoffset");
38 |
39 | b.Property("CreatedUserId")
40 | .HasColumnType("uniqueidentifier");
41 |
42 | b.Property("Deadline")
43 | .HasColumnType("datetimeoffset");
44 |
45 | b.Property("Description")
46 | .HasColumnType("nvarchar(max)");
47 |
48 | b.Property("Priority")
49 | .HasColumnType("int");
50 |
51 | b.Property("Status")
52 | .HasColumnType("int");
53 |
54 | b.Property("Title")
55 | .HasColumnType("nvarchar(max)");
56 |
57 | b.Property("UpdatedDate")
58 | .HasColumnType("datetimeoffset");
59 |
60 | b.Property("UpdatedUserId")
61 | .HasColumnType("uniqueidentifier");
62 |
63 | b.HasKey("Id");
64 |
65 | b.ToTable("Tickets");
66 | });
67 | #pragma warning restore 612, 618
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221110171741_RenameTaskToTicket.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Tarteeb.Api.Brokers.Storages;
9 |
10 | #nullable disable
11 |
12 | namespace Tarteeb.Api.Migrations
13 | {
14 | [DbContext(typeof(StorageBroker))]
15 | [Migration("20221110171741_RenameTaskToTicket")]
16 | partial class RenameTaskToTicket
17 | {
18 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
19 | {
20 | #pragma warning disable 612, 618
21 | modelBuilder
22 | .HasAnnotation("ProductVersion", "6.0.10")
23 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
24 |
25 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
26 |
27 | modelBuilder.Entity("Tarteeb.Api.Models.Tickets.Ticket", b =>
28 | {
29 | b.Property("Id")
30 | .ValueGeneratedOnAdd()
31 | .HasColumnType("uniqueidentifier");
32 |
33 | b.Property("AssigneeId")
34 | .HasColumnType("uniqueidentifier");
35 |
36 | b.Property("CreatedDate")
37 | .HasColumnType("datetimeoffset");
38 |
39 | b.Property("CreatedUserId")
40 | .HasColumnType("uniqueidentifier");
41 |
42 | b.Property("Deadline")
43 | .HasColumnType("datetimeoffset");
44 |
45 | b.Property("Description")
46 | .HasColumnType("nvarchar(max)");
47 |
48 | b.Property("Priority")
49 | .HasColumnType("int");
50 |
51 | b.Property("Status")
52 | .HasColumnType("int");
53 |
54 | b.Property("Title")
55 | .HasColumnType("nvarchar(max)");
56 |
57 | b.Property("UpdatedDate")
58 | .HasColumnType("datetimeoffset");
59 |
60 | b.Property("UpdatedUserId")
61 | .HasColumnType("uniqueidentifier");
62 |
63 | b.HasKey("Id");
64 |
65 | b.ToTable("Ticket");
66 | });
67 | #pragma warning restore 612, 618
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221110175226_RenameTicketToTickets.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Tarteeb.Api.Brokers.Storages;
9 |
10 | #nullable disable
11 |
12 | namespace Tarteeb.Api.Migrations
13 | {
14 | [DbContext(typeof(StorageBroker))]
15 | [Migration("20221110175226_RenameTicketToTickets")]
16 | partial class RenameTicketToTickets
17 | {
18 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
19 | {
20 | #pragma warning disable 612, 618
21 | modelBuilder
22 | .HasAnnotation("ProductVersion", "6.0.10")
23 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
24 |
25 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
26 |
27 | modelBuilder.Entity("Tarteeb.Api.Models.Tickets.Ticket", b =>
28 | {
29 | b.Property("Id")
30 | .ValueGeneratedOnAdd()
31 | .HasColumnType("uniqueidentifier");
32 |
33 | b.Property("AssigneeId")
34 | .HasColumnType("uniqueidentifier");
35 |
36 | b.Property("CreatedDate")
37 | .HasColumnType("datetimeoffset");
38 |
39 | b.Property("CreatedUserId")
40 | .HasColumnType("uniqueidentifier");
41 |
42 | b.Property("Deadline")
43 | .HasColumnType("datetimeoffset");
44 |
45 | b.Property("Description")
46 | .HasColumnType("nvarchar(max)");
47 |
48 | b.Property("Priority")
49 | .HasColumnType("int");
50 |
51 | b.Property("Status")
52 | .HasColumnType("int");
53 |
54 | b.Property("Title")
55 | .HasColumnType("nvarchar(max)");
56 |
57 | b.Property("UpdatedDate")
58 | .HasColumnType("datetimeoffset");
59 |
60 | b.Property("UpdatedUserId")
61 | .HasColumnType("uniqueidentifier");
62 |
63 | b.HasKey("Id");
64 |
65 | b.ToTable("Tickets");
66 | });
67 | #pragma warning restore 612, 618
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Users/UserService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Brokers.DateTimes;
10 | using Tarteeb.Api.Brokers.Loggings;
11 | using Tarteeb.Api.Brokers.Storages;
12 | using Tarteeb.Api.Models.Foundations.Users;
13 |
14 | namespace Tarteeb.Api.Services.Foundations.Users
15 | {
16 | public partial class UserService : IUserService
17 | {
18 | private readonly IStorageBroker storageBroker;
19 | private readonly IDateTimeBroker dateTimeBroker;
20 | private readonly ILoggingBroker loggingBroker;
21 |
22 | public UserService(
23 | IStorageBroker storageBroker,
24 | IDateTimeBroker dateTimeBroker,
25 | ILoggingBroker loggingBroker)
26 | {
27 | this.storageBroker = storageBroker;
28 | this.dateTimeBroker = dateTimeBroker;
29 | this.loggingBroker = loggingBroker;
30 | }
31 |
32 | public ValueTask AddUserAsync(User user) =>
33 | TryCatch(async () =>
34 | {
35 | ValidateUserOnAdd(user);
36 |
37 | return await this.storageBroker.InsertUserAsync(user);
38 | });
39 |
40 | public IQueryable RetrieveAllUsers() =>
41 | TryCatch(() => this.storageBroker.SelectAllUsers());
42 |
43 | public ValueTask RetrieveUserByIdAsync(Guid userId) =>
44 | TryCatch(async () =>
45 | {
46 | ValidateUserId(userId);
47 |
48 | User maybeUser =
49 | await this.storageBroker.SelectUserByIdAsync(userId);
50 |
51 | ValidateStorageUser(maybeUser, userId);
52 |
53 | return maybeUser;
54 | });
55 |
56 | public ValueTask ModifyUserAsync(User user) =>
57 | TryCatch(async () =>
58 | {
59 | ValidateUserOnModify(user);
60 | var maybeUser = await this.storageBroker.SelectUserByIdAsync(user.Id);
61 | ValidateAginstStorageUserOnModify(inputUser: user, storageUser: maybeUser);
62 |
63 | return await this.storageBroker.UpdateUserAsync(user);
64 | });
65 |
66 | public ValueTask RemoveUserByIdAsync(Guid userId) =>
67 | TryCatch(async () =>
68 | {
69 | ValidateUserId(userId);
70 |
71 | User maybeUser =
72 | await this.storageBroker.SelectUserByIdAsync(userId);
73 |
74 | ValidateStorageUser(maybeUser, userId);
75 |
76 | return await this.storageBroker.DeleteUserAsync(maybeUser);
77 | });
78 | }
79 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Teams/TeamService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Brokers.DateTimes;
10 | using Tarteeb.Api.Brokers.Loggings;
11 | using Tarteeb.Api.Brokers.Storages;
12 | using Tarteeb.Api.Models.Foundations.Teams;
13 |
14 | namespace Tarteeb.Api.Services.Foundations.Teams
15 | {
16 | public partial class TeamService : ITeamService
17 | {
18 | private readonly IStorageBroker storageBroker;
19 | private readonly IDateTimeBroker dateTimeBroker;
20 | private readonly ILoggingBroker loggingBroker;
21 |
22 | public TeamService(
23 | IStorageBroker storageBroker,
24 | IDateTimeBroker dateTimeBroker,
25 | ILoggingBroker loggingBroker)
26 |
27 | {
28 | this.storageBroker = storageBroker;
29 | this.dateTimeBroker = dateTimeBroker;
30 | this.loggingBroker = loggingBroker;
31 | }
32 |
33 | public ValueTask AddTeamAsync(Team team) =>
34 | TryCatch(async () =>
35 | {
36 | ValidateTeam(team);
37 |
38 | return await this.storageBroker.InsertTeamAsync(team);
39 | });
40 |
41 | public IQueryable RetrieveAllTeams() =>
42 | TryCatch(() => this.storageBroker.SelectAllTeams());
43 |
44 | public ValueTask RetrieveTeamByIdAsync(Guid teamId) =>
45 | TryCatch(async () =>
46 | {
47 | ValidateTeamId(teamId);
48 |
49 | Team maybeTeam =
50 | await storageBroker.SelectTeamByIdAsync(teamId);
51 |
52 | ValidateStorageTeamExists(maybeTeam, teamId);
53 |
54 | return maybeTeam;
55 | });
56 |
57 | public ValueTask ModifyTeamAsync(Team team) =>
58 | TryCatch(async () =>
59 | {
60 | ValidateTeamOnModify(team);
61 |
62 | var maybeTeam =
63 | await this.storageBroker.SelectTeamByIdAsync(team.Id);
64 |
65 | ValidateAgainstStorageTeamOnModify(inputTeam: team, storageTeam: maybeTeam);
66 |
67 | return await this.storageBroker.UpdateTeamAsync(team);
68 | });
69 |
70 | public ValueTask RemoveTeamByIdAsync(Guid teamId) =>
71 | TryCatch(async () =>
72 | {
73 | ValidateTeamId(teamId);
74 |
75 | Team maybeTeam =
76 | await this.storageBroker.SelectTeamByIdAsync(teamId);
77 |
78 | ValidateStorageTeamExists(maybeTeam, teamId);
79 |
80 | return await this.storageBroker.DeleteTeamAsync(maybeTeam);
81 | });
82 | }
83 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Foundations/Tickets/TicketService.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Tarteeb.Api.Brokers.DateTimes;
10 | using Tarteeb.Api.Brokers.Loggings;
11 | using Tarteeb.Api.Brokers.Storages;
12 | using Tarteeb.Api.Models.Foundations.Tickets;
13 |
14 | namespace Tarteeb.Api.Services.Foundations.Tickets
15 | {
16 | public partial class TicketService : ITicketService
17 | {
18 | private readonly IStorageBroker storageBroker;
19 | private readonly IDateTimeBroker dateTimeBroker;
20 | private readonly ILoggingBroker loggingBroker;
21 |
22 | public TicketService(
23 | IStorageBroker storageBroker,
24 | IDateTimeBroker dateTimeBroker,
25 | ILoggingBroker loggingBroker)
26 | {
27 | this.storageBroker = storageBroker;
28 | this.dateTimeBroker = dateTimeBroker;
29 | this.loggingBroker = loggingBroker;
30 | }
31 |
32 | public ValueTask AddTicketAsync(Ticket ticket) =>
33 | TryCatch(async () =>
34 | {
35 | ValidateTicketOnAdd(ticket);
36 |
37 | return await this.storageBroker.InsertTicketAsync(ticket);
38 | });
39 |
40 | public IQueryable RetrieveAllTickets() =>
41 | TryCatch(() => this.storageBroker.SelectAllTickets());
42 |
43 | public ValueTask RetrieveTicketByIdAsync(Guid ticketId) =>
44 | TryCatch(async () =>
45 | {
46 | ValidateTicketId(ticketId);
47 |
48 | Ticket maybeTicket =
49 | await this.storageBroker.SelectTicketByIdAsync(ticketId);
50 |
51 | ValidateStorageTicket(maybeTicket, ticketId);
52 |
53 | return maybeTicket;
54 | });
55 |
56 | public ValueTask ModifyTicketAsync(Ticket ticket) =>
57 | TryCatch(async () =>
58 | {
59 | ValidateTicketOnModify(ticket);
60 | var maybeTicket = await this.storageBroker.SelectTicketByIdAsync(ticket.Id);
61 |
62 | ValidateStorageTicket(maybeTicket, ticket.Id);
63 | ValidateAginstStorageTicketOnModify(inputTicket: ticket, storageTicket: maybeTicket);
64 |
65 | return await this.storageBroker.UpdateTicketAsync(ticket);
66 | });
67 |
68 | public ValueTask RemoveTicketByIdAsync(Guid ticketId) =>
69 | TryCatch(async () =>
70 | {
71 | ValidateTicketId(ticketId);
72 |
73 | Ticket maybeTicket = await this.storageBroker
74 | .SelectTicketByIdAsync(ticketId);
75 |
76 | ValidateStorageTicket(maybeTicket, ticketId);
77 |
78 | return await this.storageBroker.DeleteTicketAsync(maybeTicket);
79 | });
80 | }
81 | }
--------------------------------------------------------------------------------
/Tarteeb.Api/Services/Orchestrations/UserSecurityOrchestrationService.Exceptions.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
8 | using Tarteeb.Api.Models.Orchestrations.UserTokens;
9 | using Tarteeb.Api.Models.Orchestrations.UserTokens.Exceptions;
10 | using Xeptions;
11 |
12 | namespace Tarteeb.Api.Services.Orchestrations
13 | {
14 | public partial class UserSecurityOrchestrationService
15 | {
16 | private delegate UserToken ReturningUserTokenFunction();
17 |
18 | private UserToken TryCatch(ReturningUserTokenFunction returningUserTokenFunction)
19 | {
20 | try
21 | {
22 | return returningUserTokenFunction();
23 | }
24 | catch (InvalidUserCredentialOrchestrationException invalidUserCreadentialOrchestrationException)
25 | {
26 | throw CreateAndLogValidationException(invalidUserCreadentialOrchestrationException);
27 | }
28 | catch (NotFoundUserException notFoundUserException)
29 | {
30 | throw CreateAndLogValidationException(notFoundUserException);
31 | }
32 | catch (UserDependencyException userDependencyException)
33 | {
34 | throw CreateAndLogDependencyException(userDependencyException);
35 | }
36 | catch (UserServiceException userServiceException)
37 | {
38 | throw CreateAndLogDependencyException(userServiceException);
39 | }
40 | catch(Exception exception)
41 | {
42 | var failedUserTokenOrchestrationException =
43 | new FailedUserTokenOrchestrationException(exception);
44 |
45 | throw CreateAndLogServiceException(failedUserTokenOrchestrationException);
46 | }
47 | }
48 |
49 | private UserTokenOrchestrationValidationException CreateAndLogValidationException(Xeption exception)
50 | {
51 | var userTokenOrchestrationValidationException = new UserTokenOrchestrationValidationException(exception);
52 | this.loggingBroker.LogError(userTokenOrchestrationValidationException);
53 |
54 | return userTokenOrchestrationValidationException;
55 | }
56 |
57 | private UserTokenOrchestrationDependencyException CreateAndLogDependencyException(Xeption exception)
58 | {
59 | var userTokenOrchestrationDependencyException = new UserTokenOrchestrationDependencyException(exception);
60 | this.loggingBroker.LogError(userTokenOrchestrationDependencyException);
61 |
62 | return userTokenOrchestrationDependencyException;
63 | }
64 |
65 | private UserTokenOrchestrationServiceException CreateAndLogServiceException(Xeption exception)
66 | {
67 | var userTokenOrchestrationServiceException =
68 | new UserTokenOrchestrationServiceException(exception);
69 |
70 | this.loggingBroker.LogError(userTokenOrchestrationServiceException);
71 |
72 | return userTokenOrchestrationServiceException;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221110171741_RenameTaskToTicket.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using Microsoft.EntityFrameworkCore.Migrations;
8 |
9 | #nullable disable
10 |
11 | namespace Tarteeb.Api.Migrations
12 | {
13 | public partial class RenameTaskToTicket : Migration
14 | {
15 | protected override void Up(MigrationBuilder migrationBuilder)
16 | {
17 | migrationBuilder.DropTable(
18 | name: "Tasks");
19 |
20 | migrationBuilder.CreateTable(
21 | name: "Ticket",
22 | columns: table => new
23 | {
24 | Id = table.Column(type: "uniqueidentifier", nullable: false),
25 | Title = table.Column(type: "nvarchar(max)", nullable: true),
26 | Description = table.Column(type: "nvarchar(max)", nullable: true),
27 | Priority = table.Column(type: "int", nullable: false),
28 | Deadline = table.Column(type: "datetimeoffset", nullable: false),
29 | AssigneeId = table.Column(type: "uniqueidentifier", nullable: true),
30 | Status = table.Column(type: "int", nullable: false),
31 | CreatedDate = table.Column(type: "datetimeoffset", nullable: false),
32 | UpdatedDate = table.Column(type: "datetimeoffset", nullable: false),
33 | CreatedUserId = table.Column(type: "uniqueidentifier", nullable: false),
34 | UpdatedUserId = table.Column(type: "uniqueidentifier", nullable: false)
35 | },
36 | constraints: table =>
37 | {
38 | table.PrimaryKey("PK_Ticket", x => x.Id);
39 | });
40 | }
41 |
42 | protected override void Down(MigrationBuilder migrationBuilder)
43 | {
44 | migrationBuilder.DropTable(
45 | name: "Ticket");
46 |
47 | migrationBuilder.CreateTable(
48 | name: "Tasks",
49 | columns: table => new
50 | {
51 | Id = table.Column(type: "uniqueidentifier", nullable: false),
52 | AssigneeId = table.Column(type: "uniqueidentifier", nullable: true),
53 | CreatedDate = table.Column(type: "datetimeoffset", nullable: false),
54 | CreatedUserId = table.Column(type: "uniqueidentifier", nullable: false),
55 | Description = table.Column(type: "nvarchar(max)", nullable: true),
56 | Status = table.Column(type: "int", nullable: false),
57 | Title = table.Column(type: "nvarchar(max)", nullable: true),
58 | UpdatedDate = table.Column(type: "datetimeoffset", nullable: false),
59 | UpdatedUserId = table.Column(type: "uniqueidentifier", nullable: false)
60 | },
61 | constraints: table =>
62 | {
63 | table.PrimaryKey("PK_Tasks", x => x.Id);
64 | });
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Tarteeb.Api/Migrations/20221113120827_AddTeam.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using Tarteeb.Api.Brokers.Storages;
9 |
10 | #nullable disable
11 |
12 | namespace Tarteeb.Api.Migrations
13 | {
14 | [DbContext(typeof(StorageBroker))]
15 | [Migration("20221113120827_AddTeam")]
16 | partial class AddTeam
17 | {
18 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
19 | {
20 | #pragma warning disable 612, 618
21 | modelBuilder
22 | .HasAnnotation("ProductVersion", "6.0.10")
23 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
24 |
25 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
26 |
27 | modelBuilder.Entity("Tarteeb.Api.Models.Teams.Team", b =>
28 | {
29 | b.Property("Id")
30 | .ValueGeneratedOnAdd()
31 | .HasColumnType("uniqueidentifier");
32 |
33 | b.Property("CreatedDate")
34 | .HasColumnType("datetimeoffset");
35 |
36 | b.Property("TeamName")
37 | .HasColumnType("nvarchar(max)");
38 |
39 | b.Property("UpdatedDate")
40 | .HasColumnType("datetimeoffset");
41 |
42 | b.HasKey("Id");
43 |
44 | b.ToTable("Teams");
45 | });
46 |
47 | modelBuilder.Entity("Tarteeb.Api.Models.Tickets.Ticket", b =>
48 | {
49 | b.Property("Id")
50 | .ValueGeneratedOnAdd()
51 | .HasColumnType("uniqueidentifier");
52 |
53 | b.Property("AssigneeId")
54 | .HasColumnType("uniqueidentifier");
55 |
56 | b.Property("CreatedDate")
57 | .HasColumnType("datetimeoffset");
58 |
59 | b.Property("CreatedUserId")
60 | .HasColumnType("uniqueidentifier");
61 |
62 | b.Property("Deadline")
63 | .HasColumnType("datetimeoffset");
64 |
65 | b.Property("Description")
66 | .HasColumnType("nvarchar(max)");
67 |
68 | b.Property("Priority")
69 | .HasColumnType("int");
70 |
71 | b.Property("Status")
72 | .HasColumnType("int");
73 |
74 | b.Property("Title")
75 | .HasColumnType("nvarchar(max)");
76 |
77 | b.Property("UpdatedDate")
78 | .HasColumnType("datetimeoffset");
79 |
80 | b.Property("UpdatedUserId")
81 | .HasColumnType("uniqueidentifier");
82 |
83 | b.HasKey("Id");
84 |
85 | b.ToTable("Tickets");
86 | });
87 | #pragma warning restore 612, 618
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Securities/SecurityServiceTests.Validations.Create.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using FluentAssertions;
7 | using Moq;
8 | using Tarteeb.Api.Models.Foundations.Users;
9 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
10 | using Xunit;
11 |
12 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations
13 | {
14 |
15 | public partial class SecurityServiceTests
16 | {
17 | [Fact]
18 | public void ShouldThrowValidationExceptionOnCreateJWTIfInputIsNullAndLogItAsync()
19 | {
20 | //given
21 | User noUser = null;
22 | var nullUserException = new NullUserException();
23 |
24 | var expectedUserValidationException =
25 | new UserValidationException(nullUserException);
26 |
27 | //when
28 | UserValidationException actualUserValidationException =
29 | Assert.Throws(() => this.securityService.CreateToken(noUser));
30 |
31 | //then
32 | actualUserValidationException.Should().BeEquivalentTo(
33 | expectedUserValidationException);
34 |
35 | this.loggingBrokerMock.Verify(broker =>
36 | broker.LogError(It.Is(SameExceptionAs(
37 | expectedUserValidationException))), Times.Once);
38 |
39 | this.tokenBrokerMock.Verify(broker =>
40 | broker.GenerateJWT(It.IsAny()), Times.Never);
41 |
42 | this.loggingBrokerMock.VerifyNoOtherCalls();
43 | this.tokenBrokerMock.VerifyNoOtherCalls();
44 | }
45 |
46 | [Theory]
47 | [InlineData(null)]
48 | [InlineData("")]
49 | [InlineData(" ")]
50 | public void ShouldThrowValidationExceptionOnCreateJWTIfUserIsInvalidAndLogItAsync(
51 | string invalidString)
52 | {
53 | //given
54 | var invalidUser = new User
55 | {
56 | Email = invalidString
57 | };
58 |
59 | var invalidUserException = new InvalidUserException();
60 |
61 | invalidUserException.AddData(
62 | key: nameof(User.Id),
63 | values: "Id is required");
64 |
65 | invalidUserException.AddData(
66 | key: nameof(User.Email),
67 | values: "Text is required");
68 |
69 | var expectedUserValidationException = new UserValidationException(
70 | invalidUserException);
71 |
72 | //when
73 | UserValidationException actualUserValidationException =
74 | Assert.Throws(() => this.securityService.CreateToken(invalidUser));
75 |
76 | //then
77 | actualUserValidationException.Should().BeEquivalentTo(
78 | expectedUserValidationException);
79 |
80 | this.loggingBrokerMock.Verify(broker =>
81 | broker.LogError(It.Is(SameExceptionAs(
82 | expectedUserValidationException))), Times.Once);
83 |
84 | this.tokenBrokerMock.Verify(broker =>
85 | broker.GenerateJWT(It.IsAny()), Times.Never);
86 |
87 | this.loggingBrokerMock.VerifyNoOtherCalls();
88 | this.tokenBrokerMock.VerifyNoOtherCalls();
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Users/UserServiceTests.Exceptions.RetrieveAll.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using FluentAssertions;
8 | using Microsoft.Data.SqlClient;
9 | using Moq;
10 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
11 | using Xunit;
12 |
13 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Users
14 | {
15 | public partial class UserServiceTests
16 | {
17 | [Fact]
18 | public void ShouldThrowCriticalDependencyExceptionOnRetrieveAllIfSqlErrorOccursAndLogIt()
19 | {
20 | // given
21 | SqlException sqlException = CreateSqlException();
22 |
23 | var failedUserStorageException =
24 | new FailedUserStorageException(sqlException);
25 |
26 | var expectedUserDependencyException =
27 | new UserDependencyException(failedUserStorageException);
28 |
29 | this.storageBrokerMock.Setup(broker =>
30 | broker.SelectAllUsers())
31 | .Throws(sqlException);
32 |
33 | // when
34 | Action retrieveAllUsersAction = () =>
35 | this.userService.RetrieveAllUsers();
36 |
37 | UserDependencyException actualUserDependencyException =
38 | Assert.Throws(retrieveAllUsersAction);
39 |
40 | // then
41 | actualUserDependencyException.Should().BeEquivalentTo(expectedUserDependencyException);
42 |
43 | this.storageBrokerMock.Verify(broker =>
44 | broker.SelectAllUsers(), Times.Once);
45 |
46 | this.loggingBrokerMock.Verify(broker =>
47 | broker.LogCritical(It.Is(SameExceptionAs(
48 | expectedUserDependencyException))), Times.Once);
49 |
50 | this.storageBrokerMock.VerifyNoOtherCalls();
51 | this.loggingBrokerMock.VerifyNoOtherCalls();
52 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
53 | }
54 |
55 | [Fact]
56 | public void ShouldThrowServiceExceptionOnRetrieveAllWhenAllServiceErrorOccursAndLogIt()
57 | {
58 | // given
59 | string exceptionMessage = GetRandomString();
60 | var serviceException = new Exception(exceptionMessage);
61 |
62 | var failedUserServiceException =
63 | new FailedUserServiceException(serviceException);
64 |
65 | var expecteduserServiceException =
66 | new UserServiceException(failedUserServiceException);
67 |
68 | this.storageBrokerMock.Setup(broker =>
69 | broker.SelectAllUsers()).Throws(serviceException);
70 |
71 | // when
72 | Action retrieveAllUserAction = () =>
73 | this.userService.RetrieveAllUsers();
74 |
75 | // then
76 | Assert.Throws(retrieveAllUserAction);
77 |
78 | this.storageBrokerMock.Verify(broker =>
79 | broker.SelectAllUsers(), Times.Once);
80 |
81 | this.loggingBrokerMock.Verify(broker =>
82 | broker.LogError(It.Is(SameExceptionAs(
83 | expecteduserServiceException))), Times.Once);
84 |
85 | this.storageBrokerMock.VerifyNoOtherCalls();
86 | this.loggingBrokerMock.VerifyNoOtherCalls();
87 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Orchestrations/UserSecurityOrchestrationServiceTests.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Linq.Expressions;
10 | using Moq;
11 | using RESTFulSense.Models;
12 | using Tarteeb.Api.Brokers.Loggings;
13 | using Tarteeb.Api.Models.Foundations.Users;
14 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
15 | using Tarteeb.Api.Services.Foundations.Securities;
16 | using Tarteeb.Api.Services.Foundations.Users;
17 | using Tarteeb.Api.Services.Orchestrations;
18 | using Tynamix.ObjectFiller;
19 | using Xeptions;
20 | using Xunit;
21 |
22 | namespace Tarteeb.Api.Tests.Unit.Services.Orchestrations
23 | {
24 | public partial class UserSecurityOrchestrationServiceTests
25 | {
26 | private readonly Mock userServiceMock;
27 | private readonly Mock securityServiceMock;
28 | private readonly Mock loggingBrokerMock;
29 | private readonly IUserSecurityOrchestrationService userSecurityOrchestrationService;
30 |
31 | public UserSecurityOrchestrationServiceTests()
32 | {
33 | userServiceMock = new Mock();
34 | securityServiceMock = new Mock();
35 | loggingBrokerMock = new Mock();
36 |
37 | this.userSecurityOrchestrationService = new UserSecurityOrchestrationService(
38 | userService: userServiceMock.Object,
39 | securityService: securityServiceMock.Object,
40 | loggingBroker: loggingBrokerMock.Object);
41 | }
42 |
43 | public static TheoryData UserDependencyExceptions()
44 | {
45 | var someInnerException = new Xeption();
46 |
47 | return new TheoryData
48 | {
49 | new UserDependencyException(someInnerException),
50 | new UserServiceException(someInnerException)
51 | };
52 | }
53 |
54 | private static string GetRandomString() =>
55 | new MnemonicString().GetValue();
56 |
57 | private static DateTimeOffset GetRandomDate() =>
58 | new DateTimeRange(earliestDate: DateTime.UnixEpoch).GetValue();
59 |
60 | private static int GetRandomNumber() =>
61 | new IntRange(min: 2, max: 9).GetValue();
62 |
63 | private static Expression> SameExceptionAs(Xeption expectedException) =>
64 | actualException => actualException.SameExceptionAs(expectedException);
65 |
66 | private IQueryable CreateRandomUsers() =>
67 | CreateUserFiller().Create(count: GetRandomNumber()).AsQueryable();
68 |
69 | private IQueryable CreateRandomUsersIncluding(User user)
70 | {
71 | List users = CreateUserFiller()
72 | .Create(count: GetRandomNumber()).ToList();
73 |
74 | users.Add(user);
75 |
76 | return users.AsQueryable();
77 | }
78 |
79 | private User CreateRandomUser() =>
80 | CreateUserFiller().Create();
81 |
82 |
83 | private static Filler CreateUserFiller()
84 | {
85 | DateTimeOffset dates = GetRandomDate();
86 | var filler = new Filler();
87 |
88 | filler.Setup()
89 | .OnType().Use(dates);
90 |
91 | return filler;
92 | }
93 |
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Teams/TeamServiceTests.Exceptions.RetrieveAll.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using FluentAssertions;
8 | using Microsoft.Data.SqlClient;
9 | using Moq;
10 | using Tarteeb.Api.Models.Foundations.Teams.Exceptions;
11 | using Xunit;
12 |
13 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Teams
14 | {
15 | public partial class TeamServiceTests
16 | {
17 | [Fact]
18 | public void ShouldThrowCriticalDependencyExceptionOnRetrieveAllIfSqlErrorOccursAndLogIt()
19 | {
20 | // given
21 | SqlException sqlException = CreateSqlException();
22 |
23 | var failedTeamStorageException =
24 | new FailedTeamStorageException(sqlException);
25 |
26 | var expectedTeamDependencyException =
27 | new TeamDependencyException(failedTeamStorageException);
28 |
29 | this.storageBrokerMock.Setup(broker =>
30 | broker.SelectAllTeams()).Throws(sqlException);
31 |
32 | // when
33 | Action retrieveAllTeamsAction = () =>
34 | this.teamService.RetrieveAllTeams();
35 |
36 | TeamDependencyException actualTeamDependencyException =
37 | Assert.Throws(retrieveAllTeamsAction);
38 |
39 | // then
40 | actualTeamDependencyException.Should().BeEquivalentTo(expectedTeamDependencyException);
41 |
42 | this.storageBrokerMock.Verify(broker =>
43 | broker.SelectAllTeams(), Times.Once);
44 |
45 | this.loggingBrokerMock.Verify(broker =>
46 | broker.LogCritical(It.Is(SameExceptionAs(
47 | expectedTeamDependencyException))), Times.Once);
48 |
49 | this.storageBrokerMock.VerifyNoOtherCalls();
50 | this.loggingBrokerMock.VerifyNoOtherCalls();
51 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
52 | }
53 |
54 | [Fact]
55 | public void ShouldThrowServiceExceptionOnRetrieveAllWhenAllServiceErrorOccursAndLogIt()
56 | {
57 | // given
58 | string exceptionMessage = GetRandomString();
59 | var serviceException = new Exception(exceptionMessage);
60 |
61 | var failedTeamServiceException =
62 | new FailedTeamServiceException(serviceException);
63 |
64 | var expectedTeamServiceException =
65 | new TeamServiceException(failedTeamServiceException);
66 |
67 | this.storageBrokerMock.Setup(broker =>
68 | broker.SelectAllTeams()).Throws(serviceException);
69 |
70 | // when
71 | Action retrieveAllTeamAction = () =>
72 | this.teamService.RetrieveAllTeams();
73 |
74 | TeamServiceException actualTeamServiceException =
75 | Assert.Throws(retrieveAllTeamAction);
76 |
77 | // then
78 | actualTeamServiceException.Should().BeEquivalentTo(expectedTeamServiceException);
79 |
80 | this.storageBrokerMock.Verify(broker =>
81 | broker.SelectAllTeams(), Times.Once);
82 |
83 | this.loggingBrokerMock.Verify(broker =>
84 | broker.LogError(It.Is(SameExceptionAs(
85 | expectedTeamServiceException))), Times.Once);
86 |
87 | this.storageBrokerMock.VerifyNoOtherCalls();
88 | this.loggingBrokerMock.VerifyNoOtherCalls();
89 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Tickets/TicketServiceTests.Exceptions.RetrieveAll.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using FluentAssertions;
8 | using Microsoft.Data.SqlClient;
9 | using Moq;
10 | using Tarteeb.Api.Models.Foundations.Tickets.Exceptions;
11 | using Xunit;
12 |
13 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Tickets
14 | {
15 | public partial class TicketServiceTests
16 | {
17 | [Fact]
18 | public void ShouldThrowCriticalDependencyExceptionOnRetrieveAllWhenSqlExceptionOccursAndLogIt()
19 | {
20 | // given
21 | SqlException sqlException = CreateSqlException();
22 | var failedTicketServiceException = new FailedTicketServiceException(sqlException);
23 |
24 | var expectedTicketDependencyException =
25 | new TicketDependencyException(failedTicketServiceException);
26 |
27 | this.storageBrokerMock.Setup(broker =>
28 | broker.SelectAllTickets()).Throws(sqlException);
29 |
30 | // when
31 | Action retrieveAllTicketAction = () =>
32 | this.ticketService.RetrieveAllTickets();
33 |
34 | TicketDependencyException actualTicketDependencyException =
35 | Assert.Throws(retrieveAllTicketAction);
36 |
37 | // then
38 | actualTicketDependencyException.Should().BeEquivalentTo(expectedTicketDependencyException);
39 |
40 | this.storageBrokerMock.Verify(broker =>
41 | broker.SelectAllTickets(), Times.Once);
42 |
43 | this.loggingBrokerMock.Verify(broker =>
44 | broker.LogCritical(It.Is(SameExceptionAs(expectedTicketDependencyException))),
45 | Times.Once);
46 |
47 | this.storageBrokerMock.VerifyNoOtherCalls();
48 | this.loggingBrokerMock.VerifyNoOtherCalls();
49 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
50 | }
51 |
52 | [Fact]
53 | public void ShouldThrowServiceExceptionOnRetrieveAllWhenAllServiceErrorOccursAndLogIt()
54 | {
55 | // given
56 | string exceptionMessage = GetRandomMessage();
57 | var serviceException = new Exception(exceptionMessage);
58 | var failedTicketServiceException = new FailedTicketServiceException(serviceException);
59 |
60 | var expectedTicketServiceException =
61 | new TicketServiceException(failedTicketServiceException);
62 |
63 | this.storageBrokerMock.Setup(broker =>
64 | broker.SelectAllTickets()).Throws(serviceException);
65 |
66 | // when
67 | Action retrieveAllTicketAction = () =>
68 | this.ticketService.RetrieveAllTickets();
69 |
70 | TicketServiceException actualTicketServiceException =
71 | Assert.Throws(retrieveAllTicketAction);
72 |
73 | // then
74 | actualTicketServiceException.Should().BeEquivalentTo(expectedTicketServiceException);
75 |
76 | this.storageBrokerMock.Verify(broker =>
77 | broker.SelectAllTickets(), Times.Once);
78 |
79 | this.loggingBrokerMock.Verify(broker =>
80 | broker.LogError(It.Is(SameExceptionAs(
81 | expectedTicketServiceException))), Times.Once);
82 |
83 | this.storageBrokerMock.VerifyNoOtherCalls();
84 | this.loggingBrokerMock.VerifyNoOtherCalls();
85 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/Tarteeb.Api.Tests.Unit/Services/Foundations/Users/UserServiceTests.Validations.RetrieveById.cs:
--------------------------------------------------------------------------------
1 | //=================================
2 | // Copyright (c) Coalition of Good-Hearted Engineers
3 | // Free to use to bring order in your workplace
4 | //=================================
5 |
6 | using System;
7 | using System.Threading.Tasks;
8 | using FluentAssertions;
9 | using Moq;
10 | using Tarteeb.Api.Models.Foundations.Users;
11 | using Tarteeb.Api.Models.Foundations.Users.Exceptions;
12 | using Xunit;
13 |
14 | namespace Tarteeb.Api.Tests.Unit.Services.Foundations.Users
15 | {
16 | public partial class UserServiceTests
17 | {
18 | [Fact]
19 | public async Task ShouldThrowVlidationExceptionOnRetrieveByIdIfIdIsInvalidAndLogItAsync()
20 | {
21 | // given
22 | var invlidUserId = Guid.Empty;
23 | var invalidUserException = new InvalidUserException();
24 |
25 | invalidUserException.AddData(
26 | key: nameof(User.Id),
27 | values: "Id is required");
28 |
29 | var expectedUserValidationException = new UserValidationException(invalidUserException);
30 |
31 | // when
32 | ValueTask retrieveUserByIdTask =
33 | this.userService.RetrieveUserByIdAsync(invlidUserId);
34 |
35 | UserValidationException actualUserValidationException =
36 | await Assert.ThrowsAsync(retrieveUserByIdTask.AsTask);
37 |
38 | // then
39 | actualUserValidationException.Should().BeEquivalentTo(expectedUserValidationException);
40 |
41 | this.loggingBrokerMock.Verify(broker =>
42 | broker.LogError(It.Is(SameExceptionAs(
43 | expectedUserValidationException))), Times.Once);
44 |
45 | this.storageBrokerMock.Verify(broker =>
46 | broker.SelectUserByIdAsync(It.IsAny()), Times.Never);
47 |
48 | this.loggingBrokerMock.VerifyNoOtherCalls();
49 | this.storageBrokerMock.VerifyNoOtherCalls();
50 | this.dateTimeBrokerMock.VerifyNoOtherCalls();
51 | }
52 |
53 | [Fact]
54 | public async Task ShouldThrowValidationExceptionOnRetrieveByIdIfUserIsNotFoundAndLogItAsync()
55 | {
56 | // given
57 | Guid someUserId = Guid.NewGuid();
58 | User noUser = null;
59 | var notFoundUserValidationException = new NotFoundUserException(someUserId);
60 |
61 | var expectedValidationException =
62 | new UserValidationException(notFoundUserValidationException);
63 |
64 | this.storageBrokerMock.Setup(broker =>
65 | broker.SelectUserByIdAsync(It.IsAny())).ReturnsAsync(noUser);
66 |
67 | // when
68 | ValueTask