├── .vscode
├── extensions.json
├── settings.json
└── tasks.json
├── ShareBook
├── ShareBook.Test.Integration
│ ├── GlobalUsings.cs
│ ├── Setup
│ │ ├── ShareBookTestsFixture.cs
│ │ └── ShareBookWebAppFactory.cs
│ ├── ShareBook.Test.Integration.csproj
│ └── Tests
│ │ ├── BookTests
│ │ └── BookTests.cs
│ │ └── CategoryTests
│ │ └── CategoryTests.cs
├── ShareBook.Api
│ ├── wwwroot
│ │ └── Images
│ │ │ └── Books
│ │ │ ├── os-sete.jpg
│ │ │ ├── a-cabana.jpg
│ │ │ ├── a-passagem.jpg
│ │ │ ├── fantasia-1.jpg
│ │ │ ├── o-cortico.jpg
│ │ │ ├── star-wars.jpg
│ │ │ ├── the-hobbit.jpg
│ │ │ ├── guerra-civil.jpg
│ │ │ ├── homem-aranha.jpg
│ │ │ ├── nunca-jamais.jpg
│ │ │ ├── as-duas-torres.jpg
│ │ │ ├── os-vingadores.jpg
│ │ │ ├── a-furia-dos-reis.jpg
│ │ │ ├── a-hora-do-vampiro.jpg
│ │ │ ├── anjos-e-demonios.jpg
│ │ │ ├── antologia-poetica.jpg
│ │ │ ├── direito-e-justiça.jpg
│ │ │ ├── o-retorno-do-rei.png
│ │ │ ├── se-venden-gorras.jpg
│ │ │ ├── senhor-dos-aneis.jpg
│ │ │ ├── the-book-of-jonah.jpg
│ │ │ ├── a-irmandade-do-anel.jpg
│ │ │ ├── a-maldicao-do-cigano.jpg
│ │ │ ├── cronicas-gelo-e-fogo.jpg
│ │ │ ├── direito-penal-rideel.jpg
│ │ │ ├── num-vento-diferente.jpg
│ │ │ ├── o-festim-dos-corvos.jpg
│ │ │ ├── o-pequeno-principe.jpg
│ │ │ ├── as-provacoes-de-apolo.jpg
│ │ │ ├── o-segredo-das-sombras.jpg
│ │ │ ├── orgulho-e-preconceito.jpg
│ │ │ ├── programando-o-android.jpg
│ │ │ ├── introducao-a-programacao.jpg
│ │ │ ├── novelas-nada-exemplares.jpg
│ │ │ ├── volta-ao-mundo-em-80-dias.jpg
│ │ │ ├── a-menina-que-roubava-livros.jpg
│ │ │ ├── c-sharp-programao-em-camada.jpg
│ │ │ ├── programacao-de-jogo-android.jpg
│ │ │ ├── percy-jackson-e-os-olimpianos.jpg
│ │ │ ├── teoria-discursiva-do-direito.jpg
│ │ │ ├── 100-segredos-das-pessoas-felizes.jpg
│ │ │ ├── programacao-de-redes-com-python.jpg
│ │ │ ├── the-hobbit-there-and-back-again.jpg
│ │ │ ├── harry-potter-prisioneiro-de-askaban.jpg
│ │ │ └── harry-potter-e-as-reliquias-da-morte.jpg
│ ├── ViewModels
│ │ ├── ParentAprovalVM.cs
│ │ ├── TrackinNumberBookVM.cs
│ │ ├── RequestBookVM.cs
│ │ ├── DonateBookUserVM.cs
│ │ ├── ChangePasswordUserVM.cs
│ │ ├── ForgotMyPasswordVM.cs
│ │ ├── AddFaciclitatorNotesVM.cs
│ │ ├── ChangeUserPasswordByEmailAndHashCodeVM.cs
│ │ ├── AccessHistoryVM.cs
│ │ ├── BaseViewModel.cs
│ │ ├── ApproveBookVM.cs
│ │ ├── LoginUserVM.cs
│ │ ├── CancelBookDonationVM.cs
│ │ ├── EmailTestVM.cs
│ │ ├── ContactUsVM.cs
│ │ ├── NotificationOnesignalVM.cs
│ │ ├── UpdateUserVM.cs
│ │ ├── RequestersListVM.cs
│ │ ├── CustomValidators
│ │ │ └── StringLengthRangeOptionalAttribute.cs
│ │ ├── CreateBookVM.cs
│ │ ├── MyBooksRequestsVM.cs
│ │ ├── UpdateBookVM.cs
│ │ └── UserVM.cs
│ ├── .config
│ │ └── dotnet-tools.json
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Filters
│ │ ├── GetClaimsFilter.cs
│ │ ├── ValidateModelStateFilterAttribute.cs
│ │ ├── AuthorizationFilter.cs
│ │ └── ThrottleFilter.cs
│ ├── Program.cs
│ ├── Controllers
│ │ ├── CategoryController.cs
│ │ ├── ContactUsController.cs
│ │ ├── Generic
│ │ │ ├── BaseDeleteController.cs
│ │ │ └── BaseController.cs
│ │ └── MeetupController.cs
│ ├── web.config
│ ├── Services
│ │ └── RollbarConfigurator.cs
│ ├── appsettings.json
│ └── AutoMapper
│ │ └── ViewModelToDomainMappingProfile.cs
├── ShareBook.Domain
│ ├── Enums
│ │ ├── Profile.cs
│ │ ├── TypeSegments.cs
│ │ ├── JobResult.cs
│ │ ├── JobInterval.cs
│ │ ├── VisitorProfile.cs
│ │ ├── BookType.cs
│ │ ├── DonationStatus.cs
│ │ ├── FreightOption.cs
│ │ └── BookStatus.cs
│ ├── Common
│ │ ├── IIdProperty.cs
│ │ ├── BaseEntity.cs
│ │ ├── JobExecutorResult.cs
│ │ ├── PagedList.cs
│ │ └── Result.cs
│ ├── Category.cs
│ ├── DTOs
│ │ ├── BookStatsDTO.cs
│ │ ├── BookCancelationDTO.cs
│ │ ├── UserAnonymizeDTO.cs
│ │ ├── UserStatsDTO.cs
│ │ └── RegisterUserDTO.cs
│ ├── Exceptions
│ │ ├── AwsSqsDisabledException.cs
│ │ ├── MeetupDisabledException.cs
│ │ └── SharebookException.cs
│ ├── ContactUs.cs
│ ├── LogEntry.cs
│ ├── MeetupParticipant.cs
│ ├── Validators
│ │ ├── CategoryValidator.cs
│ │ ├── AccessHistoryValidator.cs
│ │ ├── MeetupValidator.cs
│ │ ├── BookUserValidator.cs
│ │ └── ContactUsValidator.cs
│ ├── ShareBook.Domain.csproj
│ ├── NotificationOnesignal.cs
│ ├── Address.cs
│ ├── Meetup.cs
│ ├── JobHistory.cs
│ ├── BookUser.cs
│ ├── AccessHistory.cs
│ └── MailBounce.cs
├── ShareBook.Service
│ ├── Meetup
│ │ ├── MeetupSettings.cs
│ │ ├── IMeetupService.cs
│ │ └── Dto
│ │ │ ├── YoutubeDTOError.cs
│ │ │ ├── YoutubeDetailDTO.cs
│ │ │ ├── SymplaDTO.cs
│ │ │ ├── MeetupParticipantDTO.cs
│ │ │ └── YoutubeDTO.cs
│ ├── Category
│ │ ├── ICategoryService.cs
│ │ └── CategoryService.cs
│ ├── Server
│ │ └── ServerSettings.cs
│ ├── Email
│ │ ├── IEmailTemplate.cs
│ │ ├── EmailSettings.cs
│ │ ├── Templates
│ │ │ ├── ForgotPasswordTemplate.html
│ │ │ ├── BookCanceledTemplate.html
│ │ │ ├── AnonymizeNotifyAdms.html
│ │ │ ├── ParentAprovedNotifyUser.html
│ │ │ ├── WaitingApprovalTemplate.html
│ │ │ ├── BookDonatedTemplate.html
│ │ │ ├── BookApprovedTemplate.html
│ │ │ ├── BookNoticeDonorTemplate.html
│ │ │ ├── RequestParentAproval.html
│ │ │ ├── BookReceivedTemplate.html
│ │ │ ├── BookNoticeInterestedTemplate.html
│ │ │ ├── BookCanceledNoticeUsersTemplate.html
│ │ │ ├── LateDonationNotification.html
│ │ │ ├── BookNoticeDeclinedUsersTemplate.html
│ │ │ ├── BookTrackingNumberNoticeWinnerTemplate.html
│ │ │ ├── NewBookInsertedTemplate.html
│ │ │ ├── ChooseDateReminderTemplate.html
│ │ │ └── ChooseDateRenewTemplate.html
│ │ ├── IEmailService.cs
│ │ └── EmailTemplate.cs
│ ├── Recaptcha
│ │ ├── IRecaptchaService.cs
│ │ └── RecaptchaService.cs
│ ├── Lgpd
│ │ └── ILgpdService.cs
│ ├── ContactUs
│ │ ├── IContactUsEmailService.cs
│ │ ├── IContactUsService.cs
│ │ ├── ContactUsService.cs
│ │ └── ContactUsEmailService.cs
│ ├── Upload
│ │ ├── ImageSettings.cs
│ │ ├── IUploadService.cs
│ │ └── UploadService.cs
│ ├── AccessHistory
│ │ ├── IAccessHistoryService.cs
│ │ └── AccessHistoryService.cs
│ ├── AwsSqs
│ │ ├── Dto
│ │ │ ├── SharebookMessage.cs
│ │ │ ├── NewBookBody.cs
│ │ │ └── MailSenderBody.cs
│ │ ├── MailSenderLowPriorityQueue.cs
│ │ └── MailSenderHighPriorityQueue .cs
│ ├── AWSSQS
│ │ ├── IAwsSqsQueue.cs
│ │ ├── NewBookQueue.cs
│ │ └── AWSSQSSettings.cs
│ ├── Book
│ │ ├── IBooksEmailService.cs
│ │ └── IBookService.cs
│ ├── Muambator
│ │ ├── MuambatorDTO.cs
│ │ ├── IMuambatorService.cs
│ │ └── MuambatorConfigurator.cs
│ ├── PushNotification
│ │ ├── PushNotificationSettings.cs
│ │ └── IPushNotificationService.cs
│ ├── User
│ │ ├── IUserEmailService.cs
│ │ └── IUserService.cs
│ ├── Authorization
│ │ └── Permission.cs
│ └── BookUser
│ │ ├── IBookUsersEmailService.cs
│ │ └── IBookUserService.cs
├── ShareBook.Repository
│ ├── Repository
│ │ ├── Book
│ │ │ ├── IBookRepository.cs
│ │ │ └── BookRepository.cs
│ │ ├── Meetup
│ │ │ ├── IMeetupRepository.cs
│ │ │ ├── IMeetupParticipantRepository.cs
│ │ │ ├── MeetupParticipantRepository.cs
│ │ │ └── MeetupRepository.cs
│ │ ├── Job
│ │ │ ├── IJobHistoryRepository.cs
│ │ │ └── JobHistoryRepository.cs
│ │ ├── BookUser
│ │ │ ├── IBookUserRepository.cs
│ │ │ └── BookUserRepository.cs
│ │ ├── Category
│ │ │ ├── ICategoryRepository.cs
│ │ │ └── CategoryRepository.cs
│ │ ├── User
│ │ │ ├── IUserRepository.cs
│ │ │ └── UserRepository.cs
│ │ ├── AccessHistory
│ │ │ ├── IAccessHistoryRepository.cs
│ │ │ └── AccessHistoryRepository.cs
│ │ └── IncludeList.cs
│ ├── UoW
│ │ ├── IUnitOfWork.cs
│ │ └── UnitOfWork.cs
│ ├── Mapping
│ │ ├── MailBounceMap.cs
│ │ ├── CategoryMap.cs
│ │ ├── AccessHistoryMap.cs
│ │ ├── JobHistoryMap.cs
│ │ ├── LogEntryMap.cs
│ │ ├── BookUserMap.cs
│ │ ├── AddressMap.cs
│ │ ├── BookMap.cs
│ │ └── UserMap.cs
│ ├── ShareBook.Infra.Data.csproj
│ ├── ApplicationDbContextFactory.cs
│ ├── UtcContext.cs
│ └── ApplicationDbContext.cs
├── Sharebook.Jobs
│ ├── Executor
│ │ └── IJobExecutor.cs
│ ├── Jobs
│ │ ├── IJob.cs
│ │ ├── 6 - MailSupressListUpdate.cs
│ │ └── 4 - MeetupSearch.cs
│ └── Sharebook.Jobs.csproj
├── ShareBook.Infra.CrossCutting.Identity
│ ├── TokenConfigurations.cs
│ ├── Interfaces
│ │ └── IApplicationSignInManager.cs
│ ├── ShareBook.Infra.CrossCutting.Identity.csproj
│ ├── SigningConfigurations.cs
│ └── ApplicationSignInManager.cs
├── ShareBook.Helper
│ ├── Crypto
│ │ ├── Salt.cs
│ │ └── Hash.cs
│ ├── ShareBook.Helper.csproj
│ ├── Extensions
│ │ ├── EnumeratorExtension.cs
│ │ ├── AssemblyExtension.cs
│ │ └── StringExtension.cs
│ ├── Mapper
│ │ └── Mapper.cs
│ ├── DateTime
│ │ └── DateTimeHelper.cs
│ ├── ClientVersionValidation
│ │ └── ClientVersionValidation.cs
│ └── Image
│ │ └── ImageHelper.cs
└── ShareBook.Test.Unit
│ ├── Mocks
│ ├── BookUserMock.cs
│ └── BookMock.cs
│ ├── Services
│ ├── RecaptchaServiceTests.cs
│ └── ContactUsEmailServiceTests.cs
│ ├── ShareBook.Test.Unit.csproj
│ ├── Validators
│ ├── ContactUsValidatorTests.cs
│ └── BookValidatorTests.cs
│ └── Jobs
│ └── 4 - MeetupSearchTests.cs
├── .github
└── workflows
│ ├── dockerfile-validation.yml
│ ├── dotnet-build-validation.yml
│ └── postman-collection.yml
├── .claude
└── settings.local.json
├── devops
├── .dockerignore
└── Dockerfile
└── CLAUDE.md
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "formulahendry.dotnet-test-explorer"
4 | ]
5 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Integration/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using FluentAssertions;
2 | global using ShareBook.Test.Integration.Setup;
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dotnet-test-explorer.testProjectPath": "ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj"
3 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/os-sete.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/os-sete.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-cabana.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-cabana.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-passagem.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-passagem.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/fantasia-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/fantasia-1.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-cortico.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-cortico.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/star-wars.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/star-wars.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/the-hobbit.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/the-hobbit.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/guerra-civil.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/guerra-civil.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/homem-aranha.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/homem-aranha.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/nunca-jamais.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/nunca-jamais.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/as-duas-torres.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/as-duas-torres.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/os-vingadores.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/os-vingadores.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-furia-dos-reis.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-furia-dos-reis.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-hora-do-vampiro.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-hora-do-vampiro.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/anjos-e-demonios.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/anjos-e-demonios.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/antologia-poetica.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/antologia-poetica.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/direito-e-justiça.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/direito-e-justiça.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-retorno-do-rei.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-retorno-do-rei.png
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/se-venden-gorras.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/se-venden-gorras.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/senhor-dos-aneis.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/senhor-dos-aneis.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/the-book-of-jonah.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/the-book-of-jonah.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-irmandade-do-anel.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-irmandade-do-anel.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-maldicao-do-cigano.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-maldicao-do-cigano.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/cronicas-gelo-e-fogo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/cronicas-gelo-e-fogo.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/direito-penal-rideel.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/direito-penal-rideel.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/num-vento-diferente.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/num-vento-diferente.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-festim-dos-corvos.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-festim-dos-corvos.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-pequeno-principe.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-pequeno-principe.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/Profile.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace ShareBook.Domain.Enums
3 | {
4 | public enum Profile
5 | {
6 | Administrator,
7 | User
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/as-provacoes-de-apolo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/as-provacoes-de-apolo.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-segredo-das-sombras.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/o-segredo-das-sombras.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/orgulho-e-preconceito.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/orgulho-e-preconceito.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/programando-o-android.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/programando-o-android.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/introducao-a-programacao.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/introducao-a-programacao.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/novelas-nada-exemplares.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/novelas-nada-exemplares.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/volta-ao-mundo-em-80-dias.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/volta-ao-mundo-em-80-dias.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-menina-que-roubava-livros.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/a-menina-que-roubava-livros.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/c-sharp-programao-em-camada.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/c-sharp-programao-em-camada.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/programacao-de-jogo-android.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/programacao-de-jogo-android.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/ParentAprovalVM.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Api.ViewModels
2 | {
3 | public class ParentAprovalVM
4 | {
5 | public string ParentHashCodeAproval { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/percy-jackson-e-os-olimpianos.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/percy-jackson-e-os-olimpianos.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/teoria-discursiva-do-direito.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/teoria-discursiva-do-direito.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Common/IIdProperty.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Domain.Common
4 | {
5 | public interface IIdProperty
6 | {
7 | Guid Id { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/100-segredos-das-pessoas-felizes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/100-segredos-das-pessoas-felizes.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/programacao-de-redes-com-python.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/programacao-de-redes-com-python.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/the-hobbit-there-and-back-again.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/the-hobbit-there-and-back-again.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Meetup/MeetupSettings.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Service;
2 |
3 | public class MeetupSettings
4 | {
5 | public string YoutubeToken { get; set; }
6 | public bool IsActive { get; set; }
7 | }
8 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/harry-potter-prisioneiro-de-askaban.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/harry-potter-prisioneiro-de-askaban.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Book/IBookRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public interface IBookRepository : IRepositoryGeneric
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/wwwroot/Images/Books/harry-potter-e-as-reliquias-da-morte.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SharebookBR/sharebook-backend/HEAD/ShareBook/ShareBook.Api/wwwroot/Images/Books/harry-potter-e-as-reliquias-da-morte.jpg
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/TrackinNumberBookVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace ShareBook.Api.ViewModels
3 | {
4 | public class TrackinNumberBookVM
5 | {
6 | public string TrackingNumber { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Category.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 |
3 | namespace ShareBook.Domain
4 | {
5 | public class Category : BaseEntity
6 | {
7 | public string Name { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Meetup/IMeetupRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public interface IMeetupRepository : IRepositoryGeneric
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Job/IJobHistoryRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public interface IJobHistoryRepository : IRepositoryGeneric
6 | {
7 | }
8 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/TypeSegments.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Domain.Enums
2 | {
3 | public enum TypeSegments
4 | {
5 | Inactive = 0,
6 | Engaged = 1,
7 | Active = 2,
8 | All = 3
9 | }
10 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/BookUser/IBookUserRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public interface IBookUserRepository : IRepositoryGeneric
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Category/ICategoryRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public interface ICategoryRepository : IRepositoryGeneric
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ShareBook/Sharebook.Jobs/Executor/IJobExecutor.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using System.Threading.Tasks;
3 |
4 | namespace Sharebook.Jobs;
5 |
6 | public interface IJobExecutor
7 | {
8 | Task ExecuteAsync();
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Category/ICategoryService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Service.Generic;
2 | using ShareBook.Domain;
3 |
4 | namespace ShareBook.Service
5 | {
6 | public interface ICategoryService : IBaseService
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Server/ServerSettings.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Service.Server
2 | {
3 | public class ServerSettings
4 | {
5 | public string DefaultUrl { get; set; }
6 | public string JobExecutorToken { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "dotnet-ef": {
6 | "version": "8.0.6",
7 | "commands": [
8 | "dotnet-ef"
9 | ]
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/JobResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace ShareBook.Domain.Enums
3 | {
4 | public enum JobResult
5 | {
6 | Success,
7 | Error,
8 | AwsSqsDisabled,
9 | MeetupDisabled,
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Meetup/IMeetupParticipantRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public interface IMeetupParticipantRepository : IRepositoryGeneric
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/RequestBookVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace ShareBook.Api.ViewModels
3 | {
4 | public class RequestBookVM
5 | {
6 | public Guid BookId { get; set; }
7 |
8 | public string Reason { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/DonateBookUserVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class DonateBookUserVM
6 | {
7 | public Guid UserId { get; set; }
8 | public string Note { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/JobInterval.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace ShareBook.Domain.Enums
3 | {
4 | public enum Interval
5 | {
6 | Weekly,
7 | Dayly,
8 | Hourly,
9 | Each30Minutes,
10 | Each5Minutes,
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/ChangePasswordUserVM.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Api.ViewModels
2 | {
3 | public class ChangePasswordUserVM
4 | {
5 | public string NewPassword { get; set; }
6 |
7 | public string OldPassword { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/IEmailTemplate.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace ShareBook.Service
4 | {
5 | public interface IEmailTemplate
6 | {
7 | Task GenerateHtmlFromTemplateAsync(string template, object model);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Recaptcha/IRecaptchaService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 |
3 | namespace ShareBook.Service.Recaptcha
4 | {
5 | public interface IRecaptchaService
6 | {
7 | Result SimpleValidationRecaptcha(string recaptcha);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/ForgotMyPasswordVM.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class ForgotMyPasswordVM
6 | {
7 | [Required]
8 | public string Email { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Lgpd/ILgpdService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.DTOs;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Service.Lgpd
5 | {
6 | public interface ILgpdService
7 | {
8 | public Task AnonymizeAsync(UserAnonymizeDTO dto);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/AddFaciclitatorNotesVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class AddFacilitatorNotesVM
6 | {
7 | public Guid BookId { get; set; }
8 |
9 | public string FacilitatorNotes { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/DTOs/BookStatsDTO.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Domain.DTOs
2 | {
3 | public class BookStatsDTO
4 | {
5 | public int TotalWaitingApproval { get; set; }
6 | public int TotalLate { get; set; }
7 | public int TotalOk { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/ContactUs/IContactUsEmailService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Service
5 | {
6 | public interface IContactUsEmailService
7 | {
8 | Task SendEmailContactUsAsync(ContactUs contactUs);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/ChangeUserPasswordByEmailAndHashCodeVM.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Api.ViewModels
2 | {
3 | public class ChangeUserPasswordByHashCodeVM
4 | {
5 | public string HashCodePassword { get; set; }
6 |
7 | public string NewPassword { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/User/IUserRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Repository
5 | {
6 | public interface IUserRepository : IRepositoryGeneric
7 | {
8 | Task UpdatePasswordAsync(User user);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/AccessHistoryVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Api.ViewModels {
4 | public class AccessHistoryVM : BaseViewModel {
5 | public DateTime VisitingDay { get; set; }
6 | public string VisitorName { get; set; }
7 | public string Profile { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Upload/ImageSettings.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Service.Upload
2 | {
3 | public class ImageSettings
4 | {
5 | public string BaseDirectory { get; set; }
6 |
7 | public string ImagePath { get; set; }
8 |
9 | public string EBookPdfPath { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Common/BaseEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Domain.Common
4 | {
5 | public abstract class BaseEntity : IIdProperty
6 | {
7 | public Guid Id { get; set; } = Guid.NewGuid();
8 |
9 | public DateTime? CreationDate { get; set; } = DateTime.Now;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/BaseViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ShareBook.Domain.Common;
3 | using System;
4 |
5 | namespace ShareBook.Api.ViewModels
6 | {
7 | public abstract class BaseViewModel : IIdProperty
8 | {
9 | [JsonIgnore]
10 | public Guid Id { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/DTOs/BookCancelationDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Domain.DTOs
4 | {
5 | public class BookCancelationDTO
6 | {
7 | public Book Book { get; set; }
8 | public string CanceledBy { get; set; }
9 | public string Reason { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/DTOs/UserAnonymizeDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Domain.DTOs
4 | {
5 | public class UserAnonymizeDTO
6 | {
7 | public Guid UserId { get; set; }
8 | public string Password { get; set; }
9 | public string Reason { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/ApproveBookVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class ApproveBookVM
6 | {
7 | ///
8 | /// The date that the winner will be choosed
9 | ///
10 | public DateTime? ChooseDate { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/UoW/IUnitOfWork.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Repository.UoW
5 | {
6 | public interface IUnitOfWork : IAsyncDisposable
7 | {
8 | Task BeginTransactionAsync();
9 | Task CommitAsync();
10 | Task RollbackAsync();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Common/JobExecutorResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ShareBook.Domain.Common
6 | {
7 | public class JobExecutorResult
8 | {
9 | public bool Success { get; set; }
10 | public IList Messages { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Category/CategoryRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public class CategoryRepository : RepositoryGeneric, ICategoryRepository
6 | {
7 | public CategoryRepository(ApplicationDbContext context) : base(context) { }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/LoginUserVM.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class LoginUserVM
6 | {
7 | [Required]
8 | public string Email { get; set; }
9 |
10 | [Required]
11 | public string Password { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Infra.CrossCutting.Identity/TokenConfigurations.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | namespace ShareBook.Infra.CrossCutting.Identity
4 |
5 | {
6 | public class TokenConfigurations
7 | {
8 | public string Audience { get; set; }
9 | public string Issuer { get; set; }
10 | public int Seconds { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AccessHistory/IAccessHistoryService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Enums;
4 |
5 | namespace ShareBook.Service {
6 | public interface IAccessHistoryService
7 | {
8 | Task InsertVisitorAsync(User user, User visitor, VisitorProfile profile);
9 | }
10 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Exceptions/AwsSqsDisabledException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace ShareBook.Domain.Exceptions;
5 |
6 | [Serializable]
7 | public class AwsSqsDisabledException : Exception
8 | {
9 | public AwsSqsDisabledException(string message) : base(message)
10 | {
11 | }
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Exceptions/MeetupDisabledException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace ShareBook.Domain.Exceptions;
5 |
6 | [Serializable]
7 | public class MeetupDisabledException : Exception
8 | {
9 | public MeetupDisabledException(string message) : base(message)
10 | {
11 | }
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/VisitorProfile.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace ShareBook.Domain.Enums {
4 | public enum VisitorProfile {
5 | [Description("Doador")] Donor,
6 | [Description("Ganhador")] Winner,
7 | [Description("Indefinido")] Undefined,
8 | [Description("Facilitador")] Facilitator
9 | }
10 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/ContactUs/IContactUsService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Domain.Common;
3 | using System.Threading.Tasks;
4 |
5 | namespace ShareBook.Service
6 | {
7 | public interface IContactUsService
8 | {
9 | Task> SendContactUsAsync(ContactUs contactUs, string recaptchaReactive);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/CancelBookDonationVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class CancelBookDonationVM
6 | {
7 | public Guid Id { get; set; }
8 | public string Title { get; set; }
9 | public string Author { get; set; }
10 | public string Status { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/ContactUs.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 |
3 | namespace ShareBook.Domain
4 | {
5 | public class ContactUs : BaseEntity
6 | {
7 | public string Name { get; set; }
8 | public string Email { get; set; }
9 | public string Phone { get; set; }
10 | public string Message { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/BookUser/BookUserRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | namespace ShareBook.Repository
4 | {
5 | public class BookUserRepository : RepositoryGeneric, IBookUserRepository
6 | {
7 | public BookUserRepository(ApplicationDbContext context) : base(context)
8 | {
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/EmailTestVM.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class EmailTestVM
6 | {
7 | [Required]
8 | [EmailAddress]
9 | public string Email { get; set; }
10 |
11 | [Required]
12 | public string Name { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "ShareBook.Api": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "launchUrl": "swagger",
7 | "applicationUrl": "http://localhost:8000/",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | }
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Common/PagedList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ShareBook.Domain.Common
4 | {
5 | public class PagedList
6 | {
7 | public int Page { get; set; }
8 | public int ItemsPerPage { get; set; }
9 | public int TotalItems { get; set; }
10 | public IList Items { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AwsSqs/Dto/SharebookMessage.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper.Configuration.Conventions;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace ShareBook.Service.AwsSqs.Dto
7 | {
8 | public class SharebookMessage{
9 | public string ReceiptHandle { get; set; }
10 | public T Body { get; set; }
11 | }
12 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/ContactUsVM.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Api.ViewModels
2 | {
3 | public class ContactUsVM
4 | {
5 | public string Name { get; set; }
6 | public string Email { get; set; }
7 | public string Phone { get; set; }
8 | public string Message { get; set; }
9 | public string RecaptchaReactive { get; set; }
10 | }
11 | }
--------------------------------------------------------------------------------
/.github/workflows/dockerfile-validation.yml:
--------------------------------------------------------------------------------
1 | name: Dockerfile validation
2 |
3 | on:
4 | pull_request:
5 | branches: [ develop, master ]
6 |
7 | jobs:
8 |
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Build the Docker image
16 | run: |
17 | docker build -t sharebook-api -f devops/Dockerfile .
18 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/BookType.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Text.Json.Serialization;
3 |
4 | namespace ShareBook.Domain.Enums
5 | {
6 | [JsonConverter(typeof(JsonStringEnumConverter))]
7 | public enum BookType
8 | {
9 | [Description("Impresso")]
10 | Printed,
11 | [Description("Eletrônico")]
12 | Eletronic
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AWSSQS/IAwsSqsQueue.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Service.AwsSqs.Dto;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Service.AwsSqs
5 | {
6 | public interface IAwsSqsQueue
7 | {
8 | Task SendMessageAsync(T message);
9 |
10 | Task> GetMessageAsync();
11 |
12 | Task DeleteMessageAsync(string receiptHandle);
13 | }
14 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Book/IBooksEmailService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using ShareBook.Domain;
3 |
4 | namespace ShareBook.Service
5 | {
6 | public interface IBooksEmailService
7 | {
8 | Task SendEmailNewBookInsertedAsync(Book book);
9 |
10 | Task SendEmailBookApprovedAsync(Book book);
11 |
12 | Task SendEmailBookReceivedAsync(Book book);
13 | }
14 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Muambator/MuambatorDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ShareBook.Service.Muambator
6 | {
7 | public class MuambatorDTO
8 | {
9 | public string Status { get; set; }
10 |
11 | public string Message { get; set; }
12 |
13 | public IList Results { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Job/JobHistoryRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Repository
5 | {
6 | public class JobHistoryRepository : RepositoryGeneric, IJobHistoryRepository
7 | {
8 | public JobHistoryRepository(ApplicationDbContext context) : base(context)
9 | {
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/PushNotification/PushNotificationSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ShareBook.Service.Notification
6 | {
7 | public class PushNotificationSettings
8 | {
9 | public bool IsActive { get; set; }
10 | public string AppId { get; set; }
11 | public string ApiKey { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AwsSqs/Dto/NewBookBody.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper.Configuration.Conventions;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace ShareBook.Service.AwsSqs.Dto
7 | {
8 | public class NewBookBody{
9 |
10 | public Guid BookId { get; set; }
11 | public string BookTitle { get; set; }
12 | public Guid CategoryId { get; set; }
13 | }
14 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Muambator/IMuambatorService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using ShareBook.Domain;
3 |
4 | namespace ShareBook.Service.Muambator
5 | {
6 | public interface IMuambatorService
7 | {
8 | Task AddPackageToTrackerAsync(Book book, User winner, string packageNumber);
9 |
10 | Task RemovePackageToTrackerAsync(string packageNumber);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/AccessHistory/IAccessHistoryRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 |
7 | namespace ShareBook.Repository {
8 | public interface IAccessHistoryRepository : IRepositoryGeneric {
9 | Task> GetWhoAccessedMyProfileAsync(Guid userId);
10 | }
11 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Meetup/IMeetupService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Service.Generic;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | namespace ShareBook.Service
7 | {
8 | public interface IMeetupService : IBaseService
9 | {
10 | public Task> FetchMeetupsAsync();
11 | Task> SearchAsync(string criteria);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/IncludeList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq.Expressions;
4 |
5 | namespace ShareBook.Repository.Repository
6 | {
7 | public class IncludeList : List>>
8 | {
9 | public IncludeList(params Expression>[] expressions)
10 | {
11 | AddRange(expressions);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Infra.CrossCutting.Identity/Interfaces/IApplicationSignInManager.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Infra.CrossCutting.Identity;
3 |
4 | namespace ShareBook.Infra.CrossCutting.Identity.Interfaces
5 | {
6 | public interface IApplicationSignInManager
7 | {
8 | object GenerateTokenAndSetIdentity(User user, SigningConfigurations signingConfigurations, TokenConfigurations tokenConfigurations);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Upload/IUploadService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace ShareBook.Service.Upload
4 | {
5 | public interface IUploadService
6 | {
7 | Task UploadImageAsync(byte[] imageBytes, string imageName, string lastDirectory);
8 | Task UploadPdfAsync(byte[] imageBytes, string imageName, string lastDirectory);
9 | string GetImageUrl(string imageName, string lastDirectory);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.claude/settings.local.json:
--------------------------------------------------------------------------------
1 | {
2 | "permissions": {
3 | "allow": [
4 | "WebFetch(domain:github.com)",
5 | "Read(//c/REPOS/_PEGASUS/pegasus-core-api/**)",
6 | "Bash(dotnet build)",
7 | "Bash(dotnet run:*)",
8 | "Bash(dotnet build:*)",
9 | "Bash(dir:*)",
10 | "Bash(findstr:*)",
11 | "Read(//c/Users/brnra019/Documents/Lightshot/**)",
12 | "Bash(git rm:*)"
13 | ],
14 | "deny": [],
15 | "ask": []
16 | }
17 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/EmailSettings.cs:
--------------------------------------------------------------------------------
1 | namespace ShareBook.Service
2 | {
3 | public class EmailSettings
4 | {
5 | public string HostName { get; set; }
6 | public string Username { get; set; }
7 | public string Password { get; set; }
8 | public int Port { get; set; }
9 | public bool UseSSL { get; set; }
10 | public int ImapPort { get; set; }
11 | public string BounceFolder { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Filters/GetClaimsFilter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Filters;
2 | using System.Threading;
3 |
4 | namespace ShareBook.Api.Filters
5 | {
6 | public class GetClaimsFilterAttribute : ActionFilterAttribute
7 | {
8 | public override void OnActionExecuting(ActionExecutingContext context)
9 | {
10 | Thread.CurrentPrincipal = context.HttpContext.User;
11 | base.OnActionExecuting(context);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Infra.CrossCutting.Identity/ShareBook.Infra.CrossCutting.Identity.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/MailBounceMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class MailBounceMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 | entityBuilder.HasIndex("Email");
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/DTOs/UserStatsDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Domain.DTOs
4 | {
5 | public class UserStatsDTO
6 | {
7 | public DateTime? CreationDate { get; set; }
8 | public int TotalLate { get; set; }
9 | public int TotalOk { get; set; }
10 | public int TotalCanceled { get; set; }
11 | public int TotalWaitingApproval { get; set; }
12 | public int TotalAvailable { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/LogEntry.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using System;
3 |
4 | namespace ShareBook.Domain
5 | {
6 | public class LogEntry : BaseEntity
7 | {
8 | public Guid? UserId { get; set; }
9 | public string EntityName { get; set; }
10 | public Guid EntityId { get; set; }
11 | public string Operation { get; set; }
12 | public DateTime LogDateTime { get; set; }
13 | public string ValuesChanges { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AwsSqs/MailSenderLowPriorityQueue.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using ShareBook.Service.AwsSqs.Dto;
3 |
4 | namespace ShareBook.Service.AwsSqs;
5 |
6 | public class MailSenderLowPriorityQueue : GenericQueue
7 | {
8 | public MailSenderLowPriorityQueue(IOptions awsSqsSettings) : base(awsSqsSettings)
9 | {
10 | _queueUrl = $"{_awsSqsSettings.QueueBaseUrl}/{_awsSqsSettings.SendEmailLowPriorityQueue}";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore;
2 | using Microsoft.AspNetCore.Hosting;
3 |
4 | namespace ShareBook.Api
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | BuildWebHost(args).Run();
11 | }
12 |
13 | public static IWebHost BuildWebHost(string[] args) =>
14 | WebHost.CreateDefaultBuilder(args)
15 | .UseStartup()
16 | .Build();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ShareBook/Sharebook.Jobs/Jobs/IJob.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Enums;
2 | using System;
3 | using System.Threading.Tasks;
4 |
5 | namespace Sharebook.Jobs
6 | {
7 | public interface IJob
8 | {
9 | string JobName { get; set; }
10 | string Description { get; set; }
11 | Interval Interval { get; set; }
12 | bool Active { get; set; }
13 | TimeSpan? BestTimeToExecute { get; set; }
14 |
15 | bool HasWork();
16 | Task ExecuteAsync();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/MeetupParticipant.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ShareBook.Domain
9 | {
10 | public class MeetupParticipant : BaseEntity
11 | {
12 | public virtual Meetup Meetup { get; set; }
13 | public string FirstName { get; set; }
14 | public string LastName { get; set; }
15 | public string Email { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/ForgotPasswordTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Recuperar senha - Sharebook
6 |
7 |
8 |
9 | Olá {User.Name}
10 |
11 |
12 | Para realizar a troca da senha é necessário acessar o link {LinkForgotMyPassword}
13 |
14 | Esse link tem validade de 24 horas
15 | Equipe Sharebook
16 |
17 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/Crypto/Salt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 |
4 | namespace ShareBook.Helper.Crypto
5 | {
6 | public class Salt
7 | {
8 | public static string Create()
9 | {
10 | byte[] randomBytes = new byte[128 / 8];
11 | using (var generator = RandomNumberGenerator.Create())
12 | {
13 | generator.GetBytes(randomBytes);
14 | return Convert.ToBase64String(randomBytes);
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/PushNotification/IPushNotificationService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Service.Notification
5 | {
6 | public interface IPushNotificationService
7 | {
8 | Task SendNotificationSegmentsAsync(NotificationOnesignal notficationSettings);
9 | Task SendNotificationByKeyAsync(NotificationOnesignal notficationSettings);
10 | Task SendNotificationByEmailAsync(string email, string title, string content);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Validators/CategoryValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 |
3 | namespace ShareBook.Domain.Validators
4 | {
5 | public class CategoryValidator : AbstractValidator
6 | {
7 |
8 | #region Messages
9 | public const string Name = "O nome da categoria é obrigatório";
10 | #endregion
11 |
12 |
13 | public CategoryValidator()
14 | {
15 | RuleFor(c => c.Name)
16 | .NotEmpty()
17 | .WithMessage(Name);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/User/IUserEmailService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.DTOs;
4 |
5 | namespace ShareBook.Service
6 | {
7 | public interface IUserEmailService
8 | {
9 | Task SendEmailForgotMyPasswordToUserAsync(User user);
10 | Task SendEmailRequestParentAprovalAsync(RegisterUserDTO userDto, User user);
11 | Task SendEmailParentAprovedNotifyUserAsync(User user);
12 | Task SendEmailAnonymizeNotifyAdmsAsync(UserAnonymizeDTO dto);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/DonationStatus.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Text.Json.Serialization;
3 |
4 | namespace ShareBook.Domain.Enums
5 | {
6 | [JsonConverter(typeof(JsonStringEnumConverter))]
7 | public enum DonationStatus
8 | {
9 | [Description("Aguardando Ação")]
10 | WaitingAction,
11 |
12 | [Description("Doado")]
13 | Donated,
14 |
15 | [Description("Não foi dessa vez")]
16 | Denied,
17 |
18 | [Description("Cancelado")]
19 | Canceled
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Authorization/Permission.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ShareBook.Service.Authorization
4 | {
5 | public class Permissions
6 | {
7 | public enum Permission
8 | {
9 | CreateBook,
10 | UpdateBook,
11 | DeleteBook,
12 | ApproveBook,
13 | DonateBook
14 | }
15 |
16 | public static List AdminPermissions { get; } = new List() { Permission.ApproveBook, Permission.DonateBook };
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AWSSQS/NewBookQueue.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using ShareBook.Service.AwsSqs.Dto;
3 |
4 | namespace ShareBook.Service.AwsSqs;
5 |
6 | public class NewBookQueue : GenericQueue
7 | {
8 |
9 | public NewBookQueue(IOptions awsSqsSettings) : base(awsSqsSettings)
10 | {
11 | _queueUrl = $"{_awsSqsSettings.QueueBaseUrl}/{_awsSqsSettings.NewBookQueue}";
12 | }
13 |
14 | // pra poder mockar
15 | public NewBookQueue() : base(null) {}
16 | }
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/Mocks/BookUserMock.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace ShareBook.Test.Unit.Mocks
7 | {
8 | public class BookUserMock
9 | {
10 | public static BookUser GetDonation(Book book, User requestingUser)
11 | {
12 | return new BookUser()
13 | {
14 | Book = book,
15 | User = requestingUser,
16 | Reason = "MOTIVO"
17 | };
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/ShareBook.Helper.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/FreightOption.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Text.Json.Serialization;
3 |
4 | namespace ShareBook.Domain.Enums
5 | {
6 | [JsonConverter(typeof(JsonStringEnumConverter))]
7 | public enum FreightOption
8 | {
9 | [Description("Cidade")]
10 | City,
11 |
12 | [Description("Estado")]
13 | State,
14 |
15 | [Description("País")]
16 | Country,
17 |
18 | [Description("Mundo")]
19 | World,
20 |
21 | [Description("Não")]
22 | WithoutFreight,
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/ShareBook.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AwsSqs/MailSenderHighPriorityQueue .cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.Options;
4 | using ShareBook.Service.AwsSqs.Dto;
5 |
6 | namespace ShareBook.Service.AwsSqs;
7 |
8 | public class MailSenderHighPriorityQueue : GenericQueue
9 | {
10 | public MailSenderHighPriorityQueue(IOptions awsSqsSettings) : base(awsSqsSettings)
11 | {
12 | _queueUrl = $"{_awsSqsSettings.QueueBaseUrl}/{_awsSqsSettings.SendEmailHighPriorityQueue}";
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Category/CategoryService.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using ShareBook.Domain;
3 | using ShareBook.Repository;
4 | using ShareBook.Repository.UoW;
5 | using ShareBook.Service.Generic;
6 |
7 | namespace ShareBook.Service
8 | {
9 | public class CategoryService : BaseService, ICategoryService
10 | {
11 | public CategoryService(ICategoryRepository categoryRepository, IUnitOfWork unitOfWork, IValidator validator)
12 | : base(categoryRepository, unitOfWork, validator)
13 | {
14 |
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/NotificationOnesignal.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Enums;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace ShareBook.Domain
6 | {
7 | public class NotificationOnesignal
8 | {
9 | public string Title { get; set; }
10 | public string Content { get; set; }
11 | public TypeSegments TypeSegments { get; set; }
12 | public string UrlImage { get; set; }
13 | public IList LanguageCodes { get; set; }
14 | public string Key { get; set; }
15 | public string Value { get; set; }
16 | }
17 |
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/CategoryMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class CategoryMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 |
12 | entityBuilder.HasKey(t => t.Id);
13 |
14 | entityBuilder.Property(t => t.Name)
15 | .HasMaxLength(100)
16 | .IsRequired();
17 |
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Meetup/Dto/YoutubeDTOError.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ShareBook.Service.Dto;
4 |
5 | public class YoutubeDtoError
6 | {
7 | public Error error { get; set; }
8 | }
9 |
10 | public class Error
11 | {
12 | public int Code { get; set; }
13 | public string Message { get; set; }
14 | public List Errors { get; set; }
15 | public string Status { get; set; }
16 | }
17 |
18 | public class YoutubeErrorDetailDto
19 | {
20 | public string Message { get; set; }
21 | public string Domain { get; set; }
22 | public string Reason { get; set; }
23 | }
24 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Meetup/MeetupParticipantRepository.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Common;
4 | using ShareBook.Repository.Repository;
5 | using System;
6 | using System.Linq;
7 | using System.Linq.Expressions;
8 | using System.Threading.Tasks;
9 |
10 | namespace ShareBook.Repository
11 | {
12 | public class MeetupParticipantRepository : RepositoryGeneric, IMeetupParticipantRepository
13 | {
14 | public MeetupParticipantRepository(ApplicationDbContext context) : base(context)
15 | {
16 |
17 | }
18 |
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AwsSqs/Dto/MailSenderBody.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper.Configuration.Conventions;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace ShareBook.Service.AwsSqs.Dto
7 | {
8 | public class MailSenderbody
9 | {
10 | public string Subject { get; set; }
11 | public string BodyHTML { get; set; }
12 | public IList Destinations { get; set; }
13 | public bool CopyAdmins { get; set; } = false;
14 | }
15 |
16 | public class Destination
17 | {
18 | public string Name { get; set; }
19 | public string Email { get; set; }
20 | }
21 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Address.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using System;
3 |
4 | namespace ShareBook.Domain
5 | {
6 | public class Address : BaseEntity
7 | {
8 | public string Street { get; set; }
9 |
10 | public string Number { get; set; }
11 |
12 | public string Complement { get; set; }
13 |
14 | public string Neighborhood { get; set; }
15 |
16 | public string PostalCode { get; set; }
17 |
18 | public string City { get; set; }
19 |
20 | public string State { get; set; }
21 |
22 | public string Country { get; set; }
23 |
24 | public Guid UserId { get; set; }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/NotificationOnesignalVM.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Enums;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 |
5 | namespace ShareBook.Api.ViewModels
6 | {
7 | public class NotificationOnesignalVM
8 | {
9 | [Required]
10 | public string Title { get; set; }
11 | [Required]
12 | public string Content { get; set; }
13 | public TypeSegments TypeSegments { get; set; }
14 | public string UrlImage { get; set; }
15 | [Required]
16 | public string Key { get; set; }
17 | [Required]
18 | public string Value { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Validators/AccessHistoryValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 |
3 | namespace ShareBook.Domain.Validators {
4 | public class AccessHistoryValidator : AbstractValidator {
5 | private const string nameRequired = "O nome é obrigatório";
6 | private const string nameMaxLength = "Nome deve ter no máximo 100 caracteres";
7 |
8 | public AccessHistoryValidator() {
9 | RuleFor(a => a.VisitorName)
10 | .NotEmpty()
11 | .WithMessage(nameRequired)
12 | .Must(x => x != null && x.Length < 200)
13 | .WithMessage(nameMaxLength);
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Recaptcha/RecaptchaService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 |
3 | namespace ShareBook.Service.Recaptcha
4 | {
5 | public class RecaptchaService : IRecaptchaService
6 | {
7 | // TODO: Fazer a validação real do "RecaptchaReactive" (https://developers.google.com/recaptcha/docs/verify)
8 | public Result SimpleValidationRecaptcha(string recaptcha)
9 | {
10 | Result result = new Result();
11 | if (string.IsNullOrWhiteSpace(recaptcha) || recaptcha.Length <= 100)
12 | result.Messages.Add("RecaptchaReactive está inválido!");
13 |
14 | return result;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/UpdateUserVM.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ShareBook.Domain;
3 | using System.ComponentModel.DataAnnotations;
4 |
5 | namespace ShareBook.Api.ViewModels
6 | {
7 | public class UpdateUserVM : BaseViewModel
8 | {
9 | [Required]
10 | public string Name { get; set; }
11 |
12 | [Required]
13 | public string Email { get; set; }
14 |
15 | public string Linkedin { get; set; }
16 |
17 | public string Instagram { get; set; }
18 |
19 | public Address Address { get; set; }
20 |
21 | public string Phone { get; set; }
22 |
23 | public bool AllowSendingEmail { get; set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookCanceledTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Uma doação foi cancelada.
6 |
7 |
8 |
9 | Olá,
10 |
11 |
12 | Uma doação foi cancelada. Veja mais informações abaixo:
13 |
14 |
15 |
16 | Livro: {Title}
17 | Doador(a): {Donor}
18 | Cancelado por: {CanceledBy}
19 | Justificativa: {Reason}
20 |
21 |
22 | Sharebook
23 |
24 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AWSSQS/AWSSQSSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ShareBook.Service.AwsSqs
6 | {
7 | public class AwsSqsSettings
8 | {
9 | public bool IsActive { get; set; }
10 | public string AccessKey { get; set; }
11 | public string SecretKey { get; set; }
12 | public string Region { get; set; }
13 | public string QueueBaseUrl { get; set; }
14 |
15 | // Queues
16 | public string NewBookQueue { get; set; }
17 |
18 | public string SendEmailHighPriorityQueue { get; set; }
19 |
20 | public string SendEmailLowPriorityQueue { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Controllers/CategoryController.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using Microsoft.AspNetCore.Mvc;
3 | using ShareBook.Domain;
4 | using ShareBook.Domain.Common;
5 | using ShareBook.Service;
6 | using System.Threading.Tasks;
7 |
8 | namespace ShareBook.Api.Controllers
9 | {
10 | [Route("api/[controller]")]
11 | public class CategoryController : BaseCrudController
12 | {
13 | public CategoryController(ICategoryService categoryService,
14 | IMapper mapper) : base(categoryService, mapper)
15 | {
16 | SetDefault(x => x.Name);
17 | }
18 |
19 | public override async Task> GetAllAsync() => await PagedAsync(1, 50);
20 | }
21 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/RequestersListVM.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Enums;
4 | using System;
5 | using System.ComponentModel.DataAnnotations;
6 |
7 | namespace ShareBook.Api.ViewModels
8 | {
9 | public class RequestersListVM
10 | {
11 | public Guid UserId { get; set; }
12 |
13 | public string RequesterNickName { get; set; }
14 |
15 | public string Location { get; set; }
16 |
17 | public int TotalBooksWon { get; set; }
18 |
19 | public int TotalBooksDonated { get; set; }
20 |
21 | public string RequestText { get; set; }
22 |
23 | public DonationStatus Status { get; set; }
24 |
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Meetup.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace ShareBook.Domain;
6 |
7 | public class Meetup : BaseEntity
8 | {
9 | public int SymplaEventId { get; set; }
10 | public string Title { get; set; }
11 | public string Description { get; set; }
12 | public DateTime StartDate { get; set; }
13 | public string Cover { get; set; }
14 | public string YoutubeUrl { get; set; }
15 | public string SymplaEventUrl { get; set; }
16 | public ICollection MeetupParticipants { get; set; }
17 | public bool IsParticipantListSynced { get; set; } = false;
18 | public bool Active { get; set; } = true;
19 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Muambator/MuambatorConfigurator.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 |
4 | namespace ShareBook.Service.Muambator
5 | {
6 | public static class MuambatorConfigurator
7 | {
8 | public static string Token { get; private set; }
9 |
10 | public static bool IsActive { get; private set; }
11 |
12 | public static void Configure(string token, string isActive)
13 | {
14 | if ((string.IsNullOrEmpty(token) || string.IsNullOrEmpty(isActive)) || (isActive.ToLower() != "true" && isActive.ToLower() != "false"))
15 | return;
16 |
17 | Token = token;
18 | IsActive = Convert.ToBoolean(isActive.ToLower());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/CustomValidators/StringLengthRangeOptionalAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ShareBook.Api.ViewModels.CustomValidators
4 | {
5 | public class StringLengthRangeOptionalAttribute : ValidationAttribute
6 | {
7 | public int Minimum { get; set; }
8 | public int Maximum { get; set; }
9 |
10 | public override bool IsValid(object value)
11 | {
12 | string model = (string)value;
13 |
14 | if (value == null || model.Length == 0 || model == string.Empty)
15 | return true;
16 |
17 | return model.Length > Minimum && model.Length <= Maximum;
18 | }
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/AccessHistoryMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping {
6 | public class AccessHistoryMap : IEntityTypeConfiguration {
7 | public void Configure(EntityTypeBuilder builder) {
8 | builder.ToTable("AccessHistories");
9 |
10 | builder.HasKey(a => a.Id);
11 | builder.Property(a => a.VisitorName).HasMaxLength(200);
12 | builder.HasOne(a => a.User)
13 | .WithMany(u => u.Visitors)
14 | .HasForeignKey(a => a.UserId);
15 |
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Infra.CrossCutting.Identity/SigningConfigurations.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.IdentityModel.Tokens;
2 | using System.Security.Cryptography;
3 | using System.Text;
4 |
5 | namespace ShareBook.Infra.CrossCutting.Identity
6 | {
7 | public class SigningConfigurations
8 | {
9 | public SecurityKey Key { get; }
10 | public SigningCredentials SigningCredentials { get; }
11 |
12 | public SigningConfigurations(string secretJwtKey)
13 | {
14 | Key = new SymmetricSecurityKey(
15 | Encoding.UTF8.GetBytes(secretJwtKey));
16 |
17 | SigningCredentials = new SigningCredentials(
18 | Key, SecurityAlgorithms.HmacSha256Signature);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ShareBook/Sharebook.Jobs/Sharebook.Jobs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/CreateBookVM.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Enums;
2 | using System;
3 |
4 | namespace ShareBook.Api.ViewModels
5 | {
6 | public class CreateBookVM : BaseViewModel
7 | {
8 | public string Title { get; set; }
9 |
10 | public string Author { get; set; }
11 |
12 | public Guid CategoryId { get; set; }
13 |
14 | public string ImageName { get; set; }
15 |
16 | public byte[] ImageBytes { get; set; }
17 |
18 | public FreightOption FreightOption { get; set; }
19 |
20 | public string Synopsis { get; set; }
21 | public string Type { get; set; }
22 | public string EBookDownloadLink { get; set; }
23 | public string EBookPdfFile { get; set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/Crypto/Hash.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using Microsoft.AspNetCore.Cryptography.KeyDerivation;
4 |
5 | namespace ShareBook.Helper.Crypto
6 | {
7 | public class Hash
8 | {
9 | public static string Create(string value, string salt)
10 | {
11 | var valueBytes = KeyDerivation.Pbkdf2(
12 | password: value,
13 | salt: Encoding.UTF8.GetBytes(salt),
14 | prf: KeyDerivationPrf.HMACSHA512,
15 | iterationCount: 10000,
16 | numBytesRequested: 256 / 8);
17 |
18 | return Convert.ToBase64String(valueBytes);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/User/UserRepository.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Repository
5 | {
6 | public class UserRepository : RepositoryGeneric, IUserRepository
7 | {
8 | public UserRepository(ApplicationDbContext context) : base(context)
9 | {
10 | }
11 |
12 | public async Task UpdatePasswordAsync(User user)
13 | {
14 | _dbSet.Update(user);
15 | _context.Entry(user).Property(x => x.Password).IsModified = true;
16 | _context.Entry(user).Property(x => x.PasswordSalt).IsModified = true;
17 | await _context.SaveChangesAsync();
18 |
19 | return user;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-build-validation.yml:
--------------------------------------------------------------------------------
1 | name: .NET build validation
2 |
3 | on:
4 | push:
5 | branches: [develop]
6 | pull_request:
7 | branches: [develop]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Setup .NET
16 | uses: actions/setup-dotnet@v1
17 | with:
18 | dotnet-version: 8.0.x
19 | - name: Restore dependencies
20 | run: dotnet restore ./ShareBook/ShareBook.sln
21 | - name: Build
22 | run: dotnet build ./ShareBook/ShareBook.sln --no-restore
23 | - name: Test
24 | run: dotnet test ./ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj --no-build --verbosity normal
25 | if: success()
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Meetup/Dto/YoutubeDetailDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ShareBook.Service.Dto;
5 |
6 | public class YoutubeDtoDetail
7 | {
8 | public string nextPageToken { get; set; }
9 | public string prevPageToken { get; set; }
10 | public PageInfo pageInfo { get; set; }
11 | public List Items { get; set; }
12 |
13 | }
14 |
15 | public class ItemDetail
16 | {
17 | public String Id { get; set; }
18 | public Snippet Snippet { get; set; }
19 | public liveStreamingDetails liveStreamingDetails { get; set; }
20 | }
21 |
22 | public class liveStreamingDetails
23 | {
24 | public DateTime scheduledStartTime { get; set; }
25 | public string activeLiveChatId { get; set; }
26 | }
27 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/AnonymizeNotifyAdms.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Anonimização de conta
7 |
8 |
9 |
10 | Prezados adms. Um usuário solicitou a remoção de sua conta. Seus dados pessoais foram anonimizados e sua conta foi desativada.
11 |
12 |
13 | Justificativa
14 | {Reason}
15 |
16 |
17 |
18 | Atenciosamente,
19 |
20 | Sharebook team - Compartilhando conhecimento
21 | Siga-nos no instagram:
22 | @sharebook.com.br
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/MyBooksRequestsVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ShareBook.Api.ViewModels
4 | {
5 | public class MyBookRequestVM
6 | {
7 | public Guid RequestId { get; set; }
8 |
9 | public string Title { get; set; }
10 |
11 | public string Author { get; set; }
12 |
13 | // status do pedido. (ex: aguardando decisão, negado, doado)
14 | // apenas pra saber se ganhou ou não.
15 | public string Status { get; set; }
16 |
17 | // status da doação. (ex: aguardando envio, enviado, recebido)
18 | // para saber sobre o envio.
19 | public string BookStatus { get; set; }
20 |
21 | public string TrackingNumber { get; set; }
22 |
23 | public Guid BookId { get; set; }
24 |
25 | public string Slug { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/workflows/postman-collection.yml:
--------------------------------------------------------------------------------
1 | name: Postman collection validations
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | run-postman-collection-dev:
8 | if: false # desabilita temporariamente
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@master
12 | - name: Postman collection - Development environment
13 | uses: matt-ball/newman-action@master
14 | with:
15 | collection: ShareBook API - Tests.postman_collection.json
16 | delayRequest: 2000
17 | envVar: '[{ "key": "sharebookUrl", "value": "https://dev.sharebook.com.br/" }, { "key": "sharebookEmail", "value": "raffacabofrio@gmail.com" }, { "key": "sharebookPassword", "value": "123456" }]'
18 | # TODO: Add a job for production environment which must get username and password from github secrets
19 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Meetup/Dto/SymplaDTO.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Serialization;
3 | using System.Collections.Generic;
4 |
5 | namespace ShareBook.Service.Dto;
6 |
7 | // 24/11/2024 - Paramos de integrar com sympla. Agora carregamos a lista de meetups apenas do YOUTUBE.
8 | public class SymplaDto
9 | {
10 | public string Status { get; set; }
11 | public string Code { get; set; }
12 | public string Message { get; set; }
13 | public List Data { get; set; }
14 | }
15 | public class SymplaEvent
16 | {
17 | public int Id { get; set; }
18 | [JsonProperty("start_date")]
19 | public string StartDate { get; set; }
20 | public string Name { get; set; }
21 | public string Detail { get; set; }
22 | public string Image { get; set; }
23 | public string Url { get; set; }
24 | }
25 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/JobHistoryMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class JobHistoryMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 | entityBuilder.HasKey(t => t.Id);
12 |
13 | entityBuilder.Property(t => t.JobName)
14 | .HasMaxLength(200)
15 | .IsRequired();
16 |
17 | entityBuilder.Property(t => t.LastResult)
18 | .HasMaxLength(200);
19 |
20 | entityBuilder.Property(t => t.Details)
21 | .HasMaxLength(4000); // Limite compatível com todos os bancos
22 |
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/JobHistory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using ShareBook.Domain.Common;
4 | using ShareBook.Domain.Enums;
5 |
6 | namespace ShareBook.Domain
7 | {
8 | public class JobHistory : BaseEntity
9 | {
10 | public string JobName { get; set; }
11 | public bool IsSuccess { get; set; }
12 |
13 | // Alguns jobs precisam saber de onde terminou o ultimo ciclo pra continuar a partir daí.
14 | // permitindo dividir um GRANDE PROCESSAMENTO em vários PEQUENOS.
15 | public string LastResult { get; set; }
16 | public string Details { get; set; }
17 |
18 | // Precisamos monitorar a duração dos nossos jobs, levando em consideração
19 | // que estamos numa hospedagem compartilhada e nosso limite é de 300 segundos.
20 | public double TimeSpentSeconds { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/BookUser.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using ShareBook.Domain.Enums;
3 | using System;
4 |
5 | namespace ShareBook.Domain
6 | {
7 | public class BookUser : BaseEntity
8 | {
9 | public Guid BookId { get; set; }
10 | public Book Book { get; set; }
11 | public User User { get; set; }
12 | public Guid UserId { get; set; }
13 | public string NickName { get; set; }
14 | public DonationStatus Status { get; private set; } = DonationStatus.WaitingAction;
15 | public string Note { get; set; } // motivo do doador ter escolhido.
16 | public string Reason { get; set; } // justificativa do interessado.
17 |
18 | public void UpdateBookUser(DonationStatus status, string note)
19 | {
20 | this.Status = status;
21 | this.Note = note;
22 | }
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/AccessHistory/AccessHistoryRepository.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | using ShareBook.Domain;
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace ShareBook.Repository {
11 | public class AccessHistoryRepository : RepositoryGeneric, IAccessHistoryRepository {
12 | public AccessHistoryRepository(ApplicationDbContext context) : base(context) { }
13 | public async Task> GetWhoAccessedMyProfileAsync(Guid userId) {
14 | if (userId.Equals(null)) return null;
15 |
16 | var list = from u in _context.AccessHistories
17 | where (u.UserId.Equals(userId))
18 | select u;
19 |
20 | return await list.ToListAsync();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/ParentAprovedNotifyUser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Consentimento dos pais
7 |
8 |
9 |
10 | Olá! Notícia boa! Seu acesso foi liberado pelos seus pais. Agora você pode entrar no sharebook para doar e ganhar livros. Aproveite! =)
11 |
12 |
13 | entrar no Sharebook
14 |
15 |
16 |
17 | Atenciosamente,
18 |
19 | Sharebook team - Compartilhando conhecimento
20 | Siga-nos no instagram:
21 | @sharebook.com.br
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/LogEntryMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class LogEntryMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 | entityBuilder.HasKey(t => t.Id);
12 | entityBuilder.Property(t => t.UserId);
13 | entityBuilder.Property(t => t.EntityName).HasMaxLength(64);
14 | entityBuilder.Property(t => t.EntityId);
15 | entityBuilder.Property(t => t.Operation);
16 | entityBuilder.Property(t => t.LogDateTime);
17 | entityBuilder.Property(t => t.ValuesChanges);
18 |
19 | entityBuilder.HasIndex("EntityName", "EntityId");
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/WaitingApprovalTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Aguarde aprovação - Sharebook
6 |
7 |
8 |
9 | Olá {User.Name}, nossos agradecimentos por doar na plataforma Sharebook e compartilhar conhecimento!
10 |
11 |
12 | Nossa equipe já está trabalhando na aprovação do {Title} e logo estará na nossa vitrine para que outras pessoas possam visualizar.
13 |
14 |
15 | Solicitamos que aguarde o e-mail de confirmação dessa aprovação =)
16 |
17 | Detalhes do livro:
18 |
19 | Livro: {Title}
20 | Autor: {Author}
21 |
22 |
23 | Equipe Sharebook
24 |
25 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/UpdateBookVM.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Enums;
2 | using System;
3 |
4 | namespace ShareBook.Api.ViewModels
5 | {
6 | public class UpdateBookVM : BaseViewModel
7 | {
8 | public string Title { get; set; }
9 |
10 | public string Author { get; set; }
11 |
12 | public Guid CategoryId { get; set; }
13 |
14 | public Guid UserId { get; set; }
15 |
16 | public Guid UserIdFacilitator { get; set; }
17 |
18 | public bool Approved { get; set; }
19 |
20 | public string ImageName { get; set; }
21 |
22 | public byte[] ImageBytes { get; set; }
23 |
24 | public string Synopsis { get; set; }
25 |
26 | public FreightOption FreightOption { get; set; }
27 | public string Type { get; set; }
28 | public string EBookDownloadLink { get; set; }
29 | public string EBookPdfFile { get; set; }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Validators/MeetupValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 |
3 | namespace ShareBook.Domain.Validators
4 | {
5 | public class MeetupValidator : AbstractValidator
6 | {
7 | public MeetupValidator()
8 | {
9 | RuleFor(m => m.Title)
10 | .NotEmpty()
11 | .WithMessage("A propriedade: {propertyName} é obrigatória!");
12 |
13 | RuleFor(m => m.StartDate)
14 | .NotEmpty()
15 | .WithMessage("A propriedade: {propertyName} é obrigatória!");
16 |
17 | RuleFor(m => m.SymplaEventUrl)
18 | .NotEmpty()
19 | .WithMessage("A propriedade: {propertyName} é obrigatória!");
20 |
21 | RuleFor(m => m.SymplaEventId)
22 | .NotEmpty()
23 | .WithMessage("A propriedade: {propertyName} é obrigatória!");
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/UoW/UnitOfWork.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection.Metadata.Ecma335;
3 | using System.Threading.Tasks;
4 |
5 | namespace ShareBook.Repository.UoW
6 | {
7 | public class UnitOfWork : IUnitOfWork
8 | {
9 | private readonly ApplicationDbContext _context;
10 |
11 | public UnitOfWork(ApplicationDbContext context) => _context = context;
12 |
13 | public async Task BeginTransactionAsync() => await _context.Database.BeginTransactionAsync();
14 | public async Task CommitAsync() => await _context.Database.CommitTransactionAsync();
15 | public async Task RollbackAsync() => await _context.Database.RollbackTransactionAsync();
16 | public async ValueTask DisposeAsync()
17 | {
18 | if (_context?.Database?.CurrentTransaction != null)
19 | await _context.Database.CurrentTransaction.RollbackAsync();
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/IEmailService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace ShareBook.Service
6 | {
7 | public interface IEmailService
8 | {
9 | Task SendToAdminsAsync(string messageText, string subject);
10 | Task SendAsync(string emailRecipient, string nameRecipient, string messageText, string subject);
11 | Task SendAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins, bool highPriority);
12 | Task SendSmtpAsync(string emailRecipient, string nameRecipient, string messageText, string subject, bool copyAdmins);
13 | Task TestAsync(string email, string name);
14 |
15 | Task> ProcessBounceMessagesAsync();
16 | Task> GetBouncesAsync(string email);
17 | Task IsBounceAsync(string email);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookDonatedTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Parabéns você foi selecionado para receber o livro - Sharebook
6 |
7 |
8 | Parabéns você foi selecionado para receber o livro {Book.Title}
9 |
10 | Olá {User.Name},
11 |
12 |
13 | Veja mais informações abaixo sobre o livro doado:
14 |
15 |
16 |
17 | Livro: {Book.Title}
18 | Doador: {Book.User.Name}
19 | Linkedin Doador: {Book.User.Linkedin}
20 | Telefone Doador: {Book.User.Phone}
21 | Email Doador: {Book.User.Email}
22 |
23 |
24 | Sharebook
25 |
26 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/Extensions/EnumeratorExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | namespace ShareBook.Helper.Extensions
5 | {
6 | public static class EnumeratorExtension
7 | {
8 | public static string Description(this Enum value)
9 | {
10 | // get attributes
11 | var field = value.GetType().GetField(value.ToString());
12 | var attributes = field.GetCustomAttributes(false);
13 |
14 | // Description is in a hidden Attribute class called DisplayAttribute
15 | // Not to be confused with DisplayNameAttribute
16 | dynamic displayAttribute = null;
17 |
18 | if (attributes.Any())
19 | {
20 | displayAttribute = attributes.ElementAt(0);
21 | }
22 |
23 | // return description
24 | return displayAttribute?.Description ?? "Description Not Found";
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/Mapper/Mapper.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using System;
3 |
4 | namespace ShareBook.Helper.Mapper
5 | {
6 | public static class Mapper
7 | {
8 | //public static TDestination Map(object source)
9 | //{
10 | // return AutoMapper.Mapper.Map(source);
11 | //}
12 |
13 | //public static TDestination Map(TSource source)
14 | //{
15 | // return AutoMapper.Mapper.Map(source);
16 | //}
17 |
18 | //public static TDestination Map(TSource source, TDestination destination)
19 | //{
20 | // return AutoMapper.Mapper.Map(source, destination);
21 | //}
22 |
23 | //public static void Initialize(Action action)
24 | //{
25 | // AutoMapper.Mapper.Initialize(action);
26 | //}
27 | }
28 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Validators/BookUserValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using ShareBook.Domain.Enums;
3 |
4 | namespace ShareBook.Domain.Validators
5 | {
6 | public class BookUserValidator : AbstractValidator
7 | {
8 | #region Messages
9 | public const string Book = "Livro é obrigatório";
10 | public const string Requester = "Solicitante do livro é obrigatório";
11 | public const string RequesterReason = "Justificativa do solicitante é obrigatória";
12 | #endregion
13 |
14 | public BookUserValidator()
15 | {
16 | RuleFor(b => b.BookId)
17 | .NotEmpty()
18 | .WithMessage(Book);
19 |
20 | RuleFor(b => b.UserId)
21 | .NotEmpty()
22 | .WithMessage(Requester);
23 |
24 | RuleFor(b => b.Reason)
25 | .NotEmpty()
26 | .WithMessage(RequesterReason);
27 |
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/Extensions/AssemblyExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Reflection;
4 |
5 | namespace ShareBook.Helper.Extensions
6 | {
7 | public static class AssemblyExtension
8 | {
9 | public static DateTime GetLinkerTime(this Assembly ass)
10 | {
11 | const string BuildVersionPrefix = "+build";
12 |
13 | var attribute = ass.GetCustomAttribute();
14 | if (attribute?.InformationalVersion != null)
15 | {
16 | var value = attribute.InformationalVersion;
17 | var index = value.IndexOf(BuildVersionPrefix);
18 | if (index > 0)
19 | {
20 | value = value[(index + BuildVersionPrefix.Length)..];
21 | return DateTime.ParseExact(value, "yyyy-MM-ddTHH:mm:ss:fffZ", CultureInfo.InvariantCulture);
22 | }
23 | }
24 | return default;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Integration/Setup/ShareBookTestsFixture.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using ShareBook.Repository;
3 |
4 | namespace ShareBook.Test.Integration.Setup;
5 |
6 |
7 | [CollectionDefinition(nameof(ShareBookTestsFixture))]
8 | public class ShareBookTestsFixtureCollection : ICollectionFixture
9 | { }
10 |
11 | public class ShareBookTestsFixture
12 | {
13 | public ShareBookWebAppFactory ShareBookWebAppFactory { get; } = new ShareBookWebAppFactory();
14 | public HttpClient ShareBookApiClient { get; init; }
15 | public ApplicationDbContext ApplicationDbContext { get; init; }
16 |
17 | public ShareBookTestsFixture()
18 | {
19 | ShareBookApiClient = ShareBookWebAppFactory.CreateClient();
20 | ApplicationDbContext = ShareBookWebAppFactory.Services.GetRequiredService();
21 |
22 | // Seed data
23 | var sharebookSeeder = new ShareBookSeeder(ApplicationDbContext);
24 | sharebookSeeder.Seed();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/ShareBook.Infra.Data.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookApprovedTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Livro aprovado - Sharebook
6 |
7 |
8 |
9 | Olá {User.Name}
10 |
11 |
12 | O livro {Book.Title} foi aprovado e já está na nossa vitrine para doação.
13 |
14 | Detalhes do livro:
15 |
16 | Livro: {Book.Title}
17 | Autor: {Book.Author}
18 |
19 |
20 |
21 | A data de escolha do vencedor será no dia {ChooseDate} .
22 | Pedimos para que reserve um tempo neste dia para escolher o ganhador da sua doação.
23 | Lembre-se: esse passo é fundamental para uma melhor experiência de todos!
24 | Os interessados estarão anciosos pela sua escolha. Por isso, não perca a data!
25 |
26 |
27 | Equipe Sharebook
28 |
29 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/BookUser/IBookUsersEmailService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Domain.DTOs;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | namespace ShareBook.Service
7 | {
8 | public interface IBookUsersEmailService
9 | {
10 | Task SendEmailBookDonatedAsync(BookUser bookUser);
11 |
12 | Task SendEmailBookDonatedNotifyDonorAsync(Book book, User winner);
13 |
14 | Task SendEmailBookDonorAsync(BookUser bookUser, Book bookRequested);
15 |
16 | Task SendEmailBookInterestedAsync(BookUser bookUser, Book book);
17 |
18 | Task SendEmailDonationDeclinedAsync(Book book, BookUser bookUserWinner, List bookUsersDeclined);
19 |
20 | Task SendEmailDonationCanceledAsync(Book book, List bookUsers);
21 |
22 | Task SendEmailBookCanceledToAdminsAndDonorAsync(BookCancelationDTO dto);
23 |
24 | Task SendEmailTrackingNumberInformedAsync(BookUser bookUserWinner, Book book);
25 |
26 | Task SendEmailMaxRequestsAsync(Book bookRequested);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookNoticeDonorTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Seu livro foi solicitado - Sharebook
6 |
7 |
8 | Seu livro foi solicitado - Sharebook
9 |
10 | Olá {Donor.Name},
11 |
12 |
13 |
14 | Seu livro "{Donor.BookTitle}" foi solicitado.
15 |
16 |
17 | {HtmlTable}
18 |
19 |
20 | Atenção! Este é apenas uma aviso que alguém está interessado no seu livro.
21 | É necessário no entanto aguardar até a data de {Donor.ChooseDate} para escolher o ganhador. Blz?
22 |
23 |
24 | Atenciosamente,
25 |
26 |
27 | Sharebook - Compartilhando conhecimento
28 | Siga-nos no instagram:
29 | @sharebook.com.br
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Filters/ValidateModelStateFilterAttribute.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using Microsoft.AspNetCore.Mvc.Filters;
3 | using ShareBook.Domain.Common;
4 | using System.Linq;
5 |
6 | namespace ShareBook.Api.Filters
7 | {
8 | public class ValidateModelStateFilterAttribute : ActionFilterAttribute
9 | {
10 | public override void OnActionExecuting(ActionExecutingContext context)
11 | {
12 | if (!context.ModelState.IsValid)
13 | {
14 | var errors = context.ModelState.Values.Where(v => v.Errors.Count > 0)
15 | .SelectMany(v => v.Errors)
16 | .Select(v => v.ErrorMessage)
17 | .ToList();
18 |
19 | var response = new Result();
20 | foreach (var error in errors)
21 | response.Messages.Add(error);
22 |
23 | context.Result = new JsonResult(response)
24 | {
25 | StatusCode = 400
26 | };
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/Services/RecaptchaServiceTests.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using ShareBook.Service.Recaptcha;
3 | using Xunit;
4 |
5 | namespace ShareBook.Test.Unit.Services
6 | {
7 | public class RecaptchaServiceTests
8 | {
9 | private readonly IRecaptchaService _recaptchaService = new RecaptchaService();
10 | private const string validRecaptcha = "asdaasdjasodaj7i364yubki23y728374234b2jk34h2347i26348724yh2bjhk34g2j34t273842384iuh2h4j234g2j34t27834bjh";
11 | private const string invalidRecaptcha = "123456";
12 | public RecaptchaServiceTests() { }
13 |
14 |
15 | [Fact]
16 | public void ValidRecaptcha()
17 | {
18 | Result result = _recaptchaService.SimpleValidationRecaptcha(validRecaptcha);
19 | Assert.True(result.Success);
20 | }
21 |
22 | [Fact]
23 | public void InvalidRecaptcha()
24 | {
25 | Result result = _recaptchaService.SimpleValidationRecaptcha(invalidRecaptcha);
26 | Assert.False(result.Success);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/AccessHistory/AccessHistoryService.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 |
3 | using ShareBook.Domain;
4 | using ShareBook.Domain.Enums;
5 | using ShareBook.Repository;
6 | using ShareBook.Repository.UoW;
7 | using ShareBook.Service.Generic;
8 |
9 | using System.Threading.Tasks;
10 |
11 | namespace ShareBook.Service {
12 | public class AccessHistoryService : BaseService, IAccessHistoryService {
13 | private readonly IAccessHistoryRepository _accessHistoryRepository;
14 |
15 | public AccessHistoryService(IAccessHistoryRepository repository,
16 | IUnitOfWork unitOfWork,
17 | IValidator validator) : base(repository, unitOfWork, validator)
18 | {
19 | _accessHistoryRepository = repository;
20 | }
21 |
22 | public async Task InsertVisitorAsync(User user, User visitor, VisitorProfile profile) {
23 | var visitorProfile = new AccessHistory(user.Id, visitor.Name, profile);
24 |
25 | await _accessHistoryRepository.InsertAsync(visitorProfile);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/devops/.dockerignore:
--------------------------------------------------------------------------------
1 | # Build outputs
2 | **/bin/
3 | **/obj/
4 | **/out/
5 | **/publish/
6 |
7 | # Visual Studio
8 | .vs/
9 | *.user
10 | *.suo
11 | *.userosscache
12 | *.sln.docstates
13 |
14 | # JetBrains
15 | .idea/
16 | *.sln.iml
17 |
18 | # Test results
19 | TestResults/
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | build/
27 | bld/
28 | [Bb]in/
29 | [Oo]bj/
30 | [Oo]ut/
31 | msbuild.log
32 | msbuild.err
33 | msbuild.wrn
34 |
35 | # Node.js (if used for frontend)
36 | node_modules/
37 | npm-debug.log*
38 |
39 | # Docker
40 | Dockerfile*
41 | .dockerignore
42 | docker-compose*.yml
43 |
44 | # DevOps
45 | devops/
46 |
47 | # Git
48 | .git/
49 | .gitignore
50 |
51 | # Documentation
52 | *.md
53 | README*
54 |
55 | # Logs
56 | logs/
57 | *.log
58 |
59 | # User-specific files
60 | *.rsuser
61 | *.userprefs
62 | launchSettings.json
63 |
64 | # Coverage reports
65 | coverage/
66 | *.cobertura.xml
67 |
68 | # Database files
69 | *.db
70 | *.sqlite*
71 |
72 | # Temporary files
73 | [Tt]mp/
74 | [Tt]emp/
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/RequestParentAproval.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Consentimento dos pais
7 |
8 |
9 |
10 | Olá! O usuário {UserName} , menor de idade, se cadastrou em nosso app Sharebook e informou que você é o responsável. Precisamos do seu consentimento para liberar o acesso.
11 |
12 |
13 | Sharebook é um app livre e gratuito para doação de livros. Temos todo o cuidado com a segurança e privacidade dos nossos usuários.
14 |
15 |
16 | Para liberar o acesso por favor use esse link: {AprovalLink}
17 |
18 |
19 |
20 | Atenciosamente,
21 |
22 | Sharebook team - Compartilhando conhecimento
23 | Siga-nos no instagram:
24 | @sharebook.com.br
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Services/RollbarConfigurator.cs:
--------------------------------------------------------------------------------
1 | using Rollbar;
2 | using System;
3 |
4 | namespace ShareBook.Api.Services
5 | {
6 | public static class RollbarConfigurator
7 | {
8 | public static bool IsActive { get; private set; }
9 |
10 | public static void Configure(string environment, string isActive, string token, string logLevel)
11 | {
12 | if (string.IsNullOrEmpty(environment) ||
13 | string.IsNullOrEmpty(isActive) ||
14 | string.IsNullOrEmpty(token))
15 | return;
16 |
17 | var result = ErrorLevel.TryParse(logLevel, out ErrorLevel logLevelEnum);
18 |
19 | if (!result)
20 | throw new Exception("Rollbar invalid logLevel: " + logLevel);
21 |
22 | RollbarLocator.RollbarInstance.Configure(new RollbarConfig(accessToken: token) { Environment = environment, LogLevel = logLevelEnum, AccessToken = token });
23 | RollbarLocator.RollbarInstance.Info($"Rollbar is configured properly in {environment} environment.");
24 |
25 | IsActive = true;
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Common/Result.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation.Results;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace ShareBook.Domain.Common
6 | {
7 | public class Result : Result
8 | {
9 | public Result() : base(null) { }
10 | public Result(string SuccessMessage) : base(null)
11 | {
12 | this.SuccessMessage = SuccessMessage;
13 | }
14 | }
15 |
16 | public class Result where T : class
17 | {
18 | public Result(T value) : this(null, value) { }
19 | public Result(ValidationResult validationResult) : this(validationResult, null) { }
20 | public Result(ValidationResult validationResult, T value)
21 | {
22 | Messages = validationResult?.Errors.Select(x => x.ErrorMessage).ToList() ?? new List();
23 | Value = value;
24 | }
25 |
26 | public T Value { get; set; }
27 | public List Messages { get; }
28 | public string SuccessMessage { get; set; }
29 |
30 | public bool Success { get { return Messages.Count == 0; } }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/DTOs/RegisterUserDTO.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace ShareBook.Domain.DTOs
3 | {
4 | public class RegisterUserDTO
5 | {
6 | public string Name { get; set; }
7 |
8 | public string Email { get; set; }
9 |
10 | public string Street { get; set; }
11 |
12 | public string Number { get; set; }
13 |
14 | public string Complement { get; set; }
15 |
16 | public string Neighborhood { get; set; }
17 |
18 | public string PostalCode { get; set; }
19 |
20 | public string City { get; set; }
21 |
22 | public string State { get; set; }
23 |
24 | public string Country { get; set; }
25 |
26 | public string Linkedin { get; set; }
27 |
28 | public string Instagram { get; set; }
29 |
30 | public string Phone { get; set; }
31 |
32 | public string Password { get; set; }
33 |
34 | public bool AllowSendingEmail { get; set; } = true;
35 |
36 | public int Age { get; set; }
37 |
38 | public string ParentEmail { get; set; }
39 | public string RecaptchaReactive { get; set; }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/devops/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build stage
2 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
3 | WORKDIR /app
4 |
5 | # Copy source code
6 | COPY ShareBook/ ./ShareBook/
7 |
8 | # Restore and build in one step to avoid cache issues
9 | RUN dotnet publish ShareBook/ShareBook.Api/ShareBook.Api.csproj -c Release -o /app/publish --verbosity normal
10 |
11 | # Runtime stage
12 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
13 |
14 | # Instala curl - necessário pro health check funcionar
15 | RUN apt-get update && apt-get install -y curl
16 |
17 | WORKDIR /app
18 |
19 | # Copy published files
20 | COPY --from=build /app/publish .
21 |
22 | # força o ASP.NET Core a escutar na porta 8080
23 | ENV ASPNETCORE_URLS=http://0.0.0.0:8080
24 |
25 | # Create non-root user
26 | RUN groupadd -r appuser && useradd -r -g appuser appuser
27 | RUN chown -R appuser:appuser /app
28 | USER appuser
29 |
30 | # Expose port
31 | EXPOSE 8080
32 |
33 | HEALTHCHECK --interval=30s --timeout=3s --start-period=30s \
34 | CMD curl -fsS http://127.0.0.1:8080/api/Operations/Ping || exit 1
35 |
36 | # Set entry point
37 | ENTRYPOINT ["dotnet", "ShareBook.Api.dll"]
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Enums/BookStatus.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Text.Json.Serialization;
3 |
4 | namespace ShareBook.Domain.Enums
5 | {
6 | [JsonConverter(typeof(JsonStringEnumConverter))]
7 | public enum BookStatus
8 | {
9 | [Description("Aguardando aprovação")]
10 | WaitingApproval,// Status inicial
11 |
12 | [Description("Disponível")]
13 | Available,// Status é usado quando o admin aprova o livro
14 |
15 | [Description("Aguardando decisão do doador")]
16 | AwaitingDonorDecision,// Status para quando já expirou a qt de dias que o livro pode ficar na vitrine tendo pessoas ja interessadas em ganha-lo e o doador ainda nao escolheu o ganhador
17 |
18 | [Description("Aguardando envio")]
19 | WaitingSend,// Status é usado a partir do momento que o doador escolhe um ganhador
20 |
21 | [Description("Enviado")]
22 | Sent,// Status para quando o doador envia o livro
23 |
24 | [Description("Recebido")]
25 | Received,// Status para quando o ganhador recebe o livro
26 |
27 | [Description("Cancelado")]
28 | Canceled
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/BookUserMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class BookUserMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 |
12 | entityBuilder
13 | .HasKey(bu => new { bu.Id, bu.BookId, bu.UserId });
14 |
15 | entityBuilder
16 | .HasOne(bu => bu.Book)
17 | .WithMany(b => b.BookUsers)
18 | .HasForeignKey(bu => bu.BookId);
19 |
20 | entityBuilder
21 | .HasOne(bu => bu.User)
22 | .WithMany(u => u.BookUsers)
23 | .HasForeignKey(bu => bu.UserId);
24 |
25 | entityBuilder.Property(bu => bu.Note)
26 | .HasMaxLength(2000);
27 |
28 | entityBuilder.Property(bu => bu.Reason)
29 | .HasMaxLength(2000);
30 |
31 | entityBuilder.Property(bu => bu.NickName)
32 | .HasMaxLength(64);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/ViewModels/UserVM.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System;
3 |
4 | namespace ShareBook.Api.ViewModels
5 | {
6 | public class UserVM : BaseViewModel
7 | {
8 |
9 | public string Name { get; set; }
10 |
11 | public string Email { get; set; }
12 |
13 | public string Linkedin { get; set; }
14 |
15 | public string Instagram { get; set; }
16 |
17 | public string Phone { get; set; }
18 |
19 | public Address Address { get; set; }
20 |
21 | public bool AllowSendingEmail { get; set; }
22 | }
23 |
24 | public class UserFacilitatorVM
25 | {
26 |
27 | public Guid Id { get; set; }
28 |
29 | public string Name { get; set; }
30 |
31 | public string Email { get; set; }
32 |
33 | public string Linkedin { get; set; }
34 |
35 | public string Instagram { get; set; }
36 |
37 | public string Phone { get; set; }
38 |
39 | public Address Address { get; set; }
40 | }
41 |
42 | public class MainUsersVM
43 | {
44 | public UserVM Donor { get; set; }
45 | public UserVM Facilitator { get; set; }
46 | public UserVM Winner { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/AddressMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class AddressMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 | entityBuilder.Property(t => t.PostalCode)
12 | .HasMaxLength(15);
13 |
14 | entityBuilder.Property(t => t.Neighborhood)
15 | .HasMaxLength(50);
16 |
17 | entityBuilder.Property(t => t.Complement)
18 | .HasMaxLength(50);
19 |
20 | entityBuilder.Property(t => t.Country)
21 | .HasMaxLength(50);
22 |
23 | entityBuilder.Property(t => t.City)
24 | .HasMaxLength(50);
25 |
26 | entityBuilder.Property(t => t.State)
27 | .HasMaxLength(30);
28 |
29 | entityBuilder.Property(t => t.Street)
30 | .HasMaxLength(80);
31 |
32 | entityBuilder.Property(t => t.Number)
33 | .HasMaxLength(10);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Controllers/ContactUsController.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using Microsoft.AspNetCore.Cors;
3 | using Microsoft.AspNetCore.Mvc;
4 | using ShareBook.Api.ViewModels;
5 | using ShareBook.Domain;
6 | using ShareBook.Domain.Common;
7 | using ShareBook.Service;
8 | using System.Threading.Tasks;
9 |
10 | namespace ShareBook.Api.Controllers
11 | {
12 | [Route("api/[controller]")]
13 | [EnableCors("AllowAllHeaders")]
14 | public class ContactUsController : ControllerBase
15 | {
16 | private readonly IContactUsService _contactUsService;
17 | private readonly IMapper _mapper;
18 |
19 | public ContactUsController(IContactUsService contactUsService,
20 | IMapper mapper)
21 | {
22 | _contactUsService = contactUsService;
23 | _mapper = mapper;
24 | }
25 |
26 | [HttpPost("SendMessage")]
27 | public async Task> SendMessageAsync([FromBody]ContactUsVM contactUsVM)
28 | {
29 | var contactUS = _mapper.Map(contactUsVM);
30 |
31 | return await _contactUsService.SendContactUsAsync(contactUS, contactUsVM?.RecaptchaReactive);
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Exceptions/SharebookException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ShareBook.Domain.Exceptions
5 | {
6 | public class ShareBookException : Exception
7 | {
8 | public static Dictionary ErrorMessages = new Dictionary()
9 | {
10 | { Error.NotAuthorized, "O usuário precisa estar logado para efetuar essa ação." },
11 | { Error.Forbidden, "Usuário não tem as permissões necessárias para efetuar esta ação." },
12 | { Error.NotFound, "Entidade não encontrada. Por favor, verifique." }
13 | };
14 |
15 | public enum Error
16 | {
17 | BadRequest = 400,
18 | NotAuthorized = 401,
19 | Forbidden = 403,
20 | NotFound = 404
21 | }
22 |
23 | public Error ErrorType { get; set; }
24 |
25 | public ShareBookException(string message) : this(Error.BadRequest, message) { }
26 | public ShareBookException(Error error) : this(error, ErrorMessages[error]) { }
27 | public ShareBookException(Error error, string message) : base(message)
28 | {
29 | ErrorType = error;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Integration/ShareBook.Test.Integration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/Validators/ContactUsValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 |
3 | namespace ShareBook.Domain.Validators
4 | {
5 | public class ContactUsValidator : AbstractValidator
6 | {
7 | #region Messages
8 | public const string NAME_REQUIRED = "Nome é obrigatório";
9 | public const string EMAIL_REQUIRED = "Email é obrigatório";
10 | public const string EMAIL_FORMAT = "O formato do email está inválido";
11 | public const string PHONE_REQUIRED = "Telefone é obrigatório";
12 | public const string MESSAGE_REQUIRED = "Mensagem é obrigatória";
13 | #endregion
14 |
15 | public ContactUsValidator()
16 | {
17 | RuleFor(c => c.Name)
18 | .NotEmpty()
19 | .WithMessage(NAME_REQUIRED);
20 |
21 | RuleFor(c => c.Email)
22 | .EmailAddress()
23 | .WithMessage(EMAIL_FORMAT)
24 | .NotEmpty()
25 | .WithMessage(EMAIL_REQUIRED);
26 |
27 | RuleFor(c => c.Phone)
28 | .NotEmpty()
29 | .WithMessage(PHONE_REQUIRED);
30 |
31 | RuleFor(c => c.Message)
32 | .NotEmpty()
33 | .WithMessage(MESSAGE_REQUIRED);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/User/IUserService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Domain.Common;
3 | using ShareBook.Domain.DTOs;
4 | using ShareBook.Service.Generic;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Threading.Tasks;
8 |
9 | namespace ShareBook.Service
10 | {
11 | public interface IUserService : IBaseService
12 | {
13 | Task> AuthenticationByEmailAndPasswordAsync(User user);
14 | bool IsValidPassword(User user, string decryptedPass);
15 | new Task> UpdateAsync(User user);
16 | Task> ValidOldPasswordAndChangeUserPasswordAsync(User user, string newPassword);
17 | Task> ChangeUserPasswordAsync(User user, string newPassword);
18 | Task GenerateHashCodePasswordAndSendEmailToUserAsync(string email);
19 | Task ConfirmHashCodePasswordAsync(string hashCodePassword);
20 | IList GetFacilitators(Guid userIdDonator);
21 | IList GetAdmins();
22 | Task> GetBySolicitedBookCategoryAsync(Guid bookCategoryId);
23 | Task GetStatsAsync(Guid? userId);
24 | Task> InsertAsync(RegisterUserDTO userDto);
25 | Task ParentAprovalAsync(string parentHashCodeAproval);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "shell",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/ShareBook/ShareBook.Api/ShareBook.Api.csproj",
11 | "/property:GenerateFullPaths=true"
12 | ],
13 | "problemMatcher": "$msCompile"
14 | },
15 | {
16 | "label": "publish",
17 | "command": "dotnet",
18 | "type": "process",
19 | "args": [
20 | "publish",
21 | "${workspaceFolder}/ShareBook/ShareBook.Api/ShareBook.Api.csproj",
22 | "/property:GenerateFullPaths=true",
23 | "/consoleloggerparameters:NoSummary"
24 | ],
25 | "problemMatcher": "$msCompile"
26 | },
27 | {
28 | "label": "watch",
29 | "command": "dotnet",
30 | "type": "process",
31 | "args": [
32 | "watch",
33 | "run",
34 | "--project",
35 | "${workspaceFolder}/ShareBook/ShareBook.Api/ShareBook.Api.csproj",
36 | ],
37 | "problemMatcher": "$msCompile"
38 | }
39 | ]
40 | }
--------------------------------------------------------------------------------
/ShareBook/Sharebook.Jobs/Jobs/6 - MailSupressListUpdate.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Domain.Enums;
3 | using ShareBook.Repository;
4 | using ShareBook.Service;
5 | using System;
6 | using System.Threading.Tasks;
7 |
8 | namespace Sharebook.Jobs;
9 |
10 | public class MailSupressListUpdate : GenericJob, IJob
11 | {
12 | private readonly IEmailService _emailService;
13 |
14 | public MailSupressListUpdate(
15 | IJobHistoryRepository jobHistoryRepo,
16 | IEmailService emailService) : base(jobHistoryRepo)
17 | {
18 |
19 | JobName = "MailSupressListUpdate";
20 | Description = @"Atualiza a lista de emails suprimidos. Essa lista serve para manter boa reputação do nosso
21 | mailling. Além de ser um requisito da AWS.";
22 | Interval = Interval.Dayly;
23 | Active = true;
24 | BestTimeToExecute = new TimeSpan(2, 0, 0);
25 |
26 | _emailService = emailService;
27 | }
28 |
29 | public override async Task WorkAsync()
30 | {
31 | var log = await _emailService.ProcessBounceMessagesAsync();
32 |
33 | return new JobHistory()
34 | {
35 | JobName = JobName,
36 | IsSuccess = true,
37 | Details = String.Join("\n", log)
38 | };
39 | }
40 | }
41 |
42 |
43 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/BookUser/IBookUserService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Domain.Common;
3 | using ShareBook.Domain.DTOs;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace ShareBook.Service
9 | {
10 | public interface IBookUserService
11 | {
12 | Task InsertAsync(Guid bookId, string reason);
13 |
14 | Task> GetGranteeUsersByBookIdAsync(Guid bookId);
15 |
16 | Task> GetRequestersListAsync(Guid bookId);
17 |
18 | Task DonateBookAsync(Guid bookId, Guid userId, string note);
19 |
20 | Task DeniedBookUsersAsync(Guid bookId);
21 |
22 | Task> GetRequestsByUserAsync(int page, int items);
23 |
24 | ///
25 | /// Comunicar os interessados não escolhidos sobre a finalização da doação. e quem ganhou o livro
26 | ///
27 | ///
28 | Task NotifyInterestedAboutBooksWinnerAsync(Guid bookId);
29 |
30 | Task> CancelAsync(BookCancelationDTO dto);
31 |
32 | Task InformTrackingNumberAsync(Guid bookId, string trackingNumber);
33 | Task GetRequestAsync(Guid requestId);
34 | Task CancelRequestAsync(BookUser request);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookReceivedTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Livro Recebido - Sharebook
7 |
8 |
9 |
10 | Olá {User.Name}
11 |
12 |
13 | O livro {Book.Title} foi Recebido.
14 |
15 | Detalhes do livro:
16 |
17 | Livro: {Book.Title}
18 | Autor: {Book.Author}
19 | Ganhador: {WinnerName}
20 |
21 |
22 |
23 | Parabéns por ter completado sua doação com sucesso. Você fez diferença na vida de uma pessoa.
24 |
25 |
26 |
27 | Atenciosamente,
28 |
29 | Sharebook team - Compartilhando conhecimento
30 | Siga-nos no instagram:
31 | @sharebook.com.br
32 |
33 |
34 | Curta nossa fanpage pra ficar por dentro das novidades:
35 | https://www.linkedin.com/company/sharebook-br/
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Meetup/Dto/MeetupParticipantDTO.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ShareBook.Service.Dto
9 | {
10 | public class MeetupParticipantDto
11 | {
12 | public List Data { get; set; }
13 | public Pagination Pagination { get; set; }
14 | }
15 |
16 | public class Data
17 | {
18 | [JsonProperty("event_id")]
19 | public int EventId { get; set; }
20 | [JsonProperty("first_name")]
21 | public string FirstName { get; set; }
22 | [JsonProperty("last_name")]
23 | public string LastName { get; set; }
24 | public string Email { get; set; }
25 | }
26 |
27 | public class Pagination
28 | {
29 | [JsonProperty("has_next")]
30 | public bool HasNext { get; set; }
31 | [JsonProperty("hast_prev")]
32 | public bool HasPrev { get; set; }
33 | public int Quantity { get; set; }
34 | public int Offset { get; set; }
35 | public int Page { get; set; }
36 | [JsonProperty("page_size")]
37 | public int PageSize { get; set; }
38 | [JsonProperty("total_page")]
39 | public int TotalPage { get; set; }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookNoticeInterestedTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Sharebook - Você solicitou um livro
7 |
8 |
9 | Sharebook - Você solicitou um livro
10 |
11 |
12 | Olá {NameInterested} ,
13 |
14 |
15 |
16 | Você solicitou o livro {NameBook} .
17 | Aguarde até o dia {ChooseDate} que será anunciado o ganhador. Boa sorte!
18 |
19 |
20 |
21 | Em caso de dúvidas fale com o Facilitador {NameFacilitator} .
22 |
23 |
24 | Whatsapp: {PhoneFacilitator}
25 | Email: {EmailFacilitator}
26 | LinkedIn: {LinkedinFacilitator}
27 |
28 |
29 |
30 | Atenciosamente, Sharebook Team
31 |
32 |
33 | Sharebook - Compartilhando conhecimento
34 |
35 | Siga-nos no instagram:
36 | @sharebook.com.br
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookCanceledNoticeUsersTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Resultado da doação do livro {book.Title}
7 |
8 |
9 |
10 |
11 |
12 | Olá,
13 |
14 | Aqui é o Sharebot do time Sharebook. Blz?
15 |
16 | Obrigado por ter demonstrado interesse no livro "{book.Title} ". Mas infelizmente você não foi escolhido(a) como ganhador(a). =(
17 |
18 | Por favor não desanime. Toda semana entram muitos livros novos e certamente um dia vc vai ganhar o seu. Ou até mesmo esse livro pode ser doado de novo. Blz?
19 |
20 |
21 |
22 |
23 | Atenciosamente,
24 |
25 | Sharebook team - Compartilhando conhecimento
26 | Siga-nos no instagram:
27 | @sharebook.com.br
28 |
29 |
30 | Curta nossa fanpage pra ficar por dentro das novidades:
31 | https://www.linkedin.com/company/sharebook-br/
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/ShareBook.Test.Unit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/AccessHistory.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using ShareBook.Domain.Enums;
3 |
4 | using System;
5 | using System.ComponentModel.DataAnnotations.Schema;
6 |
7 | namespace ShareBook.Domain
8 | {
9 | public class AccessHistory : BaseEntity
10 | {
11 | protected AccessHistory() { }
12 |
13 | public AccessHistory(string visitorName, VisitorProfile profile) {
14 | ChangeVisitorName(visitorName);
15 | ChangeProfile(profile);
16 | }
17 |
18 | public AccessHistory(Guid id, string visitorName, VisitorProfile profile) : this(visitorName, profile) {
19 | UserId = id;
20 | }
21 |
22 | public Guid? UserId { get; private set; }
23 | [ForeignKey("UserId")]
24 | public User User { get; private set; } //Visitante do perfil
25 | public string VisitorName { get; private set; }
26 | public VisitorProfile Profile { get; private set; }
27 |
28 | public void ChangeVisitorName(string name)
29 | {
30 | if (string.IsNullOrEmpty(name)) return;
31 |
32 | VisitorName = name;
33 | }
34 |
35 | public void ChangeProfile(VisitorProfile newProfile)
36 | {
37 | if (Profile.Equals(newProfile)) return;
38 |
39 | Profile = newProfile;
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Integration/Tests/BookTests/BookTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using Newtonsoft.Json;
3 | using ShareBook.Api.ViewModels;
4 |
5 | namespace ShareBook.Test.Integration.Tests.BookTests;
6 |
7 | [Collection(nameof(ShareBookTestsFixture))]
8 | public class BookTests
9 | {
10 | private readonly ShareBookTestsFixture _fixture;
11 |
12 | public BookTests(ShareBookTestsFixture fixture)
13 | {
14 | _fixture = fixture;
15 | }
16 |
17 | [Fact]
18 | public async Task AvailableBooks_All()
19 | {
20 | var response = await _fixture.ShareBookApiClient.GetAsync("api/book/AvailableBooks");
21 |
22 | response.Should().NotBeNull();
23 | response.StatusCode.Should().Be(HttpStatusCode.OK);
24 | string responseAsString = await response.Content.ReadAsStringAsync();
25 | responseAsString.Should().NotBeNullOrWhiteSpace();
26 | IList? books = JsonConvert.DeserializeObject>(responseAsString);
27 | books.Should().NotBeNullOrEmpty();
28 | books!.Count.Should().Be(22);
29 |
30 | books!.All(i =>
31 | !string.IsNullOrWhiteSpace(i.Title)
32 | && !string.IsNullOrWhiteSpace(i.Author)
33 | && !string.IsNullOrWhiteSpace(i.Slug)
34 | && i.CategoryId != default
35 | ).Should().BeTrue();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------
1 | # CLAUDE.md - Memória de Longo Prazo
2 |
3 | ## 📋 Informações do Projeto 'Sharebook Api'
4 |
5 | Sharebook é nosso app livre e gratuito para doação de livros. Nosso backend é feito em .NET 8, com arquitetura limpa e testes unitários. O frontend é em Angular.
6 |
7 | ### Sobre o Desenvolvedor Raffa
8 | - Clean Code + Clean Architecture: modular, coeso, com separação clara de responsabilidades.
9 | - Valoriza boa organização do projeto, com bons nomes de pastas e arquivos. Vale a pena investir tempo nisso.
10 | - Valoriza nomes significativos e expressivos para componentes, hooks e funções. Vale a pena investir tempo nisso.
11 | - Odeia retrabalho — antes de criar, sempre verifica se já não existe pronto e gratuito.
12 | - Preza por segurança — validação e autorização bem feitas não são opcionais.
13 | - Gosta de impressionar — seja o cliente, o time ou a diretoria, sempre com um toque extra.
14 | - Não gosta de bajulação. Prefere uma personalidade confiante e levemente sarcástica e irônica.
15 | - Caso a tarefa não seja trivial, explique o seu plano antes de colocar a mão na massa.
16 |
17 | ### Dicas de ouro
18 | - Leve em consideração que o claude está rodando no powershell
19 | - Quando o usuário falar pra olhar a colinha, analise o arquivo "colinha.txt" na raíz.
20 | - Quando o usuário falar pra olhar o print 142, olhe o arquivo "C:\Users\brnra019\Documents\Lightshot\Screenshot_142.png"
21 |
22 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Filters/AuthorizationFilter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Filters;
2 | using ShareBook.Domain.Exceptions;
3 | using ShareBook.Service.Authorization;
4 | using System.Linq;
5 | using System.Security.Claims;
6 |
7 | namespace ShareBook.Api.Filters
8 | {
9 | public class AuthorizationFilter : ActionFilterAttribute
10 | {
11 | public Permissions.Permission[] NecessaryPermissions { get; set; }
12 |
13 | public AuthorizationFilter(params Permissions.Permission[] permissions)
14 | {
15 | NecessaryPermissions = permissions;
16 | }
17 |
18 | public override void OnActionExecuting(ActionExecutingContext context)
19 | {
20 | var user = context.HttpContext.User;
21 |
22 | if (user == null)
23 | throw new ShareBookException(ShareBookException.Error.NotAuthorized);
24 |
25 | var isAdministrator = ((ClaimsIdentity)user.Identity).Claims
26 | .Any(x => x.Type == ClaimsIdentity.DefaultRoleClaimType.ToString() && x.Value == Domain.Enums.Profile.Administrator.ToString());
27 |
28 | if (NecessaryPermissions.Any(x => Permissions.AdminPermissions.Contains(x)) && !isAdministrator)
29 | throw new ShareBookException(ShareBookException.Error.Forbidden);
30 |
31 | base.OnActionExecuting(context);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Controllers/Generic/BaseDeleteController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Authorization;
2 | using Microsoft.AspNetCore.Cors;
3 | using Microsoft.AspNetCore.Mvc;
4 | using ShareBook.Api.Filters;
5 | using ShareBook.Api.ViewModels;
6 | using ShareBook.Domain.Common;
7 | using ShareBook.Service.Generic;
8 | using System;
9 | using System.Threading.Tasks;
10 |
11 | namespace ShareBook.Api.Controllers
12 | {
13 | public class BaseDeleteController : BaseDeleteController
14 | where T : BaseEntity
15 | {
16 | public BaseDeleteController(IBaseService service) : base(service) { }
17 | }
18 |
19 | public class BaseDeleteController : BaseDeleteController
20 | where T : BaseEntity
21 | where R : BaseViewModel
22 | {
23 | public BaseDeleteController(IBaseService service) : base(service) { }
24 | }
25 |
26 | [GetClaimsFilter]
27 | [EnableCors("AllowAllHeaders")]
28 | public class BaseDeleteController : BaseController
29 | where T : BaseEntity
30 | where R : IIdProperty
31 | where A : class
32 | {
33 |
34 | public BaseDeleteController(IBaseService service) : base(service) { }
35 |
36 | [Authorize("Bearer")]
37 | [HttpDelete("{id}")]
38 | public async Task Delete(Guid id) => await _service.DeleteAsync(id);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/DateTime/DateTimeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace ShareBook.Helper
5 | {
6 | static public class DateTimeHelper
7 | {
8 | static private readonly string SaoPauloTimezoneId = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
9 | ? "E. South America Standard Time"
10 | : "America/Sao_Paulo";
11 |
12 | // hora agora.
13 | static public TimeSpan GetTimeNowSaoPaulo()
14 | {
15 | var now = TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(SaoPauloTimezoneId));
16 | var today = new DateTime(now.Year, now.Month, now.Day);
17 | return now - today;
18 | }
19 |
20 | // data hora agora.
21 | static public DateTime GetDateTimeNowSaoPaulo() => TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(SaoPauloTimezoneId));
22 |
23 | // data-hora de hoje a meia noite.
24 | static public DateTime GetTodaySaoPaulo()
25 | {
26 | var nowSP = GetDateTimeNowSaoPaulo();
27 | var todaySP = new DateTime(nowSP.Year, nowSP.Month, nowSP.Day, 0, 0, 0);
28 | return todaySP;
29 | }
30 |
31 | static public DateTime ConvertDateTimeSaoPaulo(DateTime d) => TimeZoneInfo.ConvertTime(d, TimeZoneInfo.FindSystemTimeZoneById(SaoPauloTimezoneId));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Integration/Tests/CategoryTests/CategoryTests.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Common;
4 | using System.Net;
5 |
6 | namespace ShareBook.Test.Integration.Tests.CategoryTests;
7 |
8 | [Collection(nameof(ShareBookTestsFixture))]
9 | public class CategoryTests
10 | {
11 | private readonly ShareBookTestsFixture _fixture;
12 |
13 | public CategoryTests(ShareBookTestsFixture fixture)
14 | {
15 | _fixture = fixture;
16 | }
17 |
18 | [Fact]
19 | public async Task GetCategories()
20 | {
21 | var response = await _fixture.ShareBookApiClient.GetAsync("api/category");
22 |
23 | response.Should().NotBeNull();
24 | response.StatusCode.Should().Be(HttpStatusCode.OK);
25 | string responseAsString = await response.Content.ReadAsStringAsync();
26 | responseAsString.Should().NotBeNullOrWhiteSpace();
27 | PagedList? categories = JsonConvert.DeserializeObject>(responseAsString);
28 | categories.Should().NotBeNull();
29 | categories!.Items.Should().NotBeNull();
30 | categories.Items.Count.Should().Be(10);
31 | categories.ItemsPerPage.Should().Be(50);
32 | categories.Page.Should().Be(1);
33 |
34 | categories.Items.All(i =>
35 | !string.IsNullOrWhiteSpace(i.Name)
36 | && i.Id != default
37 | ).Should().BeTrue();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Integration/Setup/ShareBookWebAppFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.AspNetCore.Mvc.Testing;
3 | using Microsoft.AspNetCore.TestHost;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Hosting;
7 | using ShareBook.Api;
8 | using ShareBook.Repository;
9 |
10 | namespace ShareBook.Test.Integration.Setup;
11 |
12 | public class ShareBookWebAppFactory : WebApplicationFactory
13 | {
14 | protected override IHostBuilder? CreateHostBuilder()
15 | {
16 | return Host.CreateDefaultBuilder()
17 | .ConfigureWebHostDefaults(webBuilder =>
18 | {
19 | webBuilder.UseStartup();
20 | });
21 | }
22 |
23 | protected override void ConfigureWebHost(IWebHostBuilder builder)
24 | {
25 | base.ConfigureWebHost(builder);
26 | Startup.IgnoreMigrations = true;
27 |
28 | builder.ConfigureTestServices(services =>
29 | {
30 | var dbOptions = services.FirstOrDefault(x => x.ServiceType == typeof(DbContextOptions));
31 | if (dbOptions != null)
32 | services.Remove(dbOptions);
33 |
34 | services.AddDbContext(options =>
35 | {
36 | options.UseInMemoryDatabase("ShareBookInMemoryDb");
37 | });
38 | });
39 | }
40 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Meetup/MeetupRepository.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Common;
4 | using ShareBook.Repository.Repository;
5 | using System;
6 | using System.Linq;
7 | using System.Linq.Expressions;
8 | using System.Threading.Tasks;
9 |
10 | namespace ShareBook.Repository
11 | {
12 | public class MeetupRepository : RepositoryGeneric, IMeetupRepository
13 | {
14 | public MeetupRepository(ApplicationDbContext context) : base(context)
15 | {
16 |
17 | }
18 |
19 | public override async Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage, IncludeList includes)
20 | {
21 | var skip = (page - 1) * itemsPerPage;
22 | var query = _dbSet.AsQueryable();
23 |
24 | query = query.Where(filter);
25 | var total = await query.CountAsync();
26 | var result = await query
27 | .OrderByDescending(order)
28 | .Skip(skip)
29 | .Take(itemsPerPage)
30 | .ToListAsync();
31 |
32 | return new PagedList()
33 | {
34 | Page = page,
35 | ItemsPerPage = itemsPerPage,
36 | TotalItems = total,
37 | Items = result
38 | };
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/ContactUs/ContactUsService.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Common;
4 | using ShareBook.Service.Recaptcha;
5 | using System.Threading.Tasks;
6 |
7 | namespace ShareBook.Service
8 | {
9 | public class ContactUsService : IContactUsService
10 | {
11 | readonly IContactUsEmailService _contactUsEmailService;
12 | readonly IValidator _validator;
13 | readonly IRecaptchaService _recaptchaService;
14 | public ContactUsService(IContactUsEmailService contactUsEmailService, IValidator validator, IRecaptchaService recaptchaService)
15 | {
16 | _contactUsEmailService = contactUsEmailService;
17 | _validator = validator;
18 | _recaptchaService = recaptchaService;
19 | }
20 | public async Task> SendContactUsAsync(ContactUs contactUs, string recaptchaReactive)
21 | {
22 |
23 | var result = new Result(_validator.Validate(contactUs));
24 |
25 | Result resultRecaptcha = _recaptchaService.SimpleValidationRecaptcha(recaptchaReactive);
26 | if (!resultRecaptcha.Success)
27 | result.Messages.AddRange(resultRecaptcha.Messages);
28 |
29 | if (!result.Success)
30 | return result;
31 |
32 | await _contactUsEmailService.SendEmailContactUsAsync(contactUs);
33 |
34 | return result;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/ApplicationDbContextFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Design;
3 | using Microsoft.Extensions.Configuration;
4 | using System.IO;
5 |
6 | namespace ShareBook.Repository;
7 |
8 | public class ApplicationDbContextFactory : IDesignTimeDbContextFactory
9 | {
10 | public ApplicationDbContext CreateDbContext(string[] args)
11 | {
12 | var configuration = new ConfigurationBuilder()
13 | .SetBasePath(Directory.GetCurrentDirectory())
14 | .AddJsonFile("appsettings.json")
15 | .AddJsonFile("appsettings.Development.json", optional: true)
16 | .Build();
17 |
18 | var optionsBuilder = new DbContextOptionsBuilder();
19 | var dbProvider = configuration["DatabaseProvider"]?.ToLower() ?? "sqlserver";
20 |
21 | switch (dbProvider)
22 | {
23 | case "postgres":
24 | optionsBuilder.UseNpgsql(configuration.GetConnectionString("PostgresConnection"));
25 | break;
26 |
27 | case "sqlite":
28 | optionsBuilder.UseSqlite(configuration.GetConnectionString("SqliteConnection"));
29 | break;
30 |
31 | default:
32 | optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
33 | break;
34 | }
35 |
36 | return new ApplicationDbContext(optionsBuilder.Options);
37 | }
38 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/Validators/ContactUsValidatorTests.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation.Results;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Validators;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Xunit;
10 |
11 | namespace ShareBook.Test.Unit.Validators
12 | {
13 | public class ContactUsValidatorTests
14 | {
15 | ContactUsValidator contactUsValidator = new ContactUsValidator();
16 |
17 | [Fact]
18 | public void ValidEntities()
19 | {
20 | ContactUs contactUs = new ContactUs
21 | {
22 | Email = "joao@sharebook.com.br",
23 | Message = "Essa mensagem é obrigatória",
24 | Name = "Joao",
25 | Phone = "4499988-7766",
26 | };
27 | ValidationResult result = contactUsValidator.Validate(contactUs);
28 | Assert.True(result.IsValid);
29 | }
30 |
31 | [Fact]
32 | public void InvalidEmail()
33 | {
34 | ContactUs contactUs = new ContactUs
35 | {
36 | Email = "joaoarebook.com.br",
37 | Message = "Essa mensagem é obrigatória",
38 | Name = "Joao",
39 | Phone = "4499988-7766",
40 | };
41 |
42 | ValidationResult result = contactUsValidator.Validate(contactUs);
43 | Assert.False(result.IsValid);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/LateDonationNotification.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SHAREBOOK - STATUS DO DIA.
6 |
7 |
8 |
9 | Bom dia! Segue o status de hoje:
10 |
11 |
12 |
13 | Aguardando aprovação: {totalWaitingApproval}
14 | Em atraso: {totalLate}
15 | Concluídas: {totalOk}
16 |
17 |
18 | Cada doação concluída, faz uma pessoa feliz. Bora Pra cima!
19 |
20 | {htmlTable}
21 |
22 | Por favor, faça contato com os doadores os ajude a concluir sua doação. Isso é muito importante para que nossos usuários tenham uma boa experiência com nossa plataforma. Afinal ninguém gosta de atrasos, certo?
23 |
24 |
25 |
26 |
27 | Atenciosamente,
28 |
29 | Sharebook team - Compartilhando conhecimento
30 | Siga-nos no instagram:
31 | @sharebook.com.br
32 |
33 |
34 | Curta nossa fanpage pra ficar por dentro das novidades:
35 | https://www.linkedin.com/company/sharebook-br/
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookNoticeDeclinedUsersTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Resultado da doação do livro {BookTitle}
7 |
8 |
9 |
10 |
11 |
12 | Olá,
13 |
14 | Aqui é o Sharebot do time Sharebook. Blz?
15 |
16 | Obrigado por ter demonstrado interesse no livro "{BookTitle} ". Mas infelizmente o doador escolheu outro(a) ganhador(a). =(
17 |
18 | Sabemos que essa não era a notícia que você gostaria de receber. O doador leu com carinho todos os pedidos e escolheu aquele que parecia mais precisar e mais interessado.
19 |
20 | Por favor não desanime. Toda semana entram muitos livros novos e certamente um dia vc vai ganhar o seu. Ou até mesmo esse livro pode ser doado de novo. Blz?
21 |
22 |
23 |
24 |
25 | Atenciosamente,
26 |
27 | Sharebook team - Compartilhando conhecimento
28 | Siga-nos no instagram:
29 | @sharebook.com.br
30 |
31 |
32 | Curta nossa fanpage pra ficar por dentro das novidades:
33 | https://www.linkedin.com/company/sharebook-br/
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Domain/MailBounce.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain.Common;
2 | using System.Text.RegularExpressions;
3 |
4 | namespace ShareBook.Domain;
5 |
6 | public class MailBounce: BaseEntity
7 | {
8 | public string? Email { get; set; }
9 | public string? Subject { get; set; }
10 | public string? Body { get; set; }
11 | public string? ErrorCode { get; set; }
12 | public bool IsSoft { get; set; } = false;
13 | public bool IsBounce { get; set; } = false;
14 |
15 | public MailBounce(string subject, string body)
16 | {
17 | Subject = subject;
18 | Body = body;
19 |
20 | ExtractFromBody();
21 | }
22 |
23 | private void ExtractFromBody()
24 | {
25 | if (string.IsNullOrEmpty(Body)) return;
26 |
27 | // tenta extrair o email de destino original do corpo do email
28 | string pattern = @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
29 | Match match = Regex.Match(Body, pattern);
30 | Email = match.Success ? match.Value : "";
31 |
32 | // Check if email body contains an error code
33 | var errorCodeMatch = Regex.Match(Body, @"Remote Server returned: '(\d{3})");
34 |
35 | if (errorCodeMatch.Success)
36 | {
37 | IsBounce = true;
38 | ErrorCode = errorCodeMatch.Groups.Count == 2 ? errorCodeMatch.Groups[1].Value : "";
39 |
40 | if (ErrorCode.StartsWith("4"))
41 | {
42 | // Soft bounce
43 | IsSoft = true;
44 | }
45 | }
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/ShareBook/Sharebook.Jobs/Jobs/4 - MeetupSearch.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Repository;
2 | using ShareBook.Service;
3 | using ShareBook.Domain.Enums;
4 | using System;
5 | using ShareBook.Domain;
6 | using ShareBook.Domain.Exceptions;
7 | using Microsoft.Extensions.Configuration;
8 | using System.Threading.Tasks;
9 |
10 | namespace Sharebook.Jobs;
11 |
12 | public class MeetupSearch : GenericJob, IJob
13 | {
14 | private readonly IMeetupService _meetupService;
15 | private readonly IConfiguration _configuration;
16 | public MeetupSearch(IJobHistoryRepository jobHistoryRepo, IMeetupService meetupService, IConfiguration configuration) : base(jobHistoryRepo)
17 | {
18 | _meetupService = meetupService;
19 |
20 | JobName = "MeetupSearch";
21 | Description = "Atualiza a lista de Meetups do Sharebook com base no youtube.";
22 | Interval = Interval.Dayly;
23 | Active = true;
24 | BestTimeToExecute = new TimeSpan(1, 0, 0);
25 | _configuration = configuration;
26 | }
27 |
28 | public override async Task WorkAsync()
29 | {
30 | var meetupEnabled = bool.Parse(_configuration["MeetupSettings:IsActive"]);
31 | if(!meetupEnabled) throw new MeetupDisabledException("Serviço Meetup está desabilitado no appsettings.");
32 |
33 | var jobResult = await _meetupService.FetchMeetupsAsync();
34 |
35 | return new JobHistory()
36 | {
37 | JobName = JobName,
38 | IsSuccess = true,
39 | Details = string.Join("\n", jobResult)
40 | };
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Meetup/Dto/YoutubeDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ShareBook.Service.Dto;
5 |
6 | public class YoutubeDto
7 | {
8 | public string nextPageToken { get; set; }
9 | public string prevPageToken { get; set; }
10 | public PageInfo pageInfo { get; set; }
11 | public List- Items { get; set; }
12 | }
13 | public class PageInfo
14 | {
15 | public int TotalResults { get; set; }
16 | public int ResultsPerPage { get; set; }
17 | }
18 |
19 | public class Item
20 | {
21 | public Id Id { get; set; }
22 | public Snippet Snippet { get; set; }
23 | }
24 |
25 | public class Id
26 | {
27 | public string Kind { get; set; }
28 | public string VideoId { get; set; }
29 | }
30 |
31 | public class Snippet
32 | {
33 | public DateTime PublishedAt { get; set; }
34 | public string ChannelId { get; set; }
35 | public string Title { get; set; }
36 | public string Description { get; set; }
37 | public ThumbnailsDto Thumbnails { get; set; }
38 | public string ChannelTitle { get; set; }
39 | public string LiveBroadcastContent { get; set; }
40 | public DateTime PublishTime { get; set; }
41 | }
42 |
43 | public class ThumbnailsDto
44 | {
45 | public ThumbnailDetailDto Default { get; set; }
46 | public ThumbnailDetailDto Medium { get; set; }
47 | public ThumbnailDetailDto High { get; set; }
48 | }
49 |
50 | public class ThumbnailDetailDto
51 | {
52 | public string Url { get; set; }
53 | public int Width { get; set; }
54 | public int Height { get; set; }
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/UtcContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
3 | using System;
4 |
5 | namespace ShareBook.Repository
6 | {
7 | public static class UtcContext
8 | {
9 | public static void SetUtcOnDatabase(this ApplicationDbContext context, ModelBuilder builder)
10 | {
11 | var dateTimeConverter = new ValueConverter
(
12 | v => v.ToUniversalTime(),
13 | v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
14 |
15 | var nullableDateTimeConverter = new ValueConverter(
16 | v => v.HasValue ? v.Value.ToUniversalTime() : v,
17 | v => v.HasValue ? DateTime.SpecifyKind(v.Value, DateTimeKind.Utc) : v);
18 |
19 | foreach (var entityType in builder.Model.GetEntityTypes())
20 | {
21 | if (entityType.IsKeyless)
22 | {
23 | continue;
24 | }
25 |
26 | foreach (var property in entityType.GetProperties())
27 | {
28 | if (property.ClrType == typeof(DateTime))
29 | {
30 | property.SetValueConverter(dateTimeConverter);
31 | }
32 | else if (property.ClrType == typeof(DateTime?))
33 | {
34 | property.SetValueConverter(nullableDateTimeConverter);
35 | }
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Controllers/MeetupController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Cors;
2 | using Microsoft.AspNetCore.Mvc;
3 | using ShareBook.Domain;
4 | using ShareBook.Domain.Common;
5 | using ShareBook.Service;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 |
10 | namespace ShareBook.Api.Controllers
11 | {
12 | [Route("api/[controller]")]
13 | [EnableCors("AllowAllHeaders")]
14 | public class MeetupController : ControllerBase
15 | {
16 | private readonly IMeetupService _meetupService;
17 | public MeetupController(IMeetupService meetupService)
18 | {
19 | _meetupService = meetupService;
20 | }
21 | [HttpGet]
22 |
23 | public async Task> GetAsync(int? page, int? pageSize, bool upcoming = false)
24 | {
25 | return await _meetupService.GetAsync(upcoming ? x => x.Active && x.StartDate > DateTime.Now : x => x.Active && x.StartDate <= DateTime.Now, x => x.StartDate, page ?? 1, pageSize ?? 10);
26 | }
27 |
28 | [HttpGet("{id}")]
29 | public async Task GetAsync(string id)
30 | {
31 | if (!Guid.TryParse(id, out var meetupId))
32 | BadRequest();
33 |
34 | var meetup = await _meetupService.FindAsync(x => x.Id == meetupId);
35 | return meetup != null ? Ok(meetup) : NotFound();
36 | }
37 |
38 | [HttpGet("Search")]
39 | public async Task> SearchAsync([FromQuery]string criteria)
40 | {
41 | return await _meetupService.SearchAsync(criteria);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Filters/ThrottleFilter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using Microsoft.AspNetCore.Mvc.Filters;
3 | using Microsoft.Extensions.Caching.Memory;
4 | using System;
5 | using System.Net;
6 |
7 | namespace ShareBook.Api.Filters
8 | {
9 | [AttributeUsage(AttributeTargets.Method)]
10 | public class ThrottleAttribute : ActionFilterAttribute
11 | {
12 | public string Name { get; set; }
13 | public int Seconds { get; set; }
14 | public string Message { get; set; }
15 | public bool VaryByIp { get; set; }
16 |
17 | private static MemoryCache Cache { get; } = new MemoryCache(new MemoryCacheOptions());
18 |
19 | public override void OnActionExecuting(ActionExecutingContext c)
20 | {
21 | var key = VaryByIp
22 | ? string.Concat(Name, "-", c.HttpContext.Request.HttpContext.Connection.RemoteIpAddress)
23 | : Name;
24 |
25 | if (!Cache.TryGetValue(key, out bool entry))
26 | {
27 | var cacheEntryOptions = new MemoryCacheEntryOptions()
28 | .SetAbsoluteExpiration(TimeSpan.FromSeconds(Seconds));
29 |
30 | Cache.Set(key, true, cacheEntryOptions);
31 | }
32 | else
33 | {
34 | if (string.IsNullOrEmpty(Message))
35 | Message = "You may only perform this action every {n} seconds.";
36 |
37 | c.Result = new ContentResult { Content = Message.Replace("{n}", Seconds.ToString()) };
38 | c.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/ClientVersionValidation/ClientVersionValidation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.RegularExpressions;
3 |
4 | namespace ShareBook.Helper
5 | {
6 | static public class ClientVersionValidation
7 | {
8 | static public bool IsValidVersion(string version, string minVersion)
9 | {
10 | try
11 | {
12 | (int majorMin, int minorMin, int patchMin) = VersionDeconstructor(minVersion);
13 | (int major, int minor, int patch) = VersionDeconstructor(version);
14 |
15 | if (major < majorMin) return false;
16 | if (major > majorMin) return true;
17 |
18 | if (minor < minorMin) return false;
19 | if (minor > minorMin) return true;
20 |
21 | if (patch < patchMin) return false;
22 | else return true;
23 | }
24 | catch (Exception)
25 | {
26 | return false;
27 | }
28 |
29 | }
30 |
31 | static private Tuple VersionDeconstructor(string version)
32 | {
33 | string pattern = @"v([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,2})$";
34 | Regex rg = new Regex(pattern);
35 |
36 | MatchCollection matches = rg.Matches(version);
37 |
38 | if (matches.Count != 1) throw new Exception("Formato inválido");
39 |
40 | var major = int.Parse(matches[0].Groups[1].Value);
41 | var minor = int.Parse(matches[0].Groups[2].Value);
42 | var patch = int.Parse(matches[0].Groups[3].Value);
43 |
44 | return Tuple.Create(major, minor, patch);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/BookMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class BookMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 | entityBuilder.HasKey(t => t.Id);
12 |
13 | entityBuilder.Property(t => t.UserId);
14 |
15 | entityBuilder.Property(t => t.UserIdFacilitator);
16 |
17 | entityBuilder.Property(t => t.Author)
18 | .HasMaxLength(200)
19 | .IsRequired();
20 |
21 | entityBuilder.Property(t => t.Title)
22 | .HasMaxLength(200)
23 | .IsRequired();
24 |
25 | entityBuilder.Property(t => t.ImageSlug)
26 | .HasMaxLength(100)
27 | .IsRequired();
28 |
29 | entityBuilder.Property(t => t.Slug)
30 | .HasMaxLength(100);
31 |
32 | entityBuilder.Property(t => t.Synopsis)
33 | .HasMaxLength(2000);
34 |
35 | entityBuilder.Property(t => t.FacilitatorNotes)
36 | .HasMaxLength(2000);
37 |
38 | entityBuilder.Ignore(t => t.ImageBytes);
39 |
40 | entityBuilder.Ignore(t => t.ImageUrl);
41 |
42 | entityBuilder.Ignore(t => t.ImageName);
43 |
44 | entityBuilder.Ignore(t => t.EBookPdfBytes);
45 |
46 | entityBuilder.HasOne(t => t.User);
47 |
48 | entityBuilder.HasOne(t => t.UserFacilitator);
49 |
50 | entityBuilder.HasOne(t => t.Category);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/BookTrackingNumberNoticeWinnerTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | SHAREBOOK - Livro postado
7 |
8 |
9 |
10 |
11 |
12 | Olá,
13 |
14 | Temos uma notícia boa.
15 | O livro {book.Title} foi postado e você pode acompanhar o rastreio no site
16 | dos Correios com o código
17 | {book.TrackingNumber} .
18 |
19 |
20 |
21 |
22 | Em caso de dúvidas ou atraso não hesite em falar com o Facilitador. Nós queremos muito que o livro
23 | chegue até você o mais rápido possível.
24 |
25 |
26 |
27 | Nome do Facilitador: {NameFacilitator}
28 | LinkedIn: {LinkedInFacilitator}
29 | Whatsapp: {ZapFacilitator}
30 | Email: {EmailFacilitator}
31 |
32 |
33 |
34 | Atenciosamente,
35 |
36 | Sharebook team - Compartilhando conhecimento
37 | Siga-nos no instagram:
38 | @sharebook.com.br
39 |
40 |
41 | Curta nossa fanpage pra ficar por dentro das novidades:
42 | https://www.linkedin.com/company/sharebook-br/
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/NewBookInsertedTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Novo livro cadastrado - Sharebook
6 |
7 |
8 |
9 | Olá Administrador(a),
10 |
11 |
12 | Um novo livro foi cadastrado. Veja mais informações abaixo:
13 |
14 |
15 |
16 | Livro: {Book.Title}
17 | Autor: {Book.Author}
18 | Usuário: {Book.User.Name}
19 |
20 |
21 |
22 | Informações sobre o usuário:
23 |
24 |
25 |
26 | Data de Cadastro: {UserStats.CreationDate}
27 | Total doações concluídas: {UserStats.TotalOk}
28 | Total doações canceladas: {UserStats.TotalCanceled}
29 | Total doações em atraso: {UserStats.TotalLate}
30 | Total doações em aguardando aprovação: {UserStats.TotalWaitingApproval}
31 | Total doações na vitrine: {UserStats.TotalAvailable}
32 |
33 |
34 |
35 | Use esse link para revisar e aprovar: https://www.sharebook.com.br/book/form/{Book.Id}
36 |
37 |
38 |
39 | Cuidado. Geralmente não sabemos se um NOVO USUÁRIO é firmeza. O recomendado é aprovar apenas um livro de início. Caso ele realmente conclua a doação, aí temos segurança para aprovar todos. Blz?
40 |
41 |
42 |
43 | Sharebook
44 |
45 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Book/IBookService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using ShareBook.Domain.Common;
3 | using ShareBook.Domain.DTOs;
4 | using ShareBook.Domain.Enums;
5 | using ShareBook.Service.Generic;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 |
10 | namespace ShareBook.Service
11 | {
12 | public interface IBookService : IBaseService
13 | {
14 | Task ApproveAsync(Guid bookId, DateTime? chooseDate);
15 |
16 | Task ReceivedAsync(Guid bookId, Guid winnerUserId);
17 | Task UpdateBookStatusAsync(Guid bookId, BookStatus bookStatus);
18 |
19 | IList FreightOptions();
20 |
21 | Task> AvailableBooksAsync();
22 |
23 | Task> Random15BooksAsync();
24 |
25 | Task> Random15EBooksAsync();
26 |
27 | Task> FullSearchAsync(string criteria, int page, int itemsPerPage, bool isAdmin = false);
28 |
29 | Task> ByCategoryIdAsync(Guid categoryId, int page, int items);
30 |
31 | Task> GetAllAsync(int page, int items);
32 |
33 | Task BySlugAsync(string slug);
34 |
35 | Task UserRequestedBookAsync(Guid bookId);
36 |
37 | Task> GetUserDonationsAsync(Guid userId);
38 |
39 | Task> GetBooksChooseDateIsTodayAsync();
40 |
41 | Task> GetBooksChooseDateIsLateAsync();
42 |
43 | Task> GetBooksChooseDateIsTodayOrLateAsync();
44 |
45 | Task AddFacilitatorNotesAsync(Guid bookId, string facilitatorNotes);
46 |
47 | Task GetBookWithAllUsersAsync(Guid bookId);
48 |
49 | Task RenewChooseDateAsync(Guid bookId);
50 | Task GetStatsAsync();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/ContactUs/ContactUsEmailService.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System.Threading.Tasks;
3 |
4 | namespace ShareBook.Service
5 | {
6 | public class ContactUsEmailService : IContactUsEmailService
7 | {
8 | private const string ContactUsTemplate = "ContactUsTemplate";
9 | public const string ContactUsTitle = "Fale Conosco - Sharebook";
10 | private const string ContactUsNotificationTemplate = "ContactUsNotificationTemplate";
11 | public const string ContactUsNotificationTitle = "Fale Conosco - Sharebook";
12 |
13 | private readonly IEmailService _emailService;
14 |
15 | private readonly IEmailTemplate _emailTemplate;
16 |
17 |
18 | public ContactUsEmailService(IEmailService emailService, IEmailTemplate emailTemplate)
19 | {
20 | _emailService = emailService;
21 | _emailTemplate = emailTemplate;
22 | }
23 | public async Task SendEmailContactUsAsync(ContactUs contactUs)
24 | {
25 | await SendEmailContactUsToAdministratorAsync(contactUs);
26 |
27 | await SendEmailNotificationToUserAsync(contactUs);
28 | }
29 | private async Task SendEmailContactUsToAdministratorAsync(ContactUs contactUs)
30 | {
31 | var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(ContactUsTemplate, contactUs);
32 | await _emailService.SendToAdminsAsync(html, ContactUsTitle);
33 | }
34 | private async Task SendEmailNotificationToUserAsync(ContactUs contactUs)
35 | {
36 | var html = await _emailTemplate.GenerateHtmlFromTemplateAsync(ContactUsNotificationTemplate, contactUs);
37 | await _emailService.SendAsync(contactUs.Email, contactUs.Name, html, ContactUsNotificationTitle, copyAdmins: false, highPriority: true);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/ApplicationDbContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using ShareBook.Domain;
3 | using ShareBook.Repository.Mapping;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace ShareBook.Repository
8 | {
9 | public class ApplicationDbContext : DbContext
10 | {
11 | public ApplicationDbContext(DbContextOptions options) : base(options) { }
12 | public ApplicationDbContext() { }
13 |
14 | public DbSet Books { get; set; }
15 | public DbSet Users { get; set; }
16 | public DbSet LogEntries { get; set; }
17 | public DbSet BookUser { get; set; }
18 | public DbSet Categories { get; set; }
19 | public DbSet Addresses { get; set; }
20 | public DbSet JobHistories { get; set; }
21 | public DbSet AccessHistories { get; set; }
22 | public DbSet Meetups { get; set; }
23 | public DbSet MeetupParticipants { get; set; }
24 |
25 | public DbSet MailBounces { get; set; }
26 |
27 | protected override void OnModelCreating(ModelBuilder modelBuilder)
28 | {
29 | base.OnModelCreating(modelBuilder);
30 |
31 | //O Contexto procura pelas classes que implementam IEntityTypeConfiguration adicionando o mapeamento de forma automática.
32 | modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
33 |
34 | this.SetUtcOnDatabase(modelBuilder);
35 | }
36 |
37 | public override async Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
38 | {
39 | await this.LogChanges();
40 | return await base.SaveChangesAsync(cancellationToken);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/ChooseDateReminderTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SHAREBOOK - É HOJE!
6 |
7 |
8 |
9 | Olá {DonorName},
10 |
11 |
12 | Aqui é o Sharebot do time Sharebook. Tudo bem?
13 |
14 | Hoje é o grande dia. O dia de escolher o ganhador do livro '{BookTitle}'! Pra sua conveniência use o link abaixo:
15 |
16 | https://sharebook.com.br/book/donations
17 |
18 |
19 | Por favor escolha o ganhador o quanto antes. É muito importante.
20 | Afinal todos os interessados estão anciosos pelo dia de hoje. Obrigado!
21 |
22 |
23 |
24 | Dúvidas? Sem problemas, é um prazer ajudar. Entre em contato com seu facilitador.
25 |
31 |
32 |
33 |
34 |
35 |
36 | Atenciosamente,
37 |
38 | Sharebook team - Compartilhando conhecimento
39 | Siga-nos no instagram:
40 | @sharebook.com.br
41 |
42 |
43 | Curta nossa fanpage pra ficar por dentro das novidades:
44 | https://www.linkedin.com/company/sharebook-br/
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Repository/Book/BookRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Linq.Expressions;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using ShareBook.Domain;
7 | using ShareBook.Domain.Common;
8 |
9 | namespace ShareBook.Repository
10 | {
11 | public class BookRepository : RepositoryGeneric, IBookRepository
12 | {
13 | public BookRepository(ApplicationDbContext context) : base(context) { }
14 |
15 | public override async Task UpdateAsync(Book entity)
16 | {
17 |
18 | _context.Update(entity);
19 |
20 | //imagem eh opcional no update
21 | if (entity.ImageSlug == null)
22 | _context.Entry(entity).Property(x => x.ImageSlug).IsModified = false;
23 |
24 | if(entity.Slug == null)
25 | _context.Entry(entity).Property(x => x.Slug).IsModified = false;
26 |
27 | _context.Entry(entity).Property(x => x.UserId).IsModified = false;
28 |
29 | await _context.SaveChangesAsync();
30 |
31 | return entity;
32 | }
33 |
34 | public override async Task> GetAsync(Expression> filter, Expression> order, int page, int itemsPerPage)
35 | {
36 | var skip = (page - 1) * itemsPerPage;
37 | var query = _dbSet.Where(filter);
38 | var total = await query.CountAsync();
39 | var result = await query.Include(x => x.BookUsers).Include(x => x.User)
40 | .OrderBy(order)
41 | .Skip(skip)
42 | .Take(itemsPerPage)
43 | .ToListAsync();
44 |
45 | return new PagedList()
46 | {
47 | Page = page,
48 | ItemsPerPage = itemsPerPage,
49 | TotalItems = total,
50 | Items = result
51 | };
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/Validators/BookValidatorTests.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation.Results;
2 | using ShareBook.Domain;
3 | using ShareBook.Domain.Enums;
4 | using ShareBook.Domain.Validators;
5 | using System;
6 | using System.Text;
7 | using Xunit;
8 |
9 | namespace ShareBook.Test.Unit.Validators
10 | {
11 | public class BookValidatorTests
12 | {
13 | BookValidator bookValidator = new BookValidator();
14 |
15 | [Fact]
16 | public void ValidEntities()
17 | {
18 | Book book = new Book()
19 | {
20 | Title = "Lord of the Rings",
21 | Author = "J. R. R. Tolkien",
22 | ImageName = "lotr.png",
23 | ImageBytes = Encoding.UTF8.GetBytes("STRINGBASE64"),
24 | FreightOption = FreightOption.World,
25 | UserId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3"),
26 | CategoryId = Guid.NewGuid()
27 | };
28 |
29 | ValidationResult result = bookValidator.Validate(book);
30 |
31 | Assert.True(result.IsValid);
32 | }
33 |
34 |
35 | [Fact]
36 | public void InvalidEntities()
37 | {
38 | Book book = new Book()
39 | {
40 | Title = "Lord of the Rings",
41 | Author = null,
42 | ImageName = "lotr.png"
43 | };
44 |
45 | ValidationResult result = bookValidator.Validate(book);
46 |
47 | Assert.False(result.IsValid);
48 | }
49 |
50 |
51 | [Fact]
52 | public void InvalidImageExtension()
53 | {
54 | Book book = new Book()
55 | {
56 | Title = "Lord of the Rings",
57 | Author = "J. R. R. Tolkien",
58 | ImageName = "lotrnoextension"
59 | };
60 |
61 | ValidationResult result = bookValidator.Validate(book);
62 |
63 | Assert.False(result.IsValid);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/Image/ImageHelper.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using SixLabors.ImageSharp.Processing;
3 | using SixLabors.ImageSharp.Formats;
4 | using SixLabors.ImageSharp;
5 | using System;
6 |
7 | namespace ShareBook.Helper.Image
8 | {
9 | public static class ImageHelper
10 | {
11 | public static string FormatImageName(string originalName, string slug)
12 | {
13 | var newFileName = originalName.Replace(Path.GetFileNameWithoutExtension(originalName), slug);
14 |
15 | return Path.GetFileName(newFileName);
16 | }
17 |
18 | public static string GenerateImageUrl(string imageName, string directory, string serverUrl)
19 | {
20 | return serverUrl + directory.Replace("wwwroot", "") + "/" + imageName;
21 | }
22 |
23 | ///
24 | /// Scale an image by a scale factor
25 | ///
26 | /// The image bytes
27 | /// The percentage to increase (>100) or decrease(<100) the size of the image
28 | /// The resized image as a byte[]
29 | ///
30 | public static byte[] ResizeImage(byte[] imageBytes, int scalefactor)
31 | {
32 | if (scalefactor <= 0)
33 | {
34 | throw new ArgumentException("'scalefactor' deve ser maior que 0");
35 | }
36 |
37 | SixLabors.ImageSharp.Image image = SixLabors.ImageSharp.Image.Load(imageBytes, out IImageFormat imageFormat);
38 |
39 | var width = image.Width * scalefactor / 100;
40 | var height = image.Height * scalefactor / 100;
41 |
42 | image.Mutate(x => x.Resize(width, height));
43 |
44 | var memoryStream = new MemoryStream();
45 |
46 | image.Save(memoryStream, imageFormat);
47 |
48 | return memoryStream.ToArray();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "DatabaseProvider": "sqlserver",
3 | "ConnectionStrings": {
4 | "DefaultConnection": "",
5 | "PostgresConnection": "",
6 | "SqliteConnection": "Data Source=sharebook.db;"
7 | },
8 | "TokenConfigurations": {
9 | "Audience": "ShareBookAudience",
10 | "Issuer": "Sharebook",
11 | "Seconds": 86400,
12 | "SecretJwtKey": ""
13 | },
14 | "Logging": {
15 | "LogLevel": {
16 | "Default": "Debug",
17 | "System": "Warning",
18 | "Microsoft": "Warning"
19 | }
20 | },
21 | "ImageSettings": {
22 | "ImagePath": "wwwroot/Images",
23 | "EBookPdfPath": "wwwroot/EbookPdfs"
24 | },
25 | "SharebookSettings": {
26 | "DaysInShowcase": 7,
27 | "MaxRequestsPerBook": 50,
28 | "MaxLateDonationDays": 5,
29 | "MaxLateDonationDaysAutoCancel": 10
30 | },
31 | "ClientSettings": {
32 | "AndroidMinVersion": "v1.5.0"
33 | },
34 | "ServerSettings": {
35 | "DefaultUrl": "https://api.sharebook.com.br",
36 | "JobExecutorToken": ""
37 | },
38 | "EmailSettings": {
39 | "IsActive": "false",
40 | "HostName": "",
41 | "Username": "",
42 | "Password": "",
43 | "Port": 25,
44 | "UseSSL": false,
45 | "MaxEmailsPerHour": 50
46 | },
47 | "PushNotificationSettings": {
48 | "IsActive": "false",
49 | "AppId": "",
50 | "ApiKey": ""
51 | },
52 | "Muambator": {
53 | "IsActive": "false",
54 | "Token": ""
55 | },
56 | "Rollbar": {
57 | "IsActive": "false",
58 | "Token": "",
59 | "Environment": "Development",
60 | "LogLevel": "Info"
61 | },
62 | "AwsSqsSettings": {
63 | "IsActive": false,
64 | "AccessKey": "",
65 | "SecretKey": "",
66 | "Region": "",
67 | "QueueBaseUrl": "",
68 | "NewBookQueue": "new-book-dev",
69 | "SendEmailHighPriorityQueue": "send-email-high-priority-dev",
70 | "SendEmailLowPriorityQueue": "send-email-low-priority-dev"
71 | },
72 | "MeetupSettings": {
73 | "IsActive": false,
74 | "YoutubeToken": ""
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Helper/Extensions/StringExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Text;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace ShareBook.Helper.Extensions
7 | {
8 | public static class StringExtension
9 | {
10 | public static string GenerateSlug(this string phrase)
11 | {
12 | string str = phrase.RemoveAccent().ToLower();
13 | // invalid chars
14 | str = Regex.Replace(str, @"[^a-z0-9\s-]", "");
15 | // convert multiple spaces into one space
16 | str = Regex.Replace(str, @"\s+", " ").Trim();
17 | // cut and trim
18 | str = str.Substring(0, str.Length <= 45 ? str.Length : 45).Trim();
19 | str = Regex.Replace(str, @"\s", "-"); // hyphens
20 | return str;
21 | }
22 |
23 | public static string RemoveAccent(this string text)
24 | {
25 | if (string.IsNullOrEmpty(text))
26 | {
27 | return text;
28 | }
29 |
30 | var normalizedString = text.Normalize(NormalizationForm.FormD);
31 | var stringBuilder = new StringBuilder();
32 |
33 | foreach (var c in normalizedString)
34 | {
35 | var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
36 | if (unicodeCategory != UnicodeCategory.NonSpacingMark)
37 | {
38 | stringBuilder.Append(c);
39 | }
40 | }
41 |
42 | return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
43 | }
44 |
45 |
46 | public static string AddIncremental(this string text)
47 | {
48 |
49 | var number = text.Split("_copy").Length == 2 ? Convert.ToInt32(text.Split("_copy")[1]) + 1 : 1;
50 |
51 | var onlyText = text.Split("_copy").Length == 2 ? text.Split("_copy")[0] : text;
52 |
53 | return $"{onlyText}_copy{number}";
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/Controllers/Generic/BaseController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Cors;
2 | using Microsoft.AspNetCore.Mvc;
3 | using ShareBook.Api.Filters;
4 | using ShareBook.Api.ViewModels;
5 | using ShareBook.Domain.Common;
6 | using ShareBook.Service.Generic;
7 | using System;
8 | using System.Linq.Expressions;
9 | using System.Threading.Tasks;
10 |
11 | namespace ShareBook.Api.Controllers
12 | {
13 | public class BaseController : BaseController
14 | where T : BaseEntity
15 | {
16 | public BaseController(IBaseService service) : base(service)
17 | {
18 | }
19 | }
20 |
21 | public class BaseController : BaseController
22 | where T : BaseEntity
23 | where R : BaseViewModel
24 | {
25 | public BaseController(IBaseService service) : base(service)
26 | {
27 | }
28 | }
29 |
30 | [GetClaimsFilter]
31 | [EnableCors("AllowAllHeaders")]
32 | public class BaseController : Controller
33 | where T : BaseEntity
34 | where R : IIdProperty
35 | where A : class
36 | {
37 | protected readonly IBaseService _service;
38 | private Expression> _defaultOrder = x => x.Id;
39 | protected bool HasRequestViewModel { get { return typeof(R) != typeof(T); } }
40 |
41 | public BaseController(IBaseService service)
42 | {
43 | _service = service;
44 | }
45 |
46 | protected void SetDefault(Expression> defaultOrder)
47 | {
48 | _defaultOrder = defaultOrder;
49 | }
50 |
51 | [HttpGet()]
52 | public virtual async Task> GetAllAsync() => await PagedAsync(1, 15);
53 |
54 | [HttpGet("{page}/{items}")]
55 | public virtual async Task> PagedAsync(int page, int items) => await _service.GetAsync(x => true, _defaultOrder, page, items);
56 |
57 | [HttpGet("{id}")]
58 | public async Task GetByIdAsync(string id) => await _service.FindAsync(new Guid(id));
59 | }
60 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Repository/Mapping/UserMap.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
3 | using ShareBook.Domain;
4 |
5 | namespace ShareBook.Repository.Mapping
6 | {
7 | public class UserMap : IEntityTypeConfiguration
8 | {
9 | public void Configure(EntityTypeBuilder entityBuilder)
10 | {
11 | entityBuilder.HasKey(t => t.Id);
12 |
13 | entityBuilder.Property(t => t.Name)
14 | .HasMaxLength(200)
15 | .IsRequired();
16 |
17 | entityBuilder.Property(t => t.Email)
18 | .HasMaxLength(100)
19 | .IsRequired();
20 |
21 | entityBuilder.HasIndex(t => t.Email)
22 | .IsUnique();
23 |
24 | entityBuilder.Property(t => t.Password)
25 | .HasMaxLength(50)
26 | .IsRequired();
27 |
28 | entityBuilder.Property(t => t.PasswordSalt)
29 | .HasMaxLength(50)
30 | .IsRequired();
31 |
32 | entityBuilder.Property(t => t.Linkedin)
33 | .HasMaxLength(100);
34 |
35 | entityBuilder.Property(t => t.Phone)
36 | .HasMaxLength(30);
37 |
38 | entityBuilder.Property(t => t.HashCodePassword)
39 | .HasMaxLength(200);
40 |
41 | // Removido HasColumnType específico - EF Core escolhe automaticamente
42 |
43 | entityBuilder.HasMany(t => t.BooksDonated)
44 | .WithOne(b => b.User);
45 |
46 | entityBuilder.Property(t => t.Active)
47 | .HasDefaultValue(true); // Valor padrão compatível
48 |
49 | entityBuilder.Property(t => t.AllowSendingEmail)
50 | .ValueGeneratedNever()
51 | .HasDefaultValue(true);
52 |
53 | // Removido LastLogin default - será definido no código
54 |
55 | entityBuilder.Property(t => t.ParentAproved);
56 | entityBuilder.Property(t => t.ParentEmail);
57 | entityBuilder.Property(t => t.ParentHashCodeAproval);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/Templates/ChooseDateRenewTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SHAREBOOK - É HOJE!
6 |
7 |
8 |
9 | Olá {DonorName},
10 |
11 |
12 | Aqui é o Sharebot do time Sharebook. Tudo bem?
13 |
14 | Hoje seria o dia de escolher o ganhador do livro '{BookTitle}'! Mas infelizmente não apareceu nenhum
15 | interessado. Não se preocupe, renovamos data de escolha para daqui a 10 dias. Enquanto isso vamos juntos
16 | divulgar mais esse livro incrível nas mídias sociais. Tenho certeza que vamos achar MUITOS interesados. Eles só
17 | não sabem ainda. Então compartilhe o link abaixo em suas mídias sociais, grupos de whatsapp e tudo mais kkk.
18 | Bora compartilhar o conhecimento!
19 |
20 | https://sharebook.com.br/livros/{BookSlug}
21 |
22 |
23 | Dúvidas? Sem problemas, é um prazer ajudar. Entre em contato com seu facilitador.
24 |
30 |
31 |
32 |
33 |
34 |
35 | Atenciosamente,
36 |
37 | Sharebook team - Compartilhando conhecimento
38 | Siga-nos no instagram:
39 | @sharebook.com.br
40 |
41 |
42 | Curta nossa fanpage pra ficar por dentro das novidades:
43 | https://www.linkedin.com/company/sharebook-br/
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Api/AutoMapper/ViewModelToDomainMappingProfile.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using ShareBook.Api.ViewModels;
3 | using ShareBook.Domain;
4 | using ShareBook.Domain.DTOs;
5 |
6 | namespace ShareBook.Api.AutoMapper
7 | {
8 | public class ViewModelToDomainMappingProfile : Profile
9 | {
10 | public ViewModelToDomainMappingProfile() : this("Profile")
11 | {
12 | }
13 |
14 | protected ViewModelToDomainMappingProfile(string profileName) : base(profileName)
15 | {
16 | #region [ Book ]
17 |
18 | CreateMap().ReverseMap();
19 | CreateMap().ReverseMap();
20 | CreateMap().ReverseMap();
21 | CreateMap();
22 |
23 | #endregion [ Book ]
24 |
25 | #region [ User ]
26 |
27 | CreateMap();
28 | CreateMap()
29 | .ForPath(dest => dest.Address.Street, opt => opt.MapFrom(src => src.Street))
30 | .ForPath(dest => dest.Address.Number, opt => opt.MapFrom(src => src.Number))
31 | .ForPath(dest => dest.Address.PostalCode, opt => opt.MapFrom(src => src.PostalCode))
32 | .ForPath(dest => dest.Address.State, opt => opt.MapFrom(src => src.State))
33 | .ForPath(dest => dest.Address.City, opt => opt.MapFrom(src => src.City))
34 | .ForPath(dest => dest.Address.Neighborhood, opt => opt.MapFrom(src => src.Neighborhood))
35 | .ForPath(dest => dest.Address.Country, opt => opt.MapFrom(src => src.Country))
36 | .ForPath(dest => dest.Address.Complement, opt => opt.MapFrom(src => src.Complement));
37 | CreateMap();
38 |
39 | #endregion [ User ]
40 |
41 | #region [ ContactUs ]
42 |
43 | CreateMap();
44 |
45 | #endregion [ ContactUs ]
46 |
47 | #region [ Notification ]
48 |
49 | CreateMap();
50 |
51 | #endregion [ Notification ]
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/Mocks/BookMock.cs:
--------------------------------------------------------------------------------
1 | using ShareBook.Domain;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace ShareBook.Test.Unit.Mocks
7 | {
8 | public class BookMock
9 | {
10 | public static Book GetLordTheRings(User user, User userFacilitator = null)
11 | {
12 | Guid bookId = new Guid("d9f5fde8-ee7c-4cf5-aa90-35eca3c170b9");
13 | return new Book()
14 | {
15 | Id = bookId,
16 | Title = "Lord of the Rings",
17 | Author = "J. R. R. Tolkien",
18 | ImageSlug = "lotr.png",
19 | ImageBytes = Encoding.UTF8.GetBytes("STRINGBASE64"),
20 | User = user,
21 | BookUsers = new List { new BookUser { BookId = bookId, User = user } },
22 | UserFacilitator = userFacilitator,
23 | CategoryId = Guid.NewGuid(),
24 | Status = ShareBook.Domain.Enums.BookStatus.Available
25 | };
26 | }
27 |
28 |
29 | public static Book GetLordTheRings()
30 | {
31 | var requests = new List {
32 | new BookUser { BookId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3"), UserId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3") },
33 | new BookUser { BookId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3"), UserId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3") },
34 | new BookUser { BookId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3"), UserId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3") }
35 | };
36 |
37 | return new Book()
38 | {
39 | Title = "Lord of the Rings",
40 | Author = "J. R. R. Tolkien",
41 | ImageSlug = "lotr.png",
42 | ImageBytes = Encoding.UTF8.GetBytes("STRINGBASE64"),
43 | CategoryId = Guid.NewGuid(),
44 | UserId = new Guid("5489A967-9320-4350-E6FC-08D5CC8498F3"),
45 | Status = ShareBook.Domain.Enums.BookStatus.Available,
46 | BookUsers = requests
47 | };
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Infra.CrossCutting.Identity/ApplicationSignInManager.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.IdentityModel.Tokens;
2 | using ShareBook.Domain;
3 | using ShareBook.Infra.CrossCutting.Identity.Interfaces;
4 | using System;
5 | using System.IdentityModel.Tokens.Jwt;
6 | using System.Security.Claims;
7 |
8 | namespace ShareBook.Infra.CrossCutting.Identity
9 | {
10 | public class ApplicationSignInManager : IApplicationSignInManager
11 | {
12 | public object GenerateTokenAndSetIdentity(User user, SigningConfigurations signingConfigurations, TokenConfigurations tokenConfigurations)
13 | {
14 | ClaimsIdentity identity = new ClaimsIdentity(
15 | new[] {
16 | new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
17 | new Claim(JwtRegisteredClaimNames.UniqueName, user.Id.ToString()),
18 | new Claim(ClaimTypes.Role, user.Profile.ToString(), ClaimValueTypes.String, tokenConfigurations.Issuer)
19 | }
20 | );
21 |
22 | DateTime creationDate = DateTime.Now;
23 | DateTime expireDate = creationDate + TimeSpan.FromSeconds(tokenConfigurations.Seconds);
24 |
25 | var handler = new JwtSecurityTokenHandler();
26 | var securityToken = handler.CreateToken(new SecurityTokenDescriptor
27 | {
28 | Issuer = tokenConfigurations.Issuer,
29 | Audience = tokenConfigurations.Audience,
30 | SigningCredentials = signingConfigurations.SigningCredentials,
31 | Subject = identity,
32 | NotBefore = creationDate,
33 | Expires = expireDate
34 | });
35 | var token = handler.WriteToken(securityToken);
36 |
37 | return new
38 | {
39 | authenticated = true,
40 | created = creationDate,
41 | expiration = expireDate,
42 | accessToken = token,
43 | name = user.Name,
44 | email = user.Email,
45 | userId = user.Id,
46 | profile = user.Profile.ToString(),
47 | message = "OK"
48 | };
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Email/EmailTemplate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Text.RegularExpressions;
6 | using System.Threading.Tasks;
7 |
8 | namespace ShareBook.Service
9 | {
10 | public class EmailTemplate : IEmailTemplate
11 | {
12 | private string TemplatesFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Email","Templates","{0}.html");
13 | const string PropertyRegex = @"\{(.*?)\}";
14 | private Dictionary Templates { get; set; } = new Dictionary();
15 |
16 | private string GetPropValue(object obj, string propName)
17 | {
18 | string[] nameParts = propName.Split('.');
19 | if (nameParts.Length == 1)
20 | {
21 | return obj.GetType().GetProperty(propName).GetValue(obj, null)?.ToString();
22 | }
23 |
24 | foreach (string part in nameParts)
25 | {
26 | if (obj == null) { return null; }
27 |
28 | Type type = obj.GetType();
29 | PropertyInfo info = type.GetProperty(part);
30 | if (info == null) { return null; }
31 |
32 | obj = info.GetValue(obj, null);
33 | }
34 | return obj?.ToString();
35 | }
36 |
37 | private async Task GetTemplateAsync(string template)
38 | {
39 | if (!Templates.ContainsKey(template))
40 | {
41 | var templatePath = string.Format(TemplatesFolder, template);
42 | Templates.Add(template, await File.ReadAllTextAsync(templatePath));
43 | }
44 | return Templates[template];
45 | }
46 |
47 | public async Task GenerateHtmlFromTemplateAsync(string template, object model)
48 | {
49 | var templateString = await GetTemplateAsync(template);
50 | var matches = Regex.Matches(templateString, PropertyRegex);
51 | foreach (Match item in matches)
52 | {
53 | templateString = templateString.Replace(item.Value, GetPropValue(model, item.Groups[1].Value));
54 | }
55 | return templateString;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/Jobs/4 - MeetupSearchTests.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using Sharebook.Jobs;
3 | using ShareBook.Service;
4 | using System.Threading.Tasks;
5 | using Xunit;
6 | using ShareBook.Repository;
7 | using Microsoft.Extensions.Configuration;
8 | using ShareBook.Domain.Enums;
9 | using System.Collections.Generic;
10 | using ShareBook.Domain;
11 |
12 | namespace ShareBook.Test.Unit.Jobs
13 | {
14 | public class MeetupSearchTests
15 | {
16 | private readonly Mock _mockJobHistoryRepository = new();
17 | private readonly Mock _mockMeetupService = new();
18 | private readonly Mock _mockConfiguration = new();
19 |
20 | [Fact]
21 | public async Task MeetupSettingsDisabled_ShouldReturn_MeetupDisabled()
22 | {
23 | _mockConfiguration.SetupGet(s => s[It.IsAny()]).Returns("false");
24 | MeetupSearch job = new MeetupSearch(_mockJobHistoryRepository.Object, _mockMeetupService.Object, _mockConfiguration.Object);
25 |
26 | JobResult result = await job.ExecuteAsync();
27 | Assert.Equal(JobResult.MeetupDisabled, result);
28 | _mockMeetupService.VerifyNoOtherCalls();
29 | _mockJobHistoryRepository.VerifyNoOtherCalls();
30 | }
31 |
32 | [Fact]
33 | public async Task MeetupSettingsEnabled_ShouldReturn_MeetupsCorrectly()
34 | {
35 | List mockedMeetups = new List { "Meetup Mock 1", "Meetup Mock 2" };
36 | _mockConfiguration.SetupGet(s => s[It.IsAny()]).Returns("true");
37 | _mockMeetupService.Setup(s => s.FetchMeetupsAsync()).ReturnsAsync(() => mockedMeetups);
38 | MeetupSearch job = new MeetupSearch(_mockJobHistoryRepository.Object, _mockMeetupService.Object, _mockConfiguration.Object);
39 |
40 | JobHistory result = await job.WorkAsync();
41 | Assert.Equal("MeetupSearch", result.JobName);
42 | Assert.True(result.IsSuccess);
43 | Assert.Equal(string.Join("\n", mockedMeetups), result.Details);
44 | _mockMeetupService.Verify(c => c.FetchMeetupsAsync(), Times.Once);
45 | _mockMeetupService.VerifyNoOtherCalls();
46 | _mockJobHistoryRepository.VerifyNoOtherCalls();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Test.Unit/Services/ContactUsEmailServiceTests.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using ShareBook.Domain;
3 | using ShareBook.Service;
4 | using Xunit;
5 | using System.Threading.Tasks;
6 |
7 | namespace ShareBook.Test.Unit.Services
8 | {
9 | public class ContactUsEmailServiceTests
10 | {
11 | private readonly Mock _mockEmailService = new();
12 | private readonly Mock _mockEmailTemplate = new();
13 | private const string HtmlMock = "Example";
14 |
15 | public ContactUsEmailServiceTests()
16 | {
17 | _mockEmailService.Setup(t => t.SendToAdminsAsync(It.IsAny(), It.IsAny()));
18 | _mockEmailService.Setup(t => t.SendAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()));
19 | _mockEmailService.Setup(t => t.SendAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()));
20 | _mockEmailTemplate.Setup(t => t.GenerateHtmlFromTemplateAsync(It.IsAny(), It.IsAny())).ReturnsAsync(HtmlMock);
21 | }
22 |
23 | [Fact]
24 | public async Task SendEmailContactToTheUserAndToAdministrators()
25 | {
26 | ContactUs contactUs = new ContactUs
27 | {
28 | Email = "joazinho.souza@example.com",
29 | Message = "Test message test, Test message test, Test message test",
30 | Name = "Joãozinho",
31 | Phone = "44 9 8877-6655"
32 | };
33 | ContactUsEmailService service = new ContactUsEmailService(_mockEmailService.Object, _mockEmailTemplate.Object);
34 | await service.SendEmailContactUsAsync(contactUs);
35 |
36 | _mockEmailService.Verify(s => s.SendToAdminsAsync(HtmlMock, ContactUsEmailService.ContactUsTitle), Times.Once);
37 | _mockEmailService.Verify(s => s.SendAsync(contactUs.Email, contactUs.Name, HtmlMock, ContactUsEmailService.ContactUsNotificationTitle, false, true), Times.Once);
38 | _mockEmailService.VerifyNoOtherCalls();
39 | _mockEmailTemplate.Verify(s => s.GenerateHtmlFromTemplateAsync(It.IsAny(), It.IsAny()), Times.Exactly(2));
40 | _mockEmailTemplate.VerifyNoOtherCalls();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ShareBook/ShareBook.Service/Upload/UploadService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using ShareBook.Helper.Image;
3 | using ShareBook.Service.Server;
4 | using System;
5 | using System.IO;
6 | using System.Threading.Tasks;
7 |
8 | namespace ShareBook.Service.Upload
9 | {
10 | public class UploadService : IUploadService
11 | {
12 | private readonly ImageSettings _imageSettings;
13 | private readonly ServerSettings _serverSettings;
14 |
15 | public UploadService(IOptions imageSettings, IOptions serverSettings)
16 | {
17 | _imageSettings = imageSettings.Value;
18 | _serverSettings = serverSettings.Value;
19 | }
20 |
21 | public string GetImageUrl(string imageName, string lastDirectory)
22 | {
23 | var dinamicDirectory = _imageSettings.ImagePath + "/" + lastDirectory;
24 | return ImageHelper.GenerateImageUrl(imageName, dinamicDirectory, _serverSettings.DefaultUrl);
25 | }
26 |
27 |
28 | public async Task UploadImageAsync(byte[] imageBytes, string imageName, string lastDirectory)
29 | {
30 | var dinamicDirectory = Path.Combine(_imageSettings.ImagePath, lastDirectory);
31 |
32 | await UploadFileAsync(imageBytes, imageName, dinamicDirectory);
33 |
34 | return GetImageUrl(imageName, lastDirectory);
35 | }
36 |
37 | public async Task UploadPdfAsync(byte[] imageBytes, string imageName, string lastDirectory)
38 | {
39 | var dinamicDirectory = Path.Combine(_imageSettings.EBookPdfPath, lastDirectory);
40 |
41 | await UploadFileAsync(imageBytes, imageName, dinamicDirectory);
42 |
43 | return Path.Combine(lastDirectory, dinamicDirectory.Replace("wwwroot", ""), imageName);
44 |
45 | }
46 |
47 | private static async Task UploadFileAsync(byte[] imageBytes, string imageName, string dinamicDirectory)
48 | {
49 | var directoryBase = AppDomain.CurrentDomain.BaseDirectory + dinamicDirectory;
50 | if (!Directory.Exists(directoryBase))
51 | Directory.CreateDirectory(directoryBase);
52 |
53 | var imageCompletePath = Path.Combine(directoryBase, imageName);
54 | await File.WriteAllBytesAsync(imageCompletePath, imageBytes);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------