├── .gitattributes
├── .github
├── CODEOWNERS
└── workflows
│ ├── build-image-api.yml
│ ├── build-image-migrator.yml
│ ├── build-image-seed.yml
│ ├── codeql-analysis.yml
│ └── dotnetcore.yml
├── .gitignore
├── LICENSE
├── README.md
├── bombardier
├── 1-polling-stations-details-flow.js
├── 2-forms-versions.js
├── 3-answers-flow.js
├── 4-notes-flow.js
├── attachments
│ ├── image1.jpg
│ ├── image2.jpg
│ ├── image3.jpg
│ ├── image4.jpg
│ ├── image5.jpg
│ ├── image6.jpg
│ ├── image7.jpg
│ ├── image8.jpg
│ └── image9.jpg
├── polling-stations.csv
├── users.csv
└── utils.js
├── docs
├── README.md
├── dummy-db-data
│ ├── counties.csv
│ ├── form-sections.csv
│ ├── forms.csv
│ ├── ngo-admin.csv
│ ├── ngos.csv
│ ├── observers.csv
│ ├── options-to-questions.csv
│ ├── options.csv
│ ├── polling-stations.csv
│ └── questions.csv
└── images
│ ├── data_model.png
│ ├── sequence_diagrams
│ ├── sequence_diagram_mobile_answers.png
│ ├── sequence_diagram_mobile_forms.png
│ ├── sequence_diagram_mobile_login.png
│ ├── sequence_diagram_mobile_login_v2.png
│ ├── sequence_diagram_mobile_manual_sync.png
│ ├── sequence_diagram_mobile_notes.png
│ └── sequence_diagram_mobile_pick_section.jpeg
│ └── vote_monitor_diagram.png
├── forms-parser
├── README.md
├── form-parser.js
├── forms-2023-10-05.xlsx
├── forms-2023-10-10-en.xlsx
├── forms-2023-10-10-pl.xlsx
├── forms-2023-10-10.xlsx
├── forms-2023-10-11.xlsx
├── output
│ ├── EN-A.json
│ ├── EN-B.json
│ ├── EN-C.json
│ ├── PL-A.json
│ ├── PL-B.json
│ └── PL-C.json
├── package.json
└── pnpm-lock.yaml
├── requests
├── EN-A.json
├── EN-B.json
├── EN-C.json
├── PL-A.json
├── PL-B.json
├── PL-C.json
├── image1.jpg
├── observers.csv
├── polish-data-2023-10-10.xlsx
├── polish_counties_2023.csv
├── polish_municipalities_2023.csv
├── polish_polling_stations_2023.csv
├── polish_provinces_2023.csv
└── requests.http
├── src
├── .dockerignore
├── .editorconfig
├── .env.example
├── Directory.Build.targets
├── VotingIrregularities.sln
├── VotingIrregularities.sln.DotSettings
├── api
│ ├── VoteMonitor.Api.Answer
│ │ ├── Commands
│ │ │ ├── BulkAnswers.cs
│ │ │ └── FillInAnswerCommand.cs
│ │ ├── Controllers
│ │ │ └── AnswersController.cs
│ │ ├── Handlers
│ │ │ ├── AnswerQueryHandler.cs
│ │ │ ├── AnswersQueryHandler.cs
│ │ │ └── FillInAnswerQueryHandler.cs
│ │ ├── Models
│ │ │ ├── AnswerDTO.cs
│ │ │ ├── AnswerQueryDTO.cs
│ │ │ ├── BulkAnswerDto.cs
│ │ │ ├── BulkAnswersRequest.cs
│ │ │ ├── CorruptedAnswerDto.cs
│ │ │ ├── FilledInAnswerDTO.cs
│ │ │ ├── ObserverAnswersRequest.cs
│ │ │ ├── PollingStationInfoDto.cs
│ │ │ ├── QuestionDTO.cs
│ │ │ ├── SectionAnswersRequest.cs
│ │ │ └── SelectedOptionDto.cs
│ │ ├── Queries
│ │ │ ├── AnswersQuery.cs
│ │ │ ├── FilledInAnswersQuery.cs
│ │ │ └── FormAnswersQuery.cs
│ │ └── VoteMonitor.Api.Answer.csproj
│ ├── VoteMonitor.Api.Auth
│ │ ├── Commands
│ │ │ └── RegisterDeviceIdRequest.cs
│ │ ├── Controllers
│ │ │ ├── AuthorizationControllerBase.cs
│ │ │ ├── AuthorizationV1Controller.cs
│ │ │ └── AuthorizationV2Controller.cs
│ │ ├── Handlers
│ │ │ ├── AdminQueryHandler.cs
│ │ │ ├── ObserverAuthenticationQueryHandler.cs
│ │ │ └── RegisterDeviceIdRequestHandler.cs
│ │ ├── Models
│ │ │ ├── AuthenticateUserRequest.cs
│ │ │ ├── AuthenticateUserRequestV2.cs
│ │ │ ├── AuthenticationResponseModel.cs
│ │ │ ├── RegisteredObserverModel.cs
│ │ │ └── UserInfo.cs
│ │ ├── Queries
│ │ │ ├── NgoAdminApplicationUser.cs
│ │ │ └── ObserverApplicationUser.cs
│ │ └── VoteMonitor.Api.Auth.csproj
│ ├── VoteMonitor.Api.Core
│ │ ├── ApiListResponse.cs
│ │ ├── ApiResponse.cs
│ │ ├── Attributes
│ │ │ └── AllowedExtensions.cs
│ │ ├── ClaimsHelper.cs
│ │ ├── Commands
│ │ │ ├── ClearCache.cs
│ │ │ ├── NotificationRegistrationDataCommand.cs
│ │ │ ├── UploadFileCommand.cs
│ │ │ └── UploadFileCommandV2.cs
│ │ ├── ControllerExtensions.cs
│ │ ├── Controllers
│ │ │ └── CacheController.cs
│ │ ├── Extensions
│ │ │ ├── ClaimsExtensions.cs
│ │ │ ├── DateTimeExtensions.cs
│ │ │ ├── OptionsExtensions.cs
│ │ │ └── QueryExtension.cs
│ │ ├── Handlers
│ │ │ ├── CacheHandler.cs
│ │ │ └── UploadFileHandler.cs
│ │ ├── ListExtensions.cs
│ │ ├── Models
│ │ │ ├── CountyPollingStationLimit.cs
│ │ │ ├── JwtIssuerOptions.cs
│ │ │ ├── UploadedFileResult.cs
│ │ │ └── UserType.cs
│ │ ├── Options
│ │ │ ├── ApplicationCacheOptions.cs
│ │ │ ├── BlobStorageOptions.cs
│ │ │ ├── DefaultNgoOptions.cs
│ │ │ ├── FileStorageType.cs
│ │ │ ├── FirebaseServiceOptions.cs
│ │ │ ├── HashOptions.cs
│ │ │ ├── LocalFileStorageOptions.cs
│ │ │ ├── MobileSecurityOptions.cs
│ │ │ ├── PollingStationsOptions.cs
│ │ │ └── S3StorageOptions.cs
│ │ ├── PagingDefaultsConstants.cs
│ │ ├── PagingModel.cs
│ │ ├── PagingResponseModel.cs
│ │ ├── Services
│ │ │ ├── BlobService.cs
│ │ │ ├── CacheService.cs
│ │ │ ├── ClearTextService.cs
│ │ │ ├── FirebaseService.cs
│ │ │ ├── ICacheService.cs
│ │ │ ├── IFileService.cs
│ │ │ ├── IFirebaseService.cs
│ │ │ ├── IHashService.cs
│ │ │ ├── IPollingStationService.cs
│ │ │ ├── LocalFileService.cs
│ │ │ ├── NoCacheService.cs
│ │ │ ├── S3Service.cs
│ │ │ └── SHA256HashService.cs
│ │ ├── UploadType.cs
│ │ └── VoteMonitor.Api.Core.csproj
│ ├── VoteMonitor.Api.County
│ │ ├── Commands
│ │ │ ├── CreateOrUpdateCounties.cs
│ │ │ ├── CreateOrUpdateMunicipalities.cs
│ │ │ ├── CreateOrUpdateProvinces.cs
│ │ │ ├── PrefillCache.cs
│ │ │ ├── UpdateCounty.cs
│ │ │ ├── UpdateMunicipality.cs
│ │ │ └── UpdateProvince.cs
│ │ ├── Controllers
│ │ │ ├── CacheController.cs
│ │ │ ├── CountyController.cs
│ │ │ ├── MunicipalityController.cs
│ │ │ └── ProvinceController.cs
│ │ ├── Handlers
│ │ │ ├── CacheHandler.cs
│ │ │ ├── CountiesCommandHandler.cs
│ │ │ ├── MunicipalityCommandHandler.cs
│ │ │ └── ProvincesCommandHandler.cs
│ │ ├── Models
│ │ │ ├── CountiesUploadRequest.cs
│ │ │ ├── CountyCsvModel.cs
│ │ │ ├── CountyModel.cs
│ │ │ ├── ErrorModel.cs
│ │ │ ├── MunicipalitiesUploadRequest.cs
│ │ │ ├── MunicipalityCsvModel.cs
│ │ │ ├── MunicipalityModel.cs
│ │ │ ├── MunicipalityModelV2.cs
│ │ │ ├── ProvinceCsvModel.cs
│ │ │ ├── ProvinceModel.cs
│ │ │ ├── ProvincesUploadRequest.cs
│ │ │ ├── UpdateCountyRequest.cs
│ │ │ ├── UpdateMunicipalityRequest.cs
│ │ │ └── UpdateProvinceRequest.cs
│ │ ├── Queries
│ │ │ ├── GetAllCounties.cs
│ │ │ ├── GetAllCountiesByProvinceCode.cs
│ │ │ ├── GetAllMunicipalities.cs
│ │ │ ├── GetAllMunicipalitiesByCountyCode.cs
│ │ │ ├── GetAllProvinces.cs
│ │ │ ├── GetCountiesForExport.cs
│ │ │ ├── GetCountyById.cs
│ │ │ ├── GetMunicipalitiesForExport.cs
│ │ │ ├── GetMunicipalityById.cs
│ │ │ ├── GetProvinceById.cs
│ │ │ └── GetProvincesForExport.cs
│ │ └── VoteMonitor.Api.County.csproj
│ ├── VoteMonitor.Api.DataExport
│ │ ├── Controllers
│ │ │ ├── DataExportController.cs
│ │ │ └── DataExportV2Controller.cs
│ │ ├── FileGenerator
│ │ │ ├── CsvGenerator.cs
│ │ │ ├── CsvUtility.cs
│ │ │ ├── ExcelFile.cs
│ │ │ ├── ExcelUtility.cs
│ │ │ └── ICsvGenerator.cs
│ │ ├── Handlers
│ │ │ ├── CsvGeneratorQueryHandler.cs
│ │ │ ├── DataExportQueryHandler.cs
│ │ │ └── GetExcelDbCommandHandler.cs
│ │ ├── Models
│ │ │ ├── ExportModelDto.cs
│ │ │ └── NotesExportModel.cs
│ │ ├── Queries
│ │ │ ├── GenerateCSVFile.cs
│ │ │ ├── GenerateNotesCSVFile.cs
│ │ │ ├── GetDataForExport.cs
│ │ │ ├── GetExcelDbCommand.cs
│ │ │ └── GetNotesForExport.cs
│ │ └── VoteMonitor.Api.DataExport.csproj
│ ├── VoteMonitor.Api.Form
│ │ ├── CommandHandlers
│ │ │ ├── AddFormCommandHandler.cs
│ │ │ ├── AddOptionCommandHandler.cs
│ │ │ ├── DeleteFormCommandHandler.cs
│ │ │ ├── UpdateFormCommandHandler.cs
│ │ │ └── UpdateOptionCommandHandler.cs
│ │ ├── Commands
│ │ │ ├── AddFormCommand.cs
│ │ │ ├── AddOptionCommand.cs
│ │ │ ├── DeleteFormCommand.cs
│ │ │ ├── DeleteQuestionCommand.cs
│ │ │ ├── DeleteSectionCommand.cs
│ │ │ ├── UpdateFormCommand.cs
│ │ │ └── UpdateOptionCommand.cs
│ │ ├── Controllers
│ │ │ ├── ExportController.cs
│ │ │ ├── FormController.cs
│ │ │ └── OptionController.cs
│ │ ├── DependencyInjectionExtensions.cs
│ │ ├── Handlers
│ │ │ ├── DeleteQuestionHandler.cs
│ │ │ └── DeleteSectionHandler.cs
│ │ ├── Mappers
│ │ │ ├── HierarchicalMapper.cs
│ │ │ ├── IEntityMapper.cs
│ │ │ ├── IUpdateOrCreateEntityMapper.cs
│ │ │ └── UpdateOrCreateEntityMapper.cs
│ │ ├── Models
│ │ │ ├── FilledFormResponseModel.cs
│ │ │ ├── FormDTO.cs
│ │ │ ├── FormDetailsModel.cs
│ │ │ ├── FormResponseModel.cs
│ │ │ ├── FormSectionDTO.cs
│ │ │ ├── FormVersionsModel.cs
│ │ │ ├── OptionToQuestionDTO.cs
│ │ │ ├── Options
│ │ │ │ ├── CreateOptionModel.cs
│ │ │ │ ├── OptionDTO.cs
│ │ │ │ └── OptionModel.cs
│ │ │ └── QuestionDTO.cs
│ │ ├── Profiles
│ │ │ ├── FormProfile.cs
│ │ │ ├── FormSectionProfile.cs
│ │ │ ├── OptionProfile.cs
│ │ │ ├── OptionToQuestionProfile.cs
│ │ │ └── QuestionProfile.cs
│ │ ├── Queries
│ │ │ ├── ExistsFormByCodeOrIdQuery.cs
│ │ │ ├── ExistsFormByIdQuery.cs
│ │ │ ├── FetchAllOptionsQuery.cs
│ │ │ ├── FormQuestionQuery.cs
│ │ │ ├── FormVersionQuery.cs
│ │ │ ├── GetFilledFormsQuery.cs
│ │ │ ├── GetFormsQuery.cs
│ │ │ └── GetOptionByIdCommand.cs
│ │ ├── QueryHandlers
│ │ │ ├── FetchAllOptionsQueryHandler.cs
│ │ │ ├── FormQuestionQueryHandler.cs
│ │ │ ├── FormVersionQueryHandler.cs
│ │ │ ├── GetFilledFormsQueryHandler.cs
│ │ │ ├── GetFormExistsByCodeOrIdQueryHandler.cs
│ │ │ ├── GetFormExistsByIdQueryHandler.cs
│ │ │ ├── GetFormsQueryHandler.cs
│ │ │ └── GetOptionByIdQueryHandler.cs
│ │ └── VoteMonitor.Api.Form.csproj
│ ├── VoteMonitor.Api.Location
│ │ ├── Commands
│ │ │ ├── ImportPollingStationsCommand.cs
│ │ │ ├── PrefillCache.cs
│ │ │ ├── RegisterPollingStationCommand.cs
│ │ │ └── UpdatePollingSectionCommand.cs
│ │ ├── Controllers
│ │ │ ├── CacheController.cs
│ │ │ └── PollingStationController.cs
│ │ ├── Exceptions
│ │ │ └── PollingStationImportException.cs
│ │ ├── Handlers
│ │ │ ├── PollingStationAssignmentHandler.cs
│ │ │ ├── PollingStationHandler.cs
│ │ │ ├── PollingStationQueryHandler.cs
│ │ │ ├── PrefillCacheHandler.cs
│ │ │ ├── RegisterPollingSectionHandler.cs
│ │ │ └── UpdatePollingStationHandler.cs
│ │ ├── Models
│ │ │ ├── AddPollingStationInfo.cs
│ │ │ ├── PollingStationCsvModel.cs
│ │ │ ├── PollingStationsUploadRequest.cs
│ │ │ ├── ResultValues
│ │ │ │ ├── PollingStationImportErrorCode.cs
│ │ │ │ └── PollingStationImportResultValue.cs
│ │ │ └── UpdatePollingStationInfo.cs
│ │ ├── Queries
│ │ │ ├── GetPollingStationId.cs
│ │ │ └── PollingStationsAssignmentQuery.cs
│ │ ├── Services
│ │ │ └── PollingStationService.cs
│ │ └── VoteMonitor.Api.Location.csproj
│ ├── VoteMonitor.Api.Ngo
│ │ ├── Commands
│ │ │ ├── CreateNgo.cs
│ │ │ ├── CreateNgoAdmin.cs
│ │ │ ├── DeleteNgo.cs
│ │ │ ├── DeleteNgoAdmin.cs
│ │ │ ├── SetNgoOrganizerFlag.cs
│ │ │ ├── SetNgoStatusFlag.cs
│ │ │ ├── UpdateNgo.cs
│ │ │ └── UpdateNgoAdmin.cs
│ │ ├── Controllers
│ │ │ ├── NgoAdminController.cs
│ │ │ └── NgoController.cs
│ │ ├── Handlers
│ │ │ ├── NgoAdminCommandsHandler.cs
│ │ │ ├── NgoAdminQueryHandler.cs
│ │ │ ├── NgoCommandsHandler.cs
│ │ │ └── NgoQueryHandler.cs
│ │ ├── Models
│ │ │ ├── CreateUpdateNgoAdminModel.cs
│ │ │ ├── CreateUpdateNgoModel.cs
│ │ │ ├── NgoAdminModel.cs
│ │ │ ├── NgoModel.cs
│ │ │ ├── PatchNgoOrganizerModel.cs
│ │ │ └── PatchNgoStatusModel.cs
│ │ ├── Queries
│ │ │ ├── GetAllNgoAdmins.cs
│ │ │ ├── GetAllNgos.cs
│ │ │ ├── GetNgoAdminDetails.cs
│ │ │ └── GetNgoDetails.cs
│ │ └── VoteMonitor.Api.Ngo.csproj
│ ├── VoteMonitor.Api.Note
│ │ ├── Commands
│ │ │ ├── AddNoteCommand.cs
│ │ │ ├── AddNoteCommandV2.cs
│ │ │ └── AddNoteToUnknownPollingStation.cs
│ │ ├── Controllers
│ │ │ └── NoteController.cs
│ │ ├── Handlers
│ │ │ └── NoteQueriesHandler.cs
│ │ ├── Models
│ │ │ ├── NoteFilterModel.cs
│ │ │ ├── NoteModel.cs
│ │ │ ├── UploadNoteModel.cs
│ │ │ ├── UploadNoteModelV2.cs
│ │ │ ├── UploadNoteResult.cs
│ │ │ └── UploadNoteResultV2.cs
│ │ ├── Queries
│ │ │ └── NoteQuery.cs
│ │ └── VoteMonitor.Api.Note.csproj
│ ├── VoteMonitor.Api.Notification
│ │ ├── Commands
│ │ │ ├── NotificationListCommand.cs
│ │ │ ├── SendNotificationCommand.cs
│ │ │ └── SendNotificationToAllCommand.cs
│ │ ├── Controllers
│ │ │ └── NotificationController.cs
│ │ ├── Handlers
│ │ │ ├── NotificationListQueryHandler.cs
│ │ │ └── NotificationRegistrationDataHandler.cs
│ │ ├── Models
│ │ │ ├── NotificationModel.cs
│ │ │ ├── NotificationRegistrationDataModel.cs
│ │ │ ├── SendNotificationModel.cs
│ │ │ └── SendNotificationToAllModel.cs
│ │ ├── Queries
│ │ │ └── NotificationListQuery.cs
│ │ └── VoteMonitor.Api.Notification.csproj
│ ├── VoteMonitor.Api.Observer
│ │ ├── Commands
│ │ │ ├── DeleteObserverCommand.cs
│ │ │ ├── EditObserverCommand.cs
│ │ │ ├── ImportObserversRequest.cs
│ │ │ ├── NewObserverCommand.cs
│ │ │ ├── ObserverCountCommand.cs
│ │ │ ├── ObserverGenerateCommand.cs
│ │ │ ├── ObserverListCommand.cs
│ │ │ ├── RemoveDeviceIdCommand.cs
│ │ │ ├── ResetDeviceCommand.cs
│ │ │ └── ResetPasswordCommand.cs
│ │ ├── Controllers
│ │ │ └── ObserverController.cs
│ │ ├── Handlers
│ │ │ ├── ActiveObserversQueryHandler.cs
│ │ │ ├── CheckObserverExistsHandler.cs
│ │ │ ├── GenerateObserversHandler.cs
│ │ │ ├── ObserverCountQueryHandler.cs
│ │ │ ├── ObserverListQueryHandler.cs
│ │ │ ├── ObserverRequestsHandler.cs
│ │ │ ├── RemoveDeviceIdHandler.cs
│ │ │ ├── ResetDeviceHandler.cs
│ │ │ └── ResetPasswordHandler.cs
│ │ ├── Models
│ │ │ ├── ActiveObserverFilter.cs
│ │ │ ├── EditObserverModel.cs
│ │ │ ├── GeneratedObserver.cs
│ │ │ ├── NewObserverModel.cs
│ │ │ ├── ObserverModel.cs
│ │ │ ├── ObserversImportModel.cs
│ │ │ ├── RemoveDeviceIdModel.cs
│ │ │ └── ResetModel.cs
│ │ ├── Queries
│ │ │ ├── ActiveObserversQuery.cs
│ │ │ ├── GetObserverDetails.cs
│ │ │ └── ObserverListQuery.cs
│ │ ├── Utils
│ │ │ ├── RandomNumberGenerator.cs
│ │ │ └── RandomObserverBuilder.cs
│ │ └── VoteMonitor.Api.Observer.csproj
│ ├── VoteMonitor.Api.PollingStation
│ │ ├── Commands
│ │ │ └── ClearAllPollingStationsCommand.cs
│ │ ├── Controllers
│ │ │ ├── PollingStationController.cs
│ │ │ └── PollingStationInfoController.cs
│ │ ├── Handlers
│ │ │ ├── CheckPollingStationExistsHandler.cs
│ │ │ ├── ClearAllPollingStationHandler.cs
│ │ │ ├── CreatePollingStationInfoHandler.cs
│ │ │ ├── GetPollingStationByIdHandler.cs
│ │ │ ├── GetPollingStationsHadler.cs
│ │ │ ├── UpdatePollingStationInfoHandler.cs
│ │ │ └── UpdatePollingStationsHandler.cs
│ │ ├── Models
│ │ │ ├── CreatePollingStationInfoModel.cs
│ │ │ ├── GetPollingStationModel.cs
│ │ │ ├── PollingStationsFilterModel.cs
│ │ │ ├── UpdatePollingStationInfo.cs
│ │ │ └── UpdatePollingStationModel.cs
│ │ ├── Queries
│ │ │ ├── CheckPollingStationExists.cs
│ │ │ ├── CreatePollingStationInfo.cs
│ │ │ ├── GetPollingStationById.cs
│ │ │ ├── GetPollingStations.cs
│ │ │ ├── UpdatePollingStation.cs
│ │ │ └── UpdatePollingStationInfo.cs
│ │ └── VoteMonitor.Api.PollingStation.csproj
│ ├── VoteMonitor.Api.Statistics
│ │ ├── Controllers
│ │ │ └── StatisticsController.cs
│ │ ├── Handlers
│ │ │ ├── MiniStatisticsQueryHandler.cs
│ │ │ ├── StatisticsQueryBuilder.cs
│ │ │ └── StatisticsQueryHandler.cs
│ │ ├── Models
│ │ │ ├── FilterStatisticsModel.cs
│ │ │ ├── OptionStatisticsModel.cs
│ │ │ ├── OptionsFilterModel.cs
│ │ │ ├── SimpleStatisticsModel.cs
│ │ │ ├── StatisticsGroupingTypes.cs
│ │ │ └── StatisticsOptionsModel.cs
│ │ ├── Queries
│ │ │ ├── AnswersQuery.cs
│ │ │ ├── CountiesVisitedQuery.cs
│ │ │ ├── FlaggedAnswersQuery.cs
│ │ │ ├── LoggedInObserversQuery.cs
│ │ │ ├── NotesUploadedQuery.cs
│ │ │ ├── StationsVisitedQuery.cs
│ │ │ ├── StatisticsObserverNumberQuery.cs
│ │ │ ├── StatisticsOptionsQuery.cs
│ │ │ ├── StatisticsPaginatedQuery.cs
│ │ │ ├── StatisticsQuery.cs
│ │ │ └── StatisticsTopIrregularitiesQuery.cs
│ │ └── VoteMonitor.Api.Statistics.csproj
│ ├── VoteMonitor.Api
│ │ ├── Dockerfile
│ │ ├── Extensions
│ │ │ ├── ExceptionHandler.cs
│ │ │ ├── HealthChecks
│ │ │ │ ├── AzureBlobStorageHealthChecksExtensions.cs
│ │ │ │ ├── ConditionalHealthCheck.cs
│ │ │ │ ├── FirebaseHealthChecksExtensions.cs
│ │ │ │ └── S3HealthChecksExtensions.cs
│ │ │ ├── HealthChecksConfiguration.cs
│ │ │ ├── JwtConfigurationExtensions.cs
│ │ │ ├── LoggingConfiguration.cs
│ │ │ ├── ServicesExtensions.cs
│ │ │ └── SwaggerConfiguration.cs
│ │ ├── ImportHelper.cs
│ │ ├── Program.cs
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── VoteMonitor.Api.csproj
│ │ └── appsettings.json
│ ├── VoteMonitor.Entities
│ │ ├── Answer.cs
│ │ ├── AnswerCorrupted.cs
│ │ ├── AnswerQueryInfo.cs
│ │ ├── County.cs
│ │ ├── EfBuilderExtensions.cs
│ │ ├── ExportModel.cs
│ │ ├── Form.cs
│ │ ├── FormSection.cs
│ │ ├── IHierarchicalEntity.cs
│ │ ├── IIdentifiableEntity.cs
│ │ ├── MobileUniqueIdType.cs
│ │ ├── Municipality.cs
│ │ ├── Ngo.cs
│ │ ├── NgoAdmin.cs
│ │ ├── Note.cs
│ │ ├── NoteCorrupted.cs
│ │ ├── NotesAttachmentCorrupted.cs
│ │ ├── NotesAttachments.cs
│ │ ├── Notification.cs
│ │ ├── NotificationRecipient.cs
│ │ ├── NotificationRegistrationData.cs
│ │ ├── Observer.cs
│ │ ├── Option.cs
│ │ ├── OptionToQuestion.cs
│ │ ├── PollingStation.cs
│ │ ├── PollingStationInfo.cs
│ │ ├── PollingStationInfoCorrupted.cs
│ │ ├── Province.cs
│ │ ├── Question.cs
│ │ ├── QuestionType.cs
│ │ ├── Statistici.cs
│ │ ├── VoteMonitor.Entities.csproj
│ │ └── VotingContext.cs
│ ├── VotingIrregularities.Domain.Migrator
│ │ ├── ConfigurationHelper.cs
│ │ ├── ContextFactory.cs
│ │ ├── Dockerfile
│ │ ├── Migrations
│ │ │ ├── 20230818075147_InitialPostgresMigration.Designer.cs
│ │ │ ├── 20230818075147_InitialPostgresMigration.cs
│ │ │ ├── 20230829162705_CleanupPollingStations.Designer.cs
│ │ │ ├── 20230829162705_CleanupPollingStations.cs
│ │ │ ├── 20230906055404_PollingStationsRefactor.Designer.cs
│ │ │ ├── 20230906055404_PollingStationsRefactor.cs
│ │ │ ├── 20230907120427_ChangeLimits.Designer.cs
│ │ │ ├── 20230907120427_ChangeLimits.cs
│ │ │ ├── 20230914091458_RenameCommunity.Designer.cs
│ │ │ ├── 20230914091458_RenameCommunity.cs
│ │ │ ├── 20230922074009_AddAttachmentFileName.Designer.cs
│ │ │ ├── 20230922074009_AddAttachmentFileName.cs
│ │ │ ├── 20230922190024_ProvincesTable.Designer.cs
│ │ │ ├── 20230922190024_ProvincesTable.cs
│ │ │ ├── 20230926071737_NewPollingStationsInfo.Designer.cs
│ │ │ ├── 20230926071737_NewPollingStationsInfo.cs
│ │ │ ├── 20231005064956_AddFileNameColumn.Designer.cs
│ │ │ ├── 20231005064956_AddFileNameColumn.cs
│ │ │ ├── 20231006085620_ChangeAttachmentsLimits.Designer.cs
│ │ │ ├── 20231006085620_ChangeAttachmentsLimits.cs
│ │ │ ├── 20231010171443_ChangeCodeSizeLimit.Designer.cs
│ │ │ ├── 20231010171443_ChangeCodeSizeLimit.cs
│ │ │ ├── 20231014093815_AddCorruptedRecoveryTables.Designer.cs
│ │ │ ├── 20231014093815_AddCorruptedRecoveryTables.cs
│ │ │ ├── 20231014104127_AddMissingColumn.Designer.cs
│ │ │ ├── 20231014104127_AddMissingColumn.cs
│ │ │ ├── 20231015061038_AddCorruptedAnswers.Designer.cs
│ │ │ ├── 20231015061038_AddCorruptedAnswers.cs
│ │ │ └── VoteMonitorContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── VotingIrregularities.Domain.Migrator.csproj
│ │ └── appsettings.json
│ └── VotingIrregularities.Domain.Seed
│ │ ├── ConfigurationHelper.cs
│ │ ├── Dockerfile
│ │ ├── Options
│ │ ├── AdminSeed.cs
│ │ ├── HashServiceType.cs
│ │ ├── NgoSeed.cs
│ │ ├── ObserverSeed.cs
│ │ └── SeedOption.cs
│ │ ├── Program.cs
│ │ ├── Properties
│ │ └── launchSettings.json
│ │ ├── Services
│ │ ├── ClearTextService.cs
│ │ ├── IHashService.cs
│ │ └── SHA256HashService.cs
│ │ ├── VotingContextSeeder.cs
│ │ ├── VotingIrregularities.Domain.Seed.csproj
│ │ ├── appsettings.Development.json
│ │ └── appsettings.json
├── docker-compose.yml
└── test
│ ├── VoteMonitor.Api.PollingStation.Tests
│ ├── Handlers
│ │ ├── CheckPollingStationExistsHandlerTests.cs
│ │ ├── CreatePollingStationInfoHandlerTests.cs
│ │ ├── GetPollingStationsHandlerTests.cs
│ │ └── UpdatePollingStationsHandlerTests.cs
│ ├── PollingStationBuilder.cs
│ └── VoteMonitor.Api.PollingStation.Tests.csproj
│ ├── VoteMonitor.Api.Tests
│ ├── Extensions
│ │ └── ServiceExtensions_ConditionalChecksRegistrationsTests.cs
│ └── VoteMonitor.Api.Tests.csproj
│ └── VotingIrregularities.Tests
│ ├── AnswerHandlerTests.cs
│ ├── AnswersApi
│ └── AnswerQueryHandlerShould.cs
│ ├── CountyApi
│ └── CountiesCommandHandlerTests.cs
│ ├── DateTimeTest.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── VotingIrregularities.Tests.csproj
│ └── appsettings.json
└── terraform
├── .gitignore
├── .terraform.lock.hcl
├── acm.tf
├── data.tf
├── database.tf
├── ec2_bastion.tf
├── ecs.tf
├── iam.tf
├── lb.tf
├── locals.tf
├── modules
├── ecs-cluster
│ ├── assets
│ │ └── user_data.sh
│ ├── cloudwatch.tf
│ ├── data.tf
│ ├── iam.tf
│ ├── locals.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── service_discovery.tf
│ └── variables.tf
├── ecs-service
│ ├── autoscaling.tf
│ ├── data.tf
│ ├── ecs_task_definition.tf
│ ├── iam.tf
│ ├── lb.tf
│ ├── locals.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── route53.tf
│ ├── service_discovery.tf
│ └── variables.tf
└── s3
│ ├── main.tf
│ ├── outputs.tf
│ ├── random.tf
│ └── variables.tf
├── networking_eips.tf
├── networking_gateways.tf
├── networking_routing.tf
├── networking_subnets.tf
├── networking_vpc.tf
├── outputs.tf
├── providers.tf
├── secrets.tf
├── service_api.tf
├── service_migrator.tf
├── service_seed.tf
└── variables.tf
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These owners will be the default owners for everything in
2 | # the repo. Unless a later match takes precedence,
3 | # they will be requested for review when someone
4 | # opens a pull request.
5 | * @aniri @idormenco
6 |
7 | # More details on creating a codeowners file:
8 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
9 |
--------------------------------------------------------------------------------
/.github/workflows/dotnetcore.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Setup .NET Core
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: '7.0.x'
20 |
21 | - name: Build with dotnet
22 | run: dotnet build ./src/VotingIrregularities.sln --configuration Release
23 |
24 | - name: Test with dotnet
25 | run: dotnet test ./src/VotingIrregularities.sln --configuration Release
26 |
--------------------------------------------------------------------------------
/bombardier/attachments/image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image1.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image2.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image3.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image4.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image5.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image6.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image7.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image8.jpg
--------------------------------------------------------------------------------
/bombardier/attachments/image9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/bombardier/attachments/image9.jpg
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | Please see more info and docs about the MV apps [in the wiki](https://github.com/code4romania/monitorizare-vot/wiki).
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/counties.csv:
--------------------------------------------------------------------------------
1 | Id,Code,Name,NumberOfPollingStations,Diaspora,Order
2 | 1,AA,County AA,2,0,1
3 | 2,BB,County BB,1,0,2
4 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/form-sections.csv:
--------------------------------------------------------------------------------
1 | Id,Code,Description,IdForm,OrderNumber
2 | 1,A,A Form Section,1,1
3 | 2,B,Other Form Section,1,2
4 | 3,C,Some Form Section,2,1
5 | 4,D,Another Form Section,3,1
6 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/forms.csv:
--------------------------------------------------------------------------------
1 | Id,Code,Description,CurrentVersion,Diaspora,Draft,Order
2 | 1,A,First Form,1,0,0,1
3 | 2,B,Second form,2,0,0,2
4 | 3,C,Draft form,1,0,1,3
5 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/ngo-admin.csv:
--------------------------------------------------------------------------------
1 | Id,IdNgo,Account,Password
2 | 1,1,master_admin,password
3 | 2,2,regular_admin,password
4 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/ngos.csv:
--------------------------------------------------------------------------------
1 | Id,ShortName,Name,Organizer,IsActive
2 | 1,Organizer,Organizer NGO,1,1
3 | 2,Regular,Regular NGO,0,1
4 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/observers.csv:
--------------------------------------------------------------------------------
1 | Id,FromTeam,IdNgo,Phone,Name,Pin,MobileDeviceId,DeviceRegisterDate,IsTestObserver,MobileDeviceIdType
2 | 1,0,1,0123456789,Observer 1,1234,none,2020-10-21 17:35:44.830,0,0
3 | 2,0,2,9876543210,Observer 2,1234,none,2020-10-21 17:35:44.830,0,0
4 | 3,0,1,12345678,Test Observer,1234,none,2020-10-21 17:35:44.830,1,0
5 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/options-to-questions.csv:
--------------------------------------------------------------------------------
1 | Id,IdQuestion,IdOption,Flagged
2 | 1,1,1,0
3 | 2,1,2,0
4 | 3,2,1,0
5 | 4,2,2,0
6 | 5,3,1,0
7 | 6,3,2,0
8 | 7,3,3,1
9 | 8,4,1,0
10 | 9,4,2,0
11 | 10,4,3,1
12 | 11,5,1,0
13 | 12,5,2,0
14 | 13,6,1,0
15 | 14,6,2,0
16 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/options.csv:
--------------------------------------------------------------------------------
1 | Id,IsFreeText,Text,Hint,OrderNumber
2 | 1,0,Option one,NULL,1
3 | 2,0,Option two,NULL,2
4 | 3,1,Other,NULL,3
5 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/polling-stations.csv:
--------------------------------------------------------------------------------
1 | Id,Address,Coordinates,AdministrativeTerritoryCode,IdCounty,TerritoryCode,Number
2 | 1,"Some Address 1",NULL,111,1,123,1
3 | 2,"Some Address 2",NULL,222,1,234,2
4 | 3,"Some Address 3",NULL,333,2,345,1
5 |
--------------------------------------------------------------------------------
/docs/dummy-db-data/questions.csv:
--------------------------------------------------------------------------------
1 | Id,Code,IdSection,QuestionType,Text,Hint,OrderNumber
2 | 1,A1,1,0,"Multiple choice question?",NULL,1
3 | 2,A2,1,1,"Single choice question?",NULL,2
4 | 3,B1,2,2,"Single choice question with free text option?",NULL,1
5 | 4,B2,2,3,"Multiple choice question with free text option?",NULL,2
6 | 5,C1,3,1,"Single choice question?",NULL,1
7 | 6,C2,4,0,"Multiple choice question?",NULL,1
8 |
--------------------------------------------------------------------------------
/docs/images/data_model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/data_model.png
--------------------------------------------------------------------------------
/docs/images/sequence_diagrams/sequence_diagram_mobile_answers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/sequence_diagrams/sequence_diagram_mobile_answers.png
--------------------------------------------------------------------------------
/docs/images/sequence_diagrams/sequence_diagram_mobile_forms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/sequence_diagrams/sequence_diagram_mobile_forms.png
--------------------------------------------------------------------------------
/docs/images/sequence_diagrams/sequence_diagram_mobile_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/sequence_diagrams/sequence_diagram_mobile_login.png
--------------------------------------------------------------------------------
/docs/images/sequence_diagrams/sequence_diagram_mobile_login_v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/sequence_diagrams/sequence_diagram_mobile_login_v2.png
--------------------------------------------------------------------------------
/docs/images/sequence_diagrams/sequence_diagram_mobile_manual_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/sequence_diagrams/sequence_diagram_mobile_manual_sync.png
--------------------------------------------------------------------------------
/docs/images/sequence_diagrams/sequence_diagram_mobile_notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/sequence_diagrams/sequence_diagram_mobile_notes.png
--------------------------------------------------------------------------------
/docs/images/sequence_diagrams/sequence_diagram_mobile_pick_section.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/sequence_diagrams/sequence_diagram_mobile_pick_section.jpeg
--------------------------------------------------------------------------------
/docs/images/vote_monitor_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/docs/images/vote_monitor_diagram.png
--------------------------------------------------------------------------------
/forms-parser/README.md:
--------------------------------------------------------------------------------
1 | Install dependencies
2 | ```js
3 | pnpm install
4 | ```
5 | Running the app
6 | ```js
7 | node form-parser.js -f "forms-2023-10-11.xlsx" -s 1 -o "output"
8 | ```
--------------------------------------------------------------------------------
/forms-parser/forms-2023-10-05.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/forms-parser/forms-2023-10-05.xlsx
--------------------------------------------------------------------------------
/forms-parser/forms-2023-10-10-en.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/forms-parser/forms-2023-10-10-en.xlsx
--------------------------------------------------------------------------------
/forms-parser/forms-2023-10-10-pl.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/forms-parser/forms-2023-10-10-pl.xlsx
--------------------------------------------------------------------------------
/forms-parser/forms-2023-10-10.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/forms-parser/forms-2023-10-10.xlsx
--------------------------------------------------------------------------------
/forms-parser/forms-2023-10-11.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/forms-parser/forms-2023-10-11.xlsx
--------------------------------------------------------------------------------
/forms-parser/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "forms-parser",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "form-parser.js",
6 | "type": "module",
7 | "scripts": {
8 | "form-parser": " node form-parser.js -f forms-2023-10-11.xlsx -s 1 -o output"
9 | },
10 | "keywords": [],
11 | "author": "Ion Dormenco",
12 | "license": "MIT",
13 | "dependencies": {
14 | "lodash-es": "^4.17.21",
15 | "nanoid": "^4.0.2",
16 | "read-excel-file": "^5.6.1",
17 | "yargs": "^17.7.2"
18 | }
19 | }
--------------------------------------------------------------------------------
/requests/image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/requests/image1.jpg
--------------------------------------------------------------------------------
/requests/polish-data-2023-10-10.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/monitorizare-vot/b575f81e3d741a8879bfeba59d49756b0075e26b/requests/polish-data-2023-10-10.xlsx
--------------------------------------------------------------------------------
/requests/polish_provinces_2023.csv:
--------------------------------------------------------------------------------
1 | "Id","Code","Name","Order"
2 | 1,"02","dolnośląskie",1
3 | 2,"04","kujawsko-pomorskie",2
4 | 3,"06","lubelskie",3
5 | 4,"08","lubuskie",4
6 | 5,"10","łódzkie",5
7 | 6,"12","małopolskie",6
8 | 7,"14","mazowieckie",7
9 | 8,"16","opolskie",8
10 | 9,"18","podkarpackie",9
11 | 10,"20","podlaskie",10
12 | 11,"22","pomorskie",11
13 | 12,"24","śląskie",12
14 | 13,"26","świętokrzyskie",13
15 | 14,"28","warmińsko-mazurskie",14
16 | 15,"30","wielkopolskie",15
17 | 16,"32","zachodniopomorskie",16
18 | 17,"zagranica","zagranica",17
19 | 18,"statki","statki",18
20 |
--------------------------------------------------------------------------------
/src/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.dockerignore
2 | **/.env
3 | **/.git
4 | **/.gitignore
5 | **/.vs
6 | **/.vscode
7 | **/*.*proj.user
8 | **/azds.yaml
9 | **/charts
10 | **/bin
11 | **/obj
12 | **/Dockerfile
13 | **/Dockerfile.develop
14 | **/docker-compose.yml
15 | **/docker-compose.*.yml
16 | **/*.dbmdl
17 | **/*.jfm
18 | **/secrets.dev.yaml
19 | **/values.dev.yaml
20 | **/.toolstarget
--------------------------------------------------------------------------------
/src/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
3 |
4 | 1701;1702;1591;1573
5 | $(SolutionDir)\api-docs\$(MSBuildProjectName).xml
6 |
7 |
--------------------------------------------------------------------------------
/src/VotingIrregularities.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | DTO
3 | NG
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Commands/BulkAnswers.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Answer.Models;
3 |
4 | namespace VoteMonitor.Api.Answer.Commands;
5 |
6 | public record BulkAnswers : IRequest
7 | {
8 | public BulkAnswers(int observerId, IEnumerable answers)
9 | {
10 | ObserverId = observerId;
11 | Answers = answers.ToList().AsReadOnly();
12 | }
13 |
14 | public int ObserverId { get; }
15 |
16 | public IReadOnlyCollection Answers { get; }
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Commands/FillInAnswerCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Answer.Models;
3 |
4 | namespace VoteMonitor.Api.Answer.Commands;
5 |
6 | public record FillInAnswerCommand : IRequest
7 | {
8 | public FillInAnswerCommand(int observerId, IEnumerable answers, IEnumerable corruptedAnswers)
9 | {
10 | ObserverId = observerId;
11 | Answers = answers.ToList().AsReadOnly();
12 | CorruptedAnswers = corruptedAnswers.ToList().AsReadOnly();
13 | }
14 |
15 | public int ObserverId { get; }
16 | public IReadOnlyCollection Answers { get; }
17 | public IReadOnlyCollection CorruptedAnswers { get; }
18 | }
19 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/AnswerDTO.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class AnswerDto
4 | {
5 | public int QuestionId { get; set; }
6 | public int PollingStationId { get; set; }
7 | public string CountyCode { get; set; }
8 | public int PollingStationNumber { get; set; }
9 | public List Options { get; set; }
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/AnswerQueryDTO.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class AnswerQueryDto
4 | {
5 | public int ObserverId { get; set; }
6 | public int PollingStationId { get; set; }
7 | public string ObserverName { get; set; }
8 | public string ObserverPhoneNumber { get; set; }
9 | public string PollingStationName { get; set; }
10 | public DateTime LastModified { get; set; }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/BulkAnswerDto.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.Answer.Models;
4 |
5 | public class BulkAnswerDto
6 | {
7 | [Required]
8 | public int QuestionId { get; set; }
9 |
10 | [Required(AllowEmptyStrings = false)]
11 | public string CountyCode { get; set; }
12 |
13 | [Required(AllowEmptyStrings = false)]
14 | public string MunicipalityCode { get; set; }
15 |
16 | [Required(AllowEmptyStrings = false)]
17 | public int PollingStationNumber { get; set; }
18 |
19 | public List Options { get; set; }
20 | }
21 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/BulkAnswersRequest.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class BulkAnswersRequest
4 | {
5 | public BulkAnswerDto[] Answers { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/CorruptedAnswerDto.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class CorruptedAnswerDto
4 | {
5 | public int QuestionId { get; set; }
6 | public string CountyCode { get; set; }
7 | public string MunicipalityCode { get; set; }
8 | public int PollingStationNumber { get; set; }
9 | public List Options { get; set; }
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/FilledInAnswerDTO.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class FilledInAnswerDto
4 | {
5 | public int OptionId { get; set; }
6 | public string Text { get; set; }
7 | public bool IsFreeText { get; set; }
8 | public string Value { get; set; }
9 | public bool IsFlagged { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/ObserverAnswersRequest.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class ObserverAnswersRequest
4 | {
5 | public int PollingStationId { get; set; }
6 | public int ObserverId { get; set; }
7 | }
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/PollingStationInfoDto.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class PollingStationInfoDto
4 | {
5 | public DateTime LastModified { get; set; }
6 | public DateTime? ObserverArrivalTime { get; set; }
7 | public DateTime? ObserverLeaveTime { get; set; }
8 |
9 | public int NumberOfVotersOnTheList { get; set; }
10 |
11 | public int NumberOfCommissionMembers { get; set; }
12 |
13 | public int NumberOfFemaleMembers { get; set; }
14 |
15 | public int MinPresentMembers { get; set; }
16 |
17 | public bool ChairmanPresence { get; set; }
18 |
19 | public bool SinglePollingStationOrCommission { get; set; }
20 |
21 | public bool AdequatePollingStationSize { get; set; }
22 | }
23 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/QuestionDTO.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class QuestionDto
4 | where T : class
5 | {
6 | public int Id { get; set; }
7 | public string Text { get; set; }
8 | public int QuestionTypeId { get; set; }
9 | public string QuestionId { get; set; }
10 | public string FormCode { get; set; }
11 |
12 | public IList Answers { get; set; }
13 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/SectionAnswersRequest.cs:
--------------------------------------------------------------------------------
1 | using VoteMonitor.Api.Core;
2 |
3 | namespace VoteMonitor.Api.Answer.Models;
4 |
5 | public class SectionAnswersRequest : PagingModel
6 | {
7 | public bool IsUrgent { get; set; }
8 | public string County { get; set; }
9 | public int PollingStationNumber { get; set; }
10 | public int ObserverId { get; set; }
11 | public string ObserverPhoneNumber { get; set; }
12 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Models/SelectedOptionDto.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Answer.Models;
2 |
3 | public class SelectedOptionDto
4 | {
5 | public int OptionId { get; set; }
6 | public string Value { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Queries/AnswersQuery.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Answer.Models;
3 | using VoteMonitor.Api.Core;
4 |
5 | namespace VoteMonitor.Api.Answer.Queries;
6 |
7 | public class AnswersQuery : PagingModel, IRequest>
8 | {
9 | public int NgoId { get; set; }
10 | public bool Urgent { get; set; }
11 | public bool Organizer { get; set; }
12 | public string County { get; set; }
13 | public int PollingStationNumber { get; set; }
14 | public int ObserverId { get; set; }
15 | public string ObserverPhoneNumber { get; set; }
16 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Queries/FilledInAnswersQuery.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Answer.Models;
3 |
4 | namespace VoteMonitor.Api.Answer.Queries;
5 |
6 | public record FilledInAnswersQuery(int ObserverId, int PollingStationId) : IRequest>>;
7 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/Queries/FormAnswersQuery.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Answer.Models;
3 |
4 | namespace VoteMonitor.Api.Answer.Queries;
5 |
6 | public record FormAnswersQuery(int ObserverId, int PollingStationId) : IRequest;
7 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Answer/VoteMonitor.Api.Answer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/Commands/RegisterDeviceIdRequest.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Entities;
3 |
4 | namespace VoteMonitor.Api.Auth.Commands;
5 |
6 | public record RegisterDeviceId(string MobileDeviceId, MobileDeviceIdType MobileDeviceIdType, int ObserverId) : IRequest;
7 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/Models/AuthenticateUserRequest.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.Auth.Models;
4 |
5 | public class AuthenticateUserRequest
6 | {
7 | [Required]
8 | public string User { get; set; }
9 | [Required]
10 | public string Password { get; set; }
11 | public string UniqueId { get; set; }
12 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/Models/AuthenticateUserRequestV2.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.Auth.Models;
4 |
5 | public class AuthenticateUserRequestV2
6 | {
7 | [Required]
8 | public string User { get; set; }
9 | [Required]
10 | public string Password { get; set; }
11 | public string ChannelName { get; set; }
12 | public string FcmToken { get; set; }
13 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/Models/AuthenticationResponseModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Auth.Models;
2 |
3 | public class AuthenticationResponseModel
4 | {
5 | public string access_token { get; set; }
6 | public int expires_in { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/Models/RegisteredObserverModel.cs:
--------------------------------------------------------------------------------
1 | using VoteMonitor.Entities;
2 |
3 | namespace VoteMonitor.Api.Auth.Models;
4 |
5 | public class RegisteredObserverModel
6 | {
7 | public bool IsAuthenticated { get; set; }
8 |
9 | public int ObserverId { get; set; }
10 | ///
11 | /// The is registered if the lock device feature is on and the user is logging for the first time,
12 | /// or the user is logging for the first time with instead of .
13 | ///
14 | public bool ShouldRegisterMobileDeviceId { get; set; }
15 | public int IdNgo { get; set; }
16 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/Models/UserInfo.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Auth.Models;
2 |
3 | public class UserInfo
4 | {
5 | public int IdNgo { get; set; }
6 | public int NgoAdminId { get; set; }
7 | public bool Organizer { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/Queries/NgoAdminApplicationUser.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using System.ComponentModel.DataAnnotations;
3 | using VoteMonitor.Api.Auth.Models;
4 | using VoteMonitor.Api.Core.Models;
5 |
6 | namespace VoteMonitor.Api.Auth.Queries;
7 |
8 | public class NgoAdminApplicationUser : IRequest
9 | {
10 | [Required(AllowEmptyStrings = false)]
11 | public string UserName { get; set; }
12 |
13 | [Required(AllowEmptyStrings = false)]
14 | public string Password { get; set; }
15 |
16 | public UserType UserType { get; set; }
17 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Auth/VoteMonitor.Api.Auth.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/ApiListResponse.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core;
2 |
3 | public class ApiListResponse : PagingResponseModel
4 | {
5 | public List Data { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/ApiResponse.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core;
2 |
3 | public class ApiResponse
4 | where T : class
5 | {
6 | public T Data { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/ClaimsHelper.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core;
2 |
3 | public static class ClaimsHelper
4 | {
5 | public const string ObserverIdProperty = "ObserverId";
6 | public const string NgoAdminIdProperty = "NgoAdminId";
7 | public const string GenericIdProvider = "Token";
8 | public const string IdNgo = "IdNgo";
9 | public const string Organizer = "Organizer";
10 | public const string UserType = "UserType";
11 | public static readonly string TOKEN_VALUE = "Token";
12 | public static readonly string AUTH_HEADER_VALUE = "Authorization";
13 |
14 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Commands/ClearCache.cs:
--------------------------------------------------------------------------------
1 |
2 | using MediatR;
3 |
4 | namespace VoteMonitor.Api.Core.Commands;
5 |
6 | public record ClearCache: IRequest;
7 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Commands/NotificationRegistrationDataCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 |
3 | namespace VoteMonitor.Api.Core.Commands;
4 |
5 | public record NotificationRegistrationDataCommand(int ObserverId, string ChannelName, string Token) : IRequest;
6 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Commands/UploadFileCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using Microsoft.AspNetCore.Http;
3 | using VoteMonitor.Api.Core.Models;
4 |
5 | namespace VoteMonitor.Api.Core.Commands;
6 |
7 | [Obsolete("Will be removed when ui will use multiple files upload")]
8 | public record UploadFileCommand(IFormFile File, UploadType UploadType) : IRequest;
9 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Commands/UploadFileCommandV2.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using Microsoft.AspNetCore.Http;
3 | using VoteMonitor.Api.Core.Models;
4 |
5 | namespace VoteMonitor.Api.Core.Commands;
6 |
7 | public class UploadFileCommandV2 : IRequest
8 | {
9 | public UploadFileCommandV2(List files, UploadType uploadType)
10 | {
11 | Files = files.ToList().AsReadOnly();
12 | UploadType = uploadType;
13 | }
14 |
15 | public IReadOnlyCollection Files { get; }
16 | public UploadType UploadType { get; }
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Controllers/CacheController.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.Mvc;
4 | using VoteMonitor.Api.Core.Commands;
5 |
6 | namespace VoteMonitor.Api.Core.Controllers;
7 |
8 | [ApiController]
9 | [Route("api/v1/cache")]
10 | public class CacheController: Controller
11 | {
12 | private readonly IMediator _mediator;
13 |
14 | public CacheController(IMediator mediator)
15 | {
16 | _mediator = mediator;
17 | }
18 |
19 |
20 | [Authorize("Organizer")]
21 | [HttpPost("clear")]
22 | public async Task ClearCacheAsync()
23 | {
24 | await _mediator.Send(new ClearCache());
25 | return Ok();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Extensions/ClaimsExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Claims;
2 |
3 | namespace VoteMonitor.Api.Core.Extensions;
4 |
5 | public static class ClaimsExtensions
6 | {
7 | public static int? GetObserverId(this IEnumerable claims)
8 | {
9 | return int.TryParse(claims.FirstOrDefault(c => c.Type == ClaimsHelper.ObserverIdProperty)?.Value, out var observerId) ? observerId : (int?)null;
10 | }
11 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Extensions/DateTimeExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Extensions;
2 |
3 | public static class DateTimeExtensions
4 | {
5 | /// Date converted to seconds since Unix epoch (Jan 1, 1970, midnight UTC).
6 | public static long ToUnixEpochDate(this DateTime date)
7 | => (long)Math.Round((date.ToUniversalTime() -
8 | new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero))
9 | .TotalSeconds);
10 |
11 | public static DateTime? AsUtc(this DateTime? date) =>
12 | date == null ? null : DateTime.SpecifyKind(
13 | date.Value,
14 | DateTimeKind.Utc);
15 | }
16 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Extensions/QueryExtension.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Extensions;
2 |
3 | public class QueryExtension
4 | {
5 | public IQueryable GetPagedQuery(IQueryable entities, int page, int pageSize)
6 | where T: class // could be more restrictive if all entities implemented the same interface or the same base class
7 | {
8 | if (pageSize > 0)
9 | {
10 | return entities
11 | .Skip(pageSize * (page - 1))
12 | .Take(pageSize);
13 | }
14 |
15 | return entities;
16 | }
17 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Handlers/CacheHandler.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Core.Commands;
3 | using VoteMonitor.Api.Core.Services;
4 |
5 | namespace VoteMonitor.Api.Core.Handlers;
6 |
7 | public class CacheHandler : IRequestHandler
8 | {
9 | private readonly ICacheService _cacheService;
10 |
11 | public CacheHandler(ICacheService cacheService)
12 | {
13 | _cacheService = cacheService;
14 | }
15 | public async Task Handle(ClearCache request, CancellationToken cancellationToken)
16 | {
17 | await _cacheService.ClearAllValuesAsync();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/ListExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core;
2 |
3 | public static class ListExtensions
4 | {
5 | public static List Paginate(this List unPagedList, int page, int pageSize)
6 | {
7 | return unPagedList
8 | .Skip((page - 1) * pageSize)
9 | .Take(pageSize)
10 | .ToList();
11 | }
12 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Models/CountyPollingStationLimit.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Models;
2 |
3 | public class CountyPollingStationLimit
4 | {
5 | public int Id { get; set; }
6 | public string Name { get; set; }
7 | public string Code { get; set; }
8 | public int Limit { get; set; }
9 |
10 | public bool Diaspora { get; set; }
11 | public int Order { get; set; }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Models/UploadedFileResult.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Models;
2 |
3 | public record UploadedFileModel
4 | {
5 | public string FileName { get; init; }
6 | public string Path { get; init; }
7 | }
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Models/UserType.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Models;
2 |
3 | public enum UserType
4 | {
5 | Observer,
6 | NgoAdmin
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/ApplicationCacheOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public class ApplicationCacheOptions
4 | {
5 | public int Hours { get; set; }
6 |
7 | public int Minutes { get; set; } = 30;
8 |
9 | public int Seconds { get; set; }
10 |
11 | public ApplicationCacheImplementationType Implementation { get; set; } = ApplicationCacheImplementationType.NoCache;
12 | }
13 |
14 | public enum ApplicationCacheImplementationType
15 | {
16 | NoCache,
17 | MemoryDistributedCache,
18 | RedisCache
19 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/BlobStorageOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | ///
4 | /// Manages the details about the blob storage being used
5 | ///
6 | public class BlobStorageOptions
7 | {
8 | public string ConnectionString { get; set; }
9 |
10 | ///
11 | /// The name of the blob container.
12 | ///
13 | public string ContainerName { get; set; }
14 |
15 | ///
16 | /// Gets or sets blob availability in minutes
17 | ///
18 | public int SASBlobAvailabilityInMinutes { get; set; }
19 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/DefaultNgoOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public class DefaultNgoOptions
4 | {
5 | public int DefaultNgoId { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/FileStorageType.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public enum FileStorageType
4 | {
5 | LocalFileService,
6 | BlobService,
7 | S3Service,
8 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/FirebaseServiceOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public class FirebaseServiceOptions
4 | {
5 | public string ServerKey { get; set; }
6 | public string ServerPath{ get; set; }
7 | }
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/HashOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public class HashOptions
4 | {
5 | public string Salt { get; set; }
6 |
7 | ///
8 | /// Can be set to `Hash` or `ClearText`
9 | /// `Hash` will use the HashService (that needs the Salt setting) to generate hashes for the password
10 | /// :warning: `ClearText` will allow your development environment to create and store clear text passwords in the database. Please only use this in development to speed up things.
11 | ///
12 | public HashServiceType HashServiceType { get; set; } = HashServiceType.ClearText;
13 | }
14 | public enum HashServiceType
15 | {
16 | Hash,
17 | ClearText
18 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/LocalFileStorageOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | ///
4 | /// Options for defining the FileService implementation
5 | ///
6 | public class LocalFileStorageOptions
7 | {
8 | ///
9 | /// Only relevant when `Type`=`LocalFileService`.
10 | /// This will be a relative path (`\notes`).
11 | /// Make sure you configure your container persistent storage on this path
12 | ///
13 | public Dictionary StoragePaths { get; set; }
14 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/MobileSecurityOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public class MobileSecurityOptions
4 | {
5 | public bool LockDevice { get; set; }
6 | public string InvalidCredentialsErrorMessage { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/PollingStationsOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public class PollingStationsOptions
4 | {
5 | public bool OverrideDefaultSorting { get; set; }
6 | public string CodeOfFirstToDisplayCounty { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Options/S3StorageOptions.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Options;
2 |
3 | public class S3StorageOptions
4 | {
5 | public string BucketName { get; set; }
6 | public int PresignedUrlExpirationInMinutes { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/PagingDefaultsConstants.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core;
2 |
3 | public static class PagingDefaultsConstants
4 | {
5 | public const int DEFAULT_PAGE_SIZE = 20;
6 | public const int DEFAULT_PAGE = 1;
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/PagingModel.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 |
3 | namespace VoteMonitor.Api.Core;
4 |
5 | public class PagingModel
6 | {
7 | protected int _page;
8 | protected int _pageSize;
9 |
10 | [FromQuery]
11 | public int Page
12 | {
13 | get => _page < 1 ? PagingDefaultsConstants.DEFAULT_PAGE : _page;
14 | set => _page = value < 1 ? PagingDefaultsConstants.DEFAULT_PAGE : value;
15 | }
16 |
17 |
18 | [FromQuery]
19 | public int PageSize
20 | {
21 | get => _pageSize < 1 ? PagingDefaultsConstants.DEFAULT_PAGE_SIZE : _pageSize;
22 | set => _pageSize = value < 1 ? PagingDefaultsConstants.DEFAULT_PAGE_SIZE : value;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/PagingResponseModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core;
2 |
3 | public class PagingResponseModel : PagingModel
4 | {
5 | protected int _totalItems;
6 |
7 | public int TotalItems
8 | {
9 | get { return _totalItems; }
10 | set { _totalItems = value; }
11 | }
12 |
13 | public int TotalPages
14 | {
15 | get { return 1 + (_totalItems - 1) / _pageSize; }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/ClearTextService.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Services;
2 |
3 | public class ClearTextService : IHashService
4 | {
5 | public string GetHash(string clearString) => clearString;
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/ICacheService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Caching.Distributed;
2 |
3 | namespace VoteMonitor.Api.Core.Services;
4 |
5 | ///
6 | /// Interface for the caching service to be used.
7 | ///
8 | public interface ICacheService
9 | {
10 | Task GetOrSaveDataInCacheAsync(string name, Func> source, DistributedCacheEntryOptions options = null);
11 | Task GetObjectSafeAsync(string name);
12 | Task SaveObjectSafeAsync(string name, T value, DistributedCacheEntryOptions options = null);
13 | Task ClearAllValuesAsync();
14 |
15 | Task RemoveValueAsync(string cacheKey);
16 | }
17 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/IFileService.cs:
--------------------------------------------------------------------------------
1 | using VoteMonitor.Api.Core.Models;
2 |
3 | namespace VoteMonitor.Api.Core.Services;
4 |
5 | ///
6 | /// Interface for the file service to be used
7 | ///
8 | public interface IFileService
9 | {
10 | ///
11 | /// Upload stream into file storage
12 | ///
13 | ///
14 | ///
15 | ///
16 | /// the reference to the resource just uploaded
17 | Task UploadFromStreamAsync(Stream sourceStream, string contentType, string extension, UploadType uploadType);
18 |
19 | ///
20 | /// Gets pre-signed url for a given file
21 | ///
22 | ///
23 | ///
24 | string GetPreSignedUrl(string filename);
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/IFirebaseService.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Services;
2 |
3 | public interface IFirebaseService
4 | {
5 | int Send(string from, string title, string message, List recipients);
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/IHashService.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core.Services;
2 |
3 | public interface IHashService
4 | {
5 | string GetHash(string clearString);
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/IPollingStationService.cs:
--------------------------------------------------------------------------------
1 | using VoteMonitor.Api.Core.Models;
2 |
3 | namespace VoteMonitor.Api.Core.Services;
4 |
5 | public interface IPollingStationService
6 | {
7 | Task GetPollingStationId(string countyCode, string municipalityCode, int pollingStationNumber);
8 | Task GetPollingStationByMunicipalityId(int municipalityId, int pollingStationNumber);
9 | Task> GetPollingStationsAssignmentsForAllCounties(bool? diaspora);
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/NoCacheService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Caching.Distributed;
2 |
3 | namespace VoteMonitor.Api.Core.Services;
4 |
5 | public class NoCacheService : ICacheService
6 | {
7 | public async Task GetOrSaveDataInCacheAsync(string name, Func> source,
8 | DistributedCacheEntryOptions options = null)
9 | {
10 | return await source();
11 | }
12 |
13 | public Task GetObjectSafeAsync(string name) => throw new NotImplementedException();
14 |
15 | public Task SaveObjectSafeAsync(string name, T value,
16 | DistributedCacheEntryOptions options = null) => throw new NotImplementedException();
17 |
18 | public Task RemoveValueAsync(string cacheKey) => Task.CompletedTask;
19 |
20 | public Task ClearAllValuesAsync() => Task.CompletedTask;
21 | }
22 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/Services/SHA256HashService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using System.Security.Cryptography;
3 | using System.Text;
4 | using VoteMonitor.Api.Core.Options;
5 |
6 | namespace VoteMonitor.Api.Core.Services;
7 |
8 | ///
9 | public class SHA256HashService : IHashService
10 | {
11 | private readonly string _salt;
12 |
13 | public SHA256HashService(IOptions options)
14 | {
15 | _salt = options.Value.Salt;
16 | }
17 |
18 | public string GetHash(string clearString)
19 | {
20 | // SHA512 is disposable by inheritance.
21 | using (var sha256 = SHA256.Create())
22 | {
23 | // Send a sample text to hash.
24 | var hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(clearString + _salt));
25 | // Get the hashed string.
26 | return BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/UploadType.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Core;
2 |
3 | public enum UploadType
4 | {
5 | Notes,
6 | Observers
7 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Core/VoteMonitor.Api.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | enable
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Commands/CreateOrUpdateCounties.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using Microsoft.AspNetCore.Http;
4 |
5 | namespace VoteMonitor.Api.County.Commands;
6 |
7 | public record CreateOrUpdateCounties(IFormFile File) : IRequest;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Commands/CreateOrUpdateMunicipalities.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using Microsoft.AspNetCore.Http;
4 |
5 | namespace VoteMonitor.Api.County.Commands;
6 |
7 | public record CreateOrUpdateMunicipalities(IFormFile File) : IRequest;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Commands/CreateOrUpdateProvinces.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using Microsoft.AspNetCore.Http;
4 |
5 | namespace VoteMonitor.Api.County.Commands;
6 |
7 | public record CreateOrUpdateProvinces(IFormFile File) : IRequest;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Commands/PrefillCache.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 |
3 | namespace VoteMonitor.Api.County.Commands;
4 |
5 | public record PrefillCache : IRequest;
6 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Commands/UpdateCounty.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Commands;
6 |
7 | public record UpdateCounty : IRequest
8 | {
9 | public int CountyId { get; }
10 | public string Code { get; }
11 | public string Name { get; }
12 | public bool Diaspora { get; }
13 | public int Order { get; }
14 |
15 | public UpdateCounty(int countyId, UpdateCountyRequest county)
16 | {
17 | CountyId = countyId;
18 | Name = county.Name;
19 | Code = county.Code;
20 | Diaspora = county.Diaspora;
21 | Order = county.Order;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Commands/UpdateMunicipality.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Commands;
6 |
7 | public record UpdateMunicipality : IRequest
8 | {
9 | public int MunicipalityId { get; }
10 | public string Code { get; }
11 | public string Name { get; }
12 | public int Order { get; }
13 |
14 | public UpdateMunicipality(int municipalityId, UpdateMunicipalityRequest county)
15 | {
16 | MunicipalityId = municipalityId;
17 | Name = county.Name;
18 | Code = county.Code;
19 | Order = county.Order;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Commands/UpdateProvince.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Commands;
6 |
7 | public record UpdateProvince: IRequest
8 | {
9 | public int ProvinceId { get; }
10 | public string Code { get; }
11 | public string Name { get; }
12 | public bool Diaspora { get; }
13 | public int Order { get; }
14 |
15 | public UpdateProvince(int provinceId, UpdateProvinceRequest county)
16 | {
17 | ProvinceId = provinceId;
18 | Name = county.Name;
19 | Code = county.Code;
20 | Order = county.Order;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Controllers/CacheController.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.AspNetCore.Mvc;
5 | using VoteMonitor.Api.County.Commands;
6 |
7 | namespace VoteMonitor.Api.County.Controllers;
8 |
9 |
10 | [ApiController]
11 | [Route("api/v1/locations-cache")]
12 | public class CacheController: ControllerBase
13 | {
14 | private readonly IMediator _mediator;
15 |
16 | public CacheController(IMediator mediator)
17 | {
18 | _mediator = mediator;
19 | }
20 |
21 | [Authorize("Organizer")]
22 | [HttpGet("prefill")]
23 | [ProducesResponseType(StatusCodes.Status204NoContent)]
24 | [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
25 | public async Task PrefillCache()
26 | {
27 | await _mediator.Send(new PrefillCache());
28 | return NoContent();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/CountiesUploadRequest.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 | using Microsoft.AspNetCore.Http;
3 | using VoteMonitor.Api.Core.Attributes;
4 |
5 | namespace VoteMonitor.Api.County.Models;
6 |
7 | public class CountiesUploadRequest
8 | {
9 | [Required(ErrorMessage = "Please select a file.")]
10 | [DataType(DataType.Upload)]
11 | [AllowedExtensions(new[] { ".csv" })]
12 | public IFormFile CsvFile { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/CountyCsvModel.cs:
--------------------------------------------------------------------------------
1 | using CsvHelper.Configuration.Attributes;
2 |
3 | namespace VoteMonitor.Api.County.Models;
4 |
5 | public class CountyCsvModel
6 | {
7 | [Index(0)]
8 | public int Id { get; set; }
9 |
10 | [Index(1)]
11 | public string Code { set; get; }
12 |
13 | [Index(2)]
14 | public string Name { get; set; }
15 |
16 | [Index(3)]
17 | public string ProvinceCode { get; set; }
18 |
19 | [Index(4)]
20 | public bool Diaspora { get; set; }
21 |
22 | [Index(5)]
23 | public int Order { get; set; }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/CountyModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.County.Models;
2 |
3 | public class CountyModel
4 | {
5 | public int Id { get; set; }
6 | public string Code { get; set; }
7 | public string ProvinceCode { get; set; }
8 | public int NumberOfPollingStations { get; set; }
9 | public string Name { get; set; }
10 | public bool Diaspora { get; set; }
11 | public int Order { get; set; }
12 | }
13 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/ErrorModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.County.Models;
2 |
3 | public class ErrorModel
4 | {
5 | public string Message { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/MunicipalitiesUploadRequest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using System.ComponentModel.DataAnnotations;
3 | using VoteMonitor.Api.Core.Attributes;
4 |
5 | namespace VoteMonitor.Api.County.Models;
6 |
7 | public class MunicipalitiesUploadRequest
8 | {
9 | [Required(ErrorMessage = "Please select a file.")]
10 | [DataType(DataType.Upload)]
11 | [AllowedExtensions(new[] { ".csv" })]
12 | public IFormFile CsvFile { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/MunicipalityCsvModel.cs:
--------------------------------------------------------------------------------
1 | using CsvHelper.Configuration.Attributes;
2 |
3 | namespace VoteMonitor.Api.County.Models;
4 |
5 | public class MunicipalityCsvModel
6 | {
7 | [Index(0)]
8 | public int Id { get; set; }
9 |
10 | [Index(1)]
11 | public string CountyCode { set; get; }
12 |
13 | [Index(2)]
14 | public string Code { set; get; }
15 |
16 | [Index(3)]
17 | public string Name { get; set; }
18 |
19 | [Index(4)]
20 | public int Order { get; set; }
21 | }
22 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/MunicipalityModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.County.Models;
2 |
3 | public class MunicipalityModel
4 | {
5 | public int Id { get; set; }
6 | public string CountyCode { get; set; }
7 | public string Code { get; set; }
8 | public string Name { get; set; }
9 | public int NumberOfPollingStations { get; set; }
10 | public int Order { get; set; }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/MunicipalityModelV2.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.County.Models;
2 |
3 | public class MunicipalityModelV2
4 | {
5 | public int Id { get; set; }
6 |
7 | public string Code { get; set; }
8 | public string Name { get; set; }
9 | public int NumberOfPollingStations { get; set; }
10 | public int Order { get; set; }
11 |
12 | public int CountyId { get; set; }
13 | public string CountyCode { get; set; }
14 | public string CountyName { get; set; }
15 | public bool Diaspora { get; set; }
16 | public int CountyOrder { get; set; }
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/ProvinceCsvModel.cs:
--------------------------------------------------------------------------------
1 | using CsvHelper.Configuration.Attributes;
2 |
3 | namespace VoteMonitor.Api.County.Models;
4 |
5 | public class ProvinceCsvModel
6 | {
7 | [Index(0)]
8 | public int Id { get; set; }
9 |
10 | [Index(1)]
11 | public string Code { set; get; }
12 |
13 | [Index(2)]
14 | public string Name { get; set; }
15 |
16 | [Index(3)]
17 | public int Order { get; set; }
18 | }
19 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/ProvinceModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.County.Models;
2 |
3 | public class ProvinceModel
4 | {
5 | public int Id { get; set; }
6 | public string Code { get; set; }
7 | public string Name { get; set; }
8 | public int Order { get; set; }
9 | }
10 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/ProvincesUploadRequest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using System.ComponentModel.DataAnnotations;
3 | using VoteMonitor.Api.Core.Attributes;
4 |
5 | namespace VoteMonitor.Api.County.Models;
6 |
7 | public class ProvincesUploadRequest
8 | {
9 | [Required(ErrorMessage = "Please select a file.")]
10 | [DataType(DataType.Upload)]
11 | [AllowedExtensions(new[] { ".csv" })]
12 | public IFormFile CsvFile { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/UpdateCountyRequest.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.County.Models;
4 |
5 | public class UpdateCountyRequest
6 | {
7 | [Required]
8 | [StringLength(100)]
9 | public string Name { get; set; }
10 |
11 | [Required]
12 | [StringLength(20)]
13 | public string Code { get; set; }
14 |
15 | public bool Diaspora { get; set; }
16 | public int Order { get; set; }
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/UpdateMunicipalityRequest.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.County.Models;
4 |
5 | public class UpdateMunicipalityRequest
6 | {
7 | [Required]
8 | [StringLength(100)]
9 | public string Name { get; set; }
10 |
11 | [Required]
12 | [StringLength(20)]
13 | public string Code { get; set; }
14 |
15 | public int Order { get; set; }
16 | }
17 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Models/UpdateProvinceRequest.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.County.Models;
4 |
5 | public class UpdateProvinceRequest
6 | {
7 | [Required]
8 | [StringLength(100)]
9 | public string Name { get; set; }
10 |
11 | [Required]
12 | [StringLength(20)]
13 | public string Code { get; set; }
14 |
15 | public int Order { get; set; }
16 | }
17 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetAllCounties.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetAllCounties : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetAllCountiesByProvinceCode.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetAllCountiesByProvinceCode(string ProvinceCode) : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetAllMunicipalities.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetAllMunicipalities : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetAllMunicipalitiesByCountyCode.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetAllMunicipalitiesByCountyCode(string CountyCode) : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetAllProvinces.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetAllProvinces : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetCountiesForExport.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetCountiesForExport : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetCountyById.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetCountyById(int CountyId) : IRequest>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetMunicipalitiesForExport.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetMunicipalitiesForExport : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetMunicipalityById.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetMunicipalityById(int MunicipalityId) : IRequest>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetProvinceById.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetProvinceById(int ProvinceId) : IRequest>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/Queries/GetProvincesForExport.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 | using VoteMonitor.Api.County.Models;
4 |
5 | namespace VoteMonitor.Api.County.Queries;
6 |
7 | public record GetProvincesForExport : IRequest>>;
8 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.County/VoteMonitor.Api.County.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Controllers/DataExportV2Controller.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.Mvc;
4 | using VoteMonitor.Api.DataExport.FileGenerator;
5 | using VoteMonitor.Api.DataExport.Queries;
6 |
7 | namespace VoteMonitor.Api.DataExport.Controllers;
8 |
9 | [Route("api/v2/export")]
10 | public class DataExportV2Controller : Controller
11 | {
12 | private readonly IMediator _mediator;
13 |
14 | public DataExportV2Controller(IMediator mediator)
15 | {
16 | _mediator = mediator;
17 | }
18 |
19 | ///
20 | /// Exports all data in excel file
21 | ///
22 | ///
23 | [HttpGet("all")]
24 | [Authorize("Organizer")]
25 | public async Task GetAllData()
26 | {
27 |
28 | var data = await _mediator.Send(new GetExcelDbCommand());
29 |
30 |
31 | return File(
32 | fileContents: data,
33 | contentType: ExcelUtility.EXCEL_MEDIA_TYPE,
34 | fileDownloadName: "data.xlsx"
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/FileGenerator/CsvGenerator.cs:
--------------------------------------------------------------------------------
1 | using CsvHelper;
2 | using System.Globalization;
3 |
4 | namespace VoteMonitor.Api.DataExport.FileGenerator;
5 |
6 | public class CsvGenerator : ICsvGenerator
7 | {
8 | public byte[] Export(IEnumerable exportData, string fileName)
9 | {
10 | using (var mem = new MemoryStream())
11 | using (var writer = new StreamWriter(mem))
12 | using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture))
13 | {
14 | csvWriter.WriteRecords(exportData);
15 |
16 | writer.Flush();
17 | return mem.ToArray();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/FileGenerator/CsvUtility.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.DataExport.FileGenerator;
2 |
3 | public class CsvUtility
4 | {
5 | public const string CSV_MEDIA_TYPE = "text/csv"; // ref: https://stackoverflow.com/questions/7076042/what-mime-type-should-i-use-for-csv > https://tools.ietf.org/html/rfc7111
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/FileGenerator/ExcelUtility.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.DataExport.FileGenerator;
2 |
3 | public class ExcelUtility
4 | {
5 | public const string DATETIME_FORMAT = "dd/MM/yyyy hh:mm:ss";
6 | public const string EXCEL_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
7 |
8 |
9 | #region DataType available for Excel Export
10 | public const string STRING = "string";
11 | public const string INT32 = "int32";
12 | public const string DOUBLE = "double";
13 | public const string DATETIME = "datetime";
14 | public const string BOOLEAN = "boolean";
15 | #endregion
16 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/FileGenerator/ICsvGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.DataExport.FileGenerator;
2 |
3 | public interface ICsvGenerator
4 | {
5 | byte[] Export(IEnumerable exportData, string fileName);
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Handlers/CsvGeneratorQueryHandler.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.DataExport.FileGenerator;
3 | using VoteMonitor.Api.DataExport.Queries;
4 |
5 | namespace VoteMonitor.Api.DataExport.Handlers;
6 |
7 | public class CsvGeneratorQueryHandler : IRequestHandler,
8 | IRequestHandler
9 | {
10 | private readonly ICsvGenerator _csvGenerator;
11 |
12 | public CsvGeneratorQueryHandler()
13 | {
14 | _csvGenerator = new CsvGenerator();
15 | }
16 |
17 | public Task Handle(GenerateCSVFile request, CancellationToken cancellationToken)
18 | {
19 | var fileContents = _csvGenerator.Export(request.Data, "myData");
20 |
21 | return Task.FromResult(fileContents);
22 | }
23 |
24 | public Task Handle(GenerateNotesCSVFile request, CancellationToken cancellationToken)
25 | {
26 | var fileContents = _csvGenerator.Export(request.Data, "notes");
27 |
28 | return Task.FromResult(fileContents);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Models/ExportModelDto.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.DataExport.Models;
2 |
3 | ///
4 | /// data transfer object for ExportModel on DataExportQueryHandler
5 | /// Based on ExportModel entity, hide not necessary Id field
6 | ///
7 | public class ExportModelDto
8 | {
9 | public string ObserverPhone { get; set; }
10 | public int IdNgo { get; set; }
11 | public string FormCode { get; set; }
12 | public string QuestionText { get; set; }
13 | public string OptionText { get; set; }
14 | public string AnswerFreeText { get; set; }
15 | public DateTime LastModified { get; set; }
16 | public string CountyCode { get; set; }
17 | public int PollingStationNumber { get; set; }
18 | public bool HasNotes => NumberOfNotes > 0;
19 | public int NumberOfNotes { get; set; }
20 | public bool HasAttachments => NumberOfAttachments > 0;
21 | public int NumberOfAttachments { get; set; }
22 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Models/NotesExportModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.DataExport.Models;
2 |
3 | public class NotesExportModel
4 | {
5 | public string ObserverPhone { get; set; }
6 | public int IdNgo { get; set; }
7 | public string FormCode { get; set; }
8 | public string QuestionText { get; set; }
9 | public string OptionText { get; set; }
10 | public string AnswerFreeText { get; set; }
11 | public string NoteText { get; set; }
12 | public string NoteAttachmentPath { get; set; }
13 | public DateTime? LastModified { get; set; }
14 | public string CountyCode { get; set; }
15 | public int PollingStationNumber { get; set; }
16 | }
17 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Queries/GenerateCSVFile.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.DataExport.Models;
3 |
4 | namespace VoteMonitor.Api.DataExport.Queries;
5 |
6 | public class GenerateCSVFile : IRequest
7 | {
8 | public IReadOnlyCollection Data { get; }
9 |
10 | public GenerateCSVFile(IEnumerable data)
11 | {
12 | Data = data.ToList().AsReadOnly();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Queries/GenerateNotesCSVFile.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.DataExport.Models;
3 |
4 | namespace VoteMonitor.Api.DataExport.Queries;
5 |
6 | public class GenerateNotesCSVFile : IRequest
7 | {
8 | public IReadOnlyCollection Data { get; }
9 |
10 | public GenerateNotesCSVFile(IEnumerable data)
11 | {
12 | Data = data.ToList().AsReadOnly();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Queries/GetDataForExport.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.DataExport.Models;
3 |
4 | namespace VoteMonitor.Api.DataExport.Queries;
5 |
6 | public class GetDataForExport : IRequest>
7 | {
8 | public int? NgoId { get; set; }
9 | public int? ObserverId { get; set; }
10 | public int? PollingStationNumber { get; set; }
11 | public string County { get; set; }
12 | public DateTime? From { get; set; }
13 | public DateTime? To { get; set; }
14 |
15 | public bool ApplyFilters => NgoId.HasValue || ObserverId.HasValue || PollingStationNumber.HasValue ||
16 | From.HasValue || To.HasValue || !string.IsNullOrEmpty(County);
17 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Queries/GetExcelDbCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 |
3 | namespace VoteMonitor.Api.DataExport.Queries;
4 |
5 | public record GetExcelDbCommand : IRequest;
6 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/Queries/GetNotesForExport.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.DataExport.Models;
3 |
4 | namespace VoteMonitor.Api.DataExport.Queries;
5 |
6 | public class GetNotesForExport : IRequest>
7 | {
8 | public int? NgoId { get; set; }
9 | public int? ObserverId { get; set; }
10 | public int? PollingStationNumber { get; set; }
11 | public string County { get; set; }
12 | public DateTime? From { get; set; }
13 | public DateTime? To { get; set; }
14 |
15 | public bool ApplyFilters => NgoId.HasValue || ObserverId.HasValue || PollingStationNumber.HasValue ||
16 | From.HasValue || To.HasValue || !string.IsNullOrEmpty(County);
17 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.DataExport/VoteMonitor.Api.DataExport.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net7.0
4 | enable
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/CommandHandlers/AddFormCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Form.Commands;
3 | using VoteMonitor.Api.Form.Mappers;
4 | using VoteMonitor.Api.Form.Models;
5 | using VoteMonitor.Entities;
6 |
7 | namespace VoteMonitor.Api.Form.CommandHandlers;
8 |
9 | public class AddFormCommandHandler : IRequestHandler
10 | {
11 | private readonly VoteMonitorContext _context;
12 | private readonly IEntityMapper _entityMapper;
13 |
14 | public AddFormCommandHandler(VoteMonitorContext context, IEntityMapper entityMapper)
15 | {
16 | _context = context;
17 | _entityMapper = entityMapper;
18 | }
19 |
20 | public async Task Handle(AddFormCommand message, CancellationToken cancellationToken)
21 | {
22 | Entities.Form form = null;
23 | _entityMapper.Map(ref form, message.Form);
24 |
25 | _context.Forms.Add(form);
26 |
27 | await _context.SaveChangesAsync();
28 | message.Form.Id = form.Id;
29 | return message.Form;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/CommandHandlers/AddOptionCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Form.Commands;
3 | using VoteMonitor.Api.Form.Models.Options;
4 | using VoteMonitor.Entities;
5 |
6 | namespace VoteMonitor.Api.Form.CommandHandlers;
7 |
8 | public class AddOptionCommandHandler : IRequestHandler
9 | {
10 | private readonly VoteMonitorContext _context;
11 |
12 | public AddOptionCommandHandler(VoteMonitorContext context)
13 | {
14 | _context = context;
15 | }
16 |
17 | public async Task Handle(AddOptionCommand request, CancellationToken cancellationToken)
18 | {
19 | var optionEntity = new Option { Text = request.Text, Hint = request.Hint, IsFreeText = request.IsFreeText, };
20 |
21 | _context.Options.Add(optionEntity);
22 | await _context.SaveChangesAsync(cancellationToken);
23 |
24 | return new OptionDTO
25 | {
26 | Id = optionEntity.Id,
27 | Hint = optionEntity.Hint,
28 | IsFreeText = optionEntity.IsFreeText,
29 | Text = optionEntity.Text
30 | };
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Commands/AddFormCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Form.Models;
3 |
4 | namespace VoteMonitor.Api.Form.Commands;
5 |
6 | public record AddFormCommand(FormDTO Form) : IRequest;
7 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Commands/AddOptionCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Form.Models.Options;
3 |
4 | namespace VoteMonitor.Api.Form.Commands;
5 |
6 | public record AddOptionCommand(string Text, string Hint, bool IsFreeText) : IRequest;
7 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Commands/DeleteFormCommand.cs:
--------------------------------------------------------------------------------
1 | using CSharpFunctionalExtensions;
2 | using MediatR;
3 |
4 | namespace VoteMonitor.Api.Form.Commands;
5 |
6 | public enum DeleteFormErrorType
7 | {
8 | FormNotFound,
9 | FormHasAnswers,
10 | FormNotDraft,
11 | ErrorOccurred
12 | }
13 |
14 | public record DeleteFormCommand(int FormId) : IRequest>;
15 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Commands/DeleteQuestionCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 |
3 | namespace VoteMonitor.Api.Form.Commands;
4 |
5 | public record DeleteQuestionCommand(int SectionId, int QuestionId) : IRequest;
6 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Commands/DeleteSectionCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 |
3 | namespace VoteMonitor.Api.Form.Commands;
4 |
5 | public record DeleteSectionCommand(int SectionId) : IRequest;
6 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Commands/UpdateFormCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using VoteMonitor.Api.Form.Models;
3 |
4 | namespace VoteMonitor.Api.Form.Commands;
5 |
6 | public record UpdateFormCommand(FormDTO Form, int Id) : IRequest;
7 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Commands/UpdateOptionCommand.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 |
3 | namespace VoteMonitor.Api.Form.Commands;
4 |
5 | public record UpdateOptionCommand(int OptionId, string Text, string Hint, bool IsFreeText) : IRequest;
6 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Controllers/ExportController.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.Mvc;
4 | using VoteMonitor.Api.Form.Models;
5 | using VoteMonitor.Api.Form.Queries;
6 |
7 | namespace VoteMonitor.Api.Form.Controllers;
8 |
9 | [Route("api/v1/export")]
10 | public class ExportController : Controller
11 | {
12 | private readonly IMediator _mediator;
13 |
14 | public ExportController(IMediator mediator)
15 | {
16 | _mediator = mediator;
17 | }
18 |
19 | [HttpPost("forms")]
20 | [Authorize("Organizer")]
21 | public async Task> ExportFormsAsync()
22 | {
23 | var filledInForms = await _mediator.Send(new GetFormsQuery());
24 | return filledInForms;
25 | }
26 |
27 | [HttpPost("filled-forms")]
28 | [Authorize("Organizer")]
29 | public async Task> ExportFilledFormsAsync()
30 | {
31 | var filledInForms = await _mediator.Send(new GetFilledFormsQuery());
32 | return filledInForms;
33 | }
34 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Mappers/IEntityMapper.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Form.Mappers;
2 |
3 | public interface IEntityMapper
4 | {
5 | void Map(ref TEntity entity, TDto dto);
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Mappers/IUpdateOrCreateEntityMapper.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Form.Mappers;
2 |
3 | public interface IUpdateOrCreateEntityMapper : IEntityMapper
4 | {
5 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Mappers/UpdateOrCreateEntityMapper.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 |
3 | namespace VoteMonitor.Api.Form.Mappers;
4 |
5 | public class UpdateOrCreateEntityMapper : IUpdateOrCreateEntityMapper
6 | {
7 | private readonly IMapper _mapper;
8 |
9 | public UpdateOrCreateEntityMapper(IMapper mapper)
10 | {
11 | _mapper = mapper;
12 | }
13 |
14 | public virtual void Map(ref TEntity entity, TDto dto)
15 | {
16 | // If the entity is new in the dto (entity is null), we just map it
17 | // Otherwise, we update all properties except the hierarchy part(Excluded from profile).
18 | entity = entity == null
19 | ? _mapper.Map(dto)
20 | : _mapper.Map(dto, entity);
21 | }
22 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/FilledFormResponseModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Form.Models;
2 |
3 | public class FilledFormResponseModel
4 | {
5 | public int FormId { get; set; }
6 | public int ObserverId { get; set; }
7 | public IReadOnlyList FilledInQuestions { get; set; }
8 | ///
9 | /// Last date when an answer from a form was modified.
10 | ///
11 | public DateTime LastModified { get; set; }
12 |
13 | public int PollingStationId { get; set; }
14 | }
15 |
16 | public class AnswerResponseModel
17 | {
18 | public int QuestionId { get; set; }
19 | public int FormSectionId { get; set; }
20 | public IReadOnlyList SelectedOptions { get; set; }
21 | }
22 |
23 | public class SelectedOptionResponseModel
24 | {
25 | public int Id { get; set; }
26 | public int OptionId { get; set; }
27 | public string FreeTextValue { get; set; }
28 | public DateTime LasModified { get; set; }
29 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/FormDTO.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 | using VoteMonitor.Entities;
3 |
4 | namespace VoteMonitor.Api.Form.Models;
5 |
6 | public class FormDTO : IHierarchicalEntity
7 | {
8 | public int Id { get; set; }
9 | public string Code { get; set; }
10 | public int CurrentVersion { get; set; }
11 | public string Description { get; set; }
12 | public ICollection FormSections { get; set; }
13 | public bool Diaspora { get; set; }
14 | public bool Draft { get; set; }
15 | public int Order { get; set; }
16 |
17 | [JsonIgnore]
18 | [Newtonsoft.Json.JsonIgnore]
19 | public ICollection Children { get => FormSections; set => FormSections = value; }
20 | }
21 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/FormDetailsModel.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace VoteMonitor.Api.Form.Models;
4 |
5 | public class FormDetailsModel
6 | {
7 | [JsonPropertyName("id")]
8 | public int Id { get; set; }
9 |
10 | [JsonPropertyName("code")]
11 | public string Code { get; set; }
12 |
13 | [JsonPropertyName("description")]
14 | public string Description { get; set; }
15 |
16 | [JsonPropertyName("currentVersion")]
17 | public int CurrentVersion { get; set; }
18 |
19 | // quick and dirty fix to sync iOS and Android
20 | [JsonPropertyName("ver")]
21 | public int CurrentVersionOld { get; set; }
22 |
23 | [JsonPropertyName("diaspora")]
24 | public bool Diaspora { get; set; }
25 |
26 | [JsonPropertyName("order")]
27 | public int Order { get; set; }
28 |
29 | [JsonPropertyName("draft")]
30 | public bool Draft { get; set; }
31 | }
32 |
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/FormSectionDTO.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 | using VoteMonitor.Entities;
3 |
4 | namespace VoteMonitor.Api.Form.Models;
5 |
6 | public class FormSectionDTO : IHierarchicalEntity, IIdentifiableEntity
7 | {
8 | public FormSectionDTO()
9 | {
10 | Questions = new List();
11 | }
12 | public string UniqueId { get; set; }
13 | public int Id { get; set; }
14 | public string Code { get; set; }
15 | public string Description { get; set; }
16 | public int OrderNumber { get; set; }
17 | public ICollection Questions { get; set; }
18 |
19 | [JsonIgnore]
20 | [Newtonsoft.Json.JsonIgnore]
21 | ICollection IHierarchicalEntity.Children { get => Questions; set => Questions = value; }
22 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/FormVersionsModel.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Form.Models;
2 |
3 | public class FormVersionsModel
4 | {
5 | public List FormVersions { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/OptionToQuestionDTO.cs:
--------------------------------------------------------------------------------
1 | using VoteMonitor.Entities;
2 |
3 | namespace VoteMonitor.Api.Form.Models;
4 |
5 | public class OptionToQuestionDTO : IIdentifiableEntity
6 | {
7 | public int Id { get; set; }
8 | public int OptionId { get; set; }
9 | public string Text { get; set; }
10 | public bool IsFreeText { get; set; }
11 | public bool Flagged { get; set; }
12 | public int OrderNumber { get; set; }
13 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/Options/CreateOptionModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.Form.Models.Options;
4 |
5 | public class CreateOptionModel
6 | {
7 | [Required]
8 | public bool IsFreeText { get; set; }
9 |
10 | [Required(AllowEmptyStrings = false), MaxLength(1000)]
11 | public string Text { get; set; }
12 |
13 | public string Hint { get; set; }
14 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/Options/OptionDTO.cs:
--------------------------------------------------------------------------------
1 | namespace VoteMonitor.Api.Form.Models.Options;
2 |
3 | public class OptionDTO
4 | {
5 | public int Id { get; set; }
6 | public bool IsFreeText { get; set; }
7 | public string Text { get; set; }
8 | public string Hint { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/Options/OptionModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace VoteMonitor.Api.Form.Models.Options;
4 |
5 | public class OptionModel
6 | {
7 | [Required]
8 | public int Id { get; set; }
9 |
10 | [Required]
11 | public bool IsFreeText { get; set; }
12 |
13 | [Required(AllowEmptyStrings = false), MaxLength(1000)]
14 | public string Text { get; set; }
15 |
16 | public string Hint { get; set; }
17 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Models/QuestionDTO.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 | using VoteMonitor.Entities;
3 |
4 | namespace VoteMonitor.Api.Form.Models;
5 |
6 | public class QuestionDTO : IHierarchicalEntity, IIdentifiableEntity
7 | {
8 | public QuestionDTO()
9 | {
10 | OptionsToQuestions = new List();
11 | }
12 |
13 | public int Id { get; set; }
14 | public string FormCode { get; set; }
15 | public string Code { get; set; }
16 | public int IdSection { get; set; }
17 | public QuestionType QuestionType { get; set; }
18 | public string Text { get; set; }
19 | public string Hint { get; set; }
20 | public int OrderNumber { get; set; }
21 |
22 | public ICollection OptionsToQuestions { get; set; }
23 |
24 | [JsonIgnore]
25 | [Newtonsoft.Json.JsonIgnore]
26 | public ICollection Children { get => OptionsToQuestions; set => OptionsToQuestions = value; }
27 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Profiles/FormProfile.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using VoteMonitor.Api.Form.Models;
3 |
4 | namespace VoteMonitor.Api.Form.Profiles;
5 |
6 | public class FormProfile : Profile
7 | {
8 | public FormProfile()
9 | {
10 | CreateMap()
11 | .ForMember(dest => dest.FormSections, c => c.Ignore())
12 | .ForMember(dest => dest.Id, c => c.Ignore());
13 | }
14 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Profiles/FormSectionProfile.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using VoteMonitor.Api.Form.Models;
3 | using VoteMonitor.Entities;
4 |
5 | namespace VoteMonitor.Api.Form.Profiles;
6 |
7 | public class FormSectionProfile : Profile
8 | {
9 | public FormSectionProfile()
10 | {
11 | CreateMap()
12 | .ForMember(dest => dest.Questions, c => c.Ignore())
13 | .ForMember(dest => dest.Id, c => c.Ignore())
14 | .ForMember(dest => dest.IdForm, c => c.Ignore());
15 | }
16 | }
--------------------------------------------------------------------------------
/src/api/VoteMonitor.Api.Form/Profiles/OptionProfile.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using VoteMonitor.Api.Form.Models.Options;
3 | using VoteMonitor.Entities;
4 |
5 | namespace VoteMonitor.Api.Form.Profiles;
6 |
7 | public class OptionProfile : Profile
8 | {
9 | public OptionProfile()
10 | {
11 | CreateMap(MemberList.Source);
12 | CreateMap(MemberList.Source);
13 |
14 | CreateMap