diff --git a/.gitignore b/.gitignore index 6fc99faa39..06946f0dde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,12 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +#mock-api-runtime +*.jar + +#sonar +.scannerwork + # User-specific files *.suo *.user diff --git a/SME.SGP.Api.Teste/Controllers/PermissionamentoControllerTeste.cs b/SME.SGP.Api.Teste/Controllers/PermissionamentoControllerTeste.cs index bc14c9364e..e2531a5209 100644 --- a/SME.SGP.Api.Teste/Controllers/PermissionamentoControllerTeste.cs +++ b/SME.SGP.Api.Teste/Controllers/PermissionamentoControllerTeste.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using SME.SGP.Api.Controllers; using Xunit; namespace SME.SGP.Api.Teste.Controllers @@ -27,8 +29,11 @@ public async Task Verificar_Se_Existe_Permissao_Ou_AllowAnonymou_Authorize_Contr ObterDadosControllers(listaApiMethod, apiControllers, AssemblyName); - var listMetodos = listaApiMethod.Where(x => x.CustomAttributeName.Count == 0); - var semAuthorizeAttribute = listaApiMethod.Where(x => x.Authorize ==false); + + //o ideal seria olhar pelo atributo [AllowAnonymous] para criterio de exclusao + var exclusions = new []{nameof(VersaoController)}; + var listMetodos = listaApiMethod.Where(x => x.CustomAttributeName.Count == 0 && !exclusions.Contains(x.ControllerName)); + var semAuthorizeAttribute = listaApiMethod.Where(x => x.Authorize ==false && !exclusions.Contains(x.ControllerName)); var listAutorizecontrollerName = semAuthorizeAttribute.GroupBy(x => x.ControllerName).ToList(); var listcontrollerName = listMetodos.GroupBy(c => c.ControllerName).ToList(); @@ -44,8 +49,10 @@ public async Task Verificar_Se_Existe_Permissao_Ou_AllowAnonymou_Authorize_Contr ObterDadosControllers(listaApiMethod, apiControllers, AssemblyName); - var listMetodos = listaApiMethod.Where(x => x.CustomAttributeName.Count == 0); - var semAuthorizeAttribute = listaApiMethod.Where(x => x.Authorize == false); + //o ideal seria olhar pelo atributo [AllowAnonymous] para criterio de exclusao + var exclusions = new []{nameof(VersaoController)}; + var listMetodos = listaApiMethod.Where(x => x.CustomAttributeName.Count == 0 && !exclusions.Contains(x.ControllerName)); + var semAuthorizeAttribute = listaApiMethod.Where(x => x.Authorize == false && !exclusions.Contains(x.ControllerName)); var listAutorizecontrollerName = semAuthorizeAttribute.GroupBy(x => x.ControllerName).ToList(); var listcontrollerName = listMetodos.GroupBy(c => c.ControllerName).ToList(); diff --git a/SME.SGP.Api.Teste/SME.SGP.Api.Teste.csproj b/SME.SGP.Api.Teste/SME.SGP.Api.Teste.csproj index 044175053e..b9b2fb4389 100644 --- a/SME.SGP.Api.Teste/SME.SGP.Api.Teste.csproj +++ b/SME.SGP.Api.Teste/SME.SGP.Api.Teste.csproj @@ -2,7 +2,7 @@ net5.0 - + true false bf27baf5-fe9e-4489-8f4e-5234401470bd diff --git a/docker-compose-dev.yaml b/docker-compose-dev.yaml new file mode 100644 index 0000000000..07c62984b8 --- /dev/null +++ b/docker-compose-dev.yaml @@ -0,0 +1,61 @@ +version: "3.1" +services: + sme-db: + container_name: sme-db + restart: always + image: postgres:11-alpine + ports: + - "5433:5432" + environment: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: sgp_db + deploy: + resources: + limits: + cpus: "4" + memory: 10g + reservations: + cpus: "4" + memory: 10g + networks: + - sme-network + sme-flyway: + container_name: sme-flyway + restart: on-failure + image: boxfuse/flyway:5.2.4 + command: migrate -locations='filesystem:/opt/scripts' -url='jdbc:postgresql://sme-db:5432/sgp_db?user=postgres&password=postgres' -outOfOrder=true + volumes: + - ./scripts:/opt/scripts + depends_on: + - sme-db + networks: + - sme-network + sme-rabbitmq: + container_name: sme-rabbitmq + image: rabbitmq:3.10.6-management-alpine + environment: + - RABBITMQ_DEFAULT_USER=rabbitmq + - RABBITMQ_DEFAULT_PASS=rabbitmq + deploy: + resources: + limits: + cpus: "4" + memory: 10g + reservations: + cpus: "4" + memory: 10g + ports: + - "5673:5672" + - "15673:15672" + networks: + - sme-network +networks: + sme-network: + driver: bridge + +# insert into ue (nome,data_atualizacao) values ('ue1',now()); +# insert into tipo_calendario (nome,ano_letivo,periodo,modalidade,criado_em,criado_por,criado_rf) values ('Calendario 1',2022,1,1,now(),1,1); +# insert into aula (ue_id,disciplina_id,turma_id,tipo_calendario_id,professor_rf,quantidade,data_aula,recorrencia_aula,tipo_aula,criado_em,criado_por,criado_rf) +# values (1,1,1,1,'prof1',1,now(),'1','1',now(),now(),'admin'); +# insert into diario_bordo (aula_id,planejamento,criado_em,criado_por,criado_rf) values (1,'sd',now(),1,1); +# insert into diario_bordo_observacao (diario_bordo_id,observacao,criado_em,criado_por,criado_rf,usuario_id) values (1,'sd',now(),1,1,1); diff --git a/mocks/apm.yaml b/mocks/apm.yaml new file mode 100644 index 0000000000..193550069c --- /dev/null +++ b/mocks/apm.yaml @@ -0,0 +1,8 @@ +- method: POST + path: /apm/intake/v2/events + features: + delay: 0 + response: + status: 200 + body: + message: "ok" \ No newline at end of file diff --git a/mocks/eol.yaml b/mocks/eol.yaml new file mode 100644 index 0000000000..c65da81477 --- /dev/null +++ b/mocks/eol.yaml @@ -0,0 +1,546 @@ +- method: GET + path: /eol/swagger/index.html + features: + delay: 0 + response: + status: 200 + body: + Message: "ok" +- method: POST + path: /eol/v1/autenticacao + features: + delay: 0 + response: + status: 200 + body: + CodigoRf: "1" + Status: Ok + UsuarioId: a7f525b9-0e3c-4546-8457-08f697cfc6f6 +- method: GET + path: /eol/autenticacaoSgp/CarregarPerfisPorLogin/{login} + features: + delay: 0 + response: + status: 200 + body: + CodigoRf: ${login} + PossuiCargoCJ: true + Perfis: + - 46E1E074-37D6-E911-ABD6-F81654FE895D + PossuiPerfilCJ: true + ContratoExterno: false +- method: GET + path: /eol/AutenticacaoSgp/{login}/dados + features: + delay: 0 + response: + status: 200 + body: + Nome: SomeUser + Cpf: 000.000.000-00 + CodigoRf: ${login} + Empresa: SomeCompany + Email: ${login}@sme.com +- method: GET + path: /eol/abrangencia/compacta-vigente/{login}/perfil/{perfil} + features: + delay: 0 + response: + status: 200 + body: + Login: ${login} + Abrangencia: + Abrangencia: SME + CargosId: + - 1 + CdTipoFuncaoAtividade: 1 + Grupo: ADMSME + GrupoID: ${perfil} + IdDres: [] + IdUes: [] + IdTurmas: [] +- method: GET + path: /eol/v1/componentes-curriculares/turmas/{turma}/funcionarios/{login}/perfis/{perfil}/agrupaComponenteCurricular/{realizarAgrupamento} + features: + delay: 0 + response: + status: 200 + body: + - Codigo: 1 + CodigoComponenteCurricularPai: 1 + RegistraFrequencia: true + LancaNota: true + GrupoMatriz: + Id: 1 +- method: GET + path: /eol/Turmas/{turma}/alunos-ativos/data-aula-ticks/{data-aula} + features: + delay: 0 + response: + status: 200 + body: + - nomeAluno: "Aluno 1" + CodigoAluno: 1 + NumeroAlunoChamada: 1 + Ano: 1 + CodigoSituacaoMatricula: 1 + SituacaoMatricula: Ativo + CodigoTurma: 1 + DataSituacao: "2023-01-01T00:00:00" + DataMatricula: "2023-01-01T00:00:00" +- method: GET + path: /eol/alunos/{codigoAluno}/turmas/anosLetivos/{anoLetivo}/historico/{consideraHistorico}/filtrar-situacao/{filtrarSituacao} + features: + delay: 0 + response: + status: 200 + body: + - nomeAluno: "Aluno 1" + CodigoAluno: 1 + NumeroAlunoChamada: 1 + Ano: 1 + CodigoSituacaoMatricula: 1 + SituacaoMatricula: Ativo + CodigoTurma: 1 + DataSituacao: "2023-01-01T00:00:00" + DataMatricula: "2023-01-01T00:00:00" +- method: GET + path: /eol/turmas/{codigoTurma}/dados + features: + delay: 0 + response: + status: 200 + body: + Ano: 1 + AnoLetivo: 2023 + Codigo: 1 + TipoTurma: Regular + Modalidade: Fundamental + CodigoModalidade: 1 + NomeTurma: "Turma 1" + Semestre: 0 +- method: GET + path: /eol/turmas/{codigoTurma}/todos-alunos + features: + delay: 0 + response: + status: 200 + body: + - nomeAluno: "Aluno 1" + CodigoAluno: 1 + NumeroAlunoChamada: 1 + Ano: 1 + CodigoSituacaoMatricula: 1 + SituacaoMatricula: Ativo + CodigoTurma: 1 + DataSituacao: "2023-01-01T00:00:00" + DataMatricula: "2023-01-01T00:00:00" +- method: GET + path: /eol/v1/componentes-curriculares/turmas/{codigoTurma}/funcionarios/{login}/perfis/{perfil}/planejamento + features: + delay: 0 + response: + status: 200 + body: + - Codigo: 1 + CodigoComponenteCurricularPai: 1 + RegistraFrequencia: true + LancaNota: true + GrupoMatriz: + Id: 1 +- method: GET + path: /eol/professores/{professorRf}/turmas/{codigoTurma}/disciplinas/{disciplinaId}/atribuicao/verificar/data + features: + delay: 0 + response: + status: 200 + body: + true +- method: GET + path: /eol/turmas/{turmaCodigo}/considera-inativos/{consideraInativos} + features: + delay: 0 + response: + status: 200 + body: + - nomeAluno: "Aluno 1" + CodigoAluno: 1 + NumeroAlunoChamada: 1 + Ano: 1 + CodigoSituacaoMatricula: 1 + SituacaoMatricula: Ativo + CodigoTurma: 1 + DataSituacao: "2023-01-01T00:00:00" + DataMatricula: "2023-01-01T00:00:00" +- method: GET + path: /eol/turmas/ues/{ueCodigo}/modalidades/{modalidade}/anos/{anoLetivo}/componentes + features: + delay: 0 + response: + status: 200 + body: + TotalPaginas: 1 + TotalRegistros: 100 + Items: + - Id: 1 + TurmaCodigo: 1 + Modalidade: Fundamental + NomeTurma: "Turma 1" + Ano: 1 + NomeComponenteCurricular: "Português" + ComponenteCurricularCodigo: 1 + ComponenteCurricularPaiCodigo: 1 + Turno: Manha +- method: GET + path: /eol/turmas/itinerario/ensino-medio + features: + delay: 0 + response: + status: 200 + body: + - Id: 1 + Nome: "Turma 1" + Serie: 1 +- method: GET + path: /eol/v1/componentes-curriculares/turmas + features: + delay: 0 + response: + status: 200 + body: + - Codigo: 1 + CodigoComponenteCurricularPai: 1 + RegistraFrequencia: true + LancaNota: true + GrupoMatriz: + Id : 1 +- method: GET + path: /api/v1/componentes-curriculares/turmas + features: + delay: 0 + response: + status: 200 + body: + - Codigo: 1 + Descricao: "Português" + LancaNota: true + Regencia: false +- method: POST + path: /eol/turmas/turmas-regulares + features: + delay: 0 + response: + status: 200 + body: + - "1" + - "2" +- method: GET + path: /eol/AutenticacaoSgp/CarregarDadosAcesso/usuarios/{login}/perfis/{perfilGuid} + features: + delay: 0 + response: + status: 200 + body: + Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJsb2dpbiI6ImFkbWluIiwibm9tZSI6IlNvbWVVc2VyIiwicmYiOiJzb21lLnVzZXIiLCJwZXJmaWwiOiI0NkUxRTA3NC0zN0Q2LUU5MTEtQUJENi1GODE2NTRGRTg5NUQiLCJyb2xlcyI6WyIxIiwiMiIsIjMiLCI0IiwiNSIsIjYiLCI3IiwiOCIsIjkiLCIxMCIsIjExIiwiMTIiLCIxMyIsIjE0IiwiMTUiLCIxNiIsIjE3IiwiMTgiLCIxOSIsIjIwIiwiMjEiLCIyMiIsIjIzIiwiMjQiLCIyNSIsIjI2IiwiMjciLCIyOCIsIjI5IiwiMzAiLCIzMSIsIjMyIiwiMzMiLCIzNCIsIjM1IiwiMzYiLCIzNyIsIjM4IiwiMzkiLCI0MCIsIjQxIiwiNDIiLCI0MyIsIjQ0IiwiNDUiLCI0NiIsIjQ3IiwiNDgiLCI0OSIsIjUwIiwiNTEiLCI1MiIsIjUzIiwiNTQiLCI1NSIsIjU2IiwiNTciLCI1OCIsIjU5IiwiNjAiLCI2MSIsIjYyIiwiNjMiLCI2NCIsIjY1IiwiNjYiLCI2NyIsIjY4IiwiNjkiLCI3MCIsIjcxIiwiNzIiLCI3MyIsIjc0IiwiNzUiLCI3NiIsIjc3IiwiNzgiLCI3OSIsIjgwIiwiODEiLCI4MiIsIjgzIiwiODQiLCI4NSIsIjg2IiwiODciLCI4OCIsIjg5IiwiOTAiLCI5MSIsIjkyIiwiOTMiLCI5NCIsIjk1IiwiOTYiLCI5NyIsIjk4IiwiOTkiLCIxMDAiLCIxMDEiLCIxMDIiLCIxMDMiLCIxMDQiLCIxMDUiLCIxMDYiLCIxMDciLCIxMDgiLCIxMDkiLCIxMTAiLCIxMTEiLCIxMTIiLCIxMTMiLCIxMTQiLCIxMTUiLCIxMTYiLCIxMTciLCIxMTgiLCIxMTkiLCIxMjAiLCIxMjEiLCIxMjIiLCIxMjMiLCIxMjQiLCIxMjUiLCIxMjYiLCIxMjciLCIxMjgiLCIxMjkiLCIxMzAiLCIxMzEiLCIxMzIiLCIxMzMiLCIxMzQiLCIxMzUiLCIxMzYiLCIxMzciLCIxMzgiLCIxMzkiLCIxNDAiLCIxNDEiLCIxNDIiLCIxNDMiLCIxNDQiLCIxNDUiLCIxNDYiLCIxNDciLCIxNDgiLCIxNDkiLCIxNTAiLCIxNTEiLCIxNTIiLCIxNTMiLCIxNTQiLCIxNTUiLCIxNTYiLCIxNTciLCIxNTgiLCIxNTkiLCIxNjAiLCIxNjEiLCIxNjIiLCIxNjMiLCIxNjQiLCIxNjUiLCIxNjYiLCIxNjciLCIxNjgiLCIxNjkiLCIxNzAiLCIxNzEiLCIxNzIiLCIxNzMiLCIxNzQiLCIxNzUiLCIxNzYiLCIxNzciLCIxNzgiLCIxNzkiLCIxODAiLCIxODEiLCIxODIiLCIxODMiLCIxODQiLCIxODUiLCIxODYiLCIxODciLCIxODgiLCIxODkiLCIxOTAiLCIxOTEiLCIxOTIiLCIxOTMiLCIxOTQiLCIxOTUiLCIxOTYiLCIxOTciLCIxOTgiLCIxOTkiLCIyMDAiLCIyMDEiLCIyMDIiLCIyMDMiLCIyMDQiLCIyMDUiLCIyMDYiLCIyMDciLCIyMDgiLCIyMDkiLCIyMTAiLCIyMTEiLCIyMTIiLCIyMTMiLCIyMTQiLCIyMTUiLCIyMTYiLCIyMTciLCIyMTgiLCIyMTkiLCIyMjAiLCIyMjEiLCIyMjIiLCIyMjMiLCIyMjQiLCIyMjUiLCIyMjYiLCIyMjciLCIyMjgiLCIyMjkiLCIyMzAiLCIyMzEiLCIyMzIiLCIyMzMiLCIyMzQiLCIyMzUiLCIyMzYiLCIyMzciLCIyMzgiLCIyMzkiLCIyNDAiLCIyNDEiLCIyNDIiLCIyNDMiLCIyNDQiLCIyNDUiLCIyNDYiLCIyNDciLCIyNDgiLCIyNDkiLCIyNTAiLCIyNTEiLCIyNTIiLCIyNTMiLCIyNTQiLCIyNTUiLCIyNTYiLCIyNTciLCIyNTgiLCIyNTkiLCIyNjAiLCIyNjEiLCIyNjIiLCIyNjMiLCIyNjQiLCIyNjUiLCIyNjYiLCIyNjciLCIyNjgiLCIyNjkiLCIyNzAiLCIyNzEiLCIyNzIiLCIyNzMiLCIyNzQiLCIyNzUiLCIyNzYiLCIyNzciLCIyNzgiLCIyNzkiLCIyODAiLCIyODEiLCIyODIiLCIyODMiLCIyODQiLCIyODUiLCIyODYiLCIyODciLCIyODgiLCIyODkiLCIyOTAiLCIyOTEiLCIyOTIiLCIyOTMiLCIyOTQiLCIyOTUiLCIyOTYiLCIyOTciLCIyOTgiLCIyOTkiLCIzMDAiXSwibmJmIjoxNTc1NDUwODUzLCJleHAiOjE4NzU0OTQwNTMsImlzcyI6IklQVCIsImF1ZCI6IkNsaWVudEFwcCJ9.zcA2n4EjW6GmfcxqSi1ojet353Yf9A8zNMknQSYFZXQ" + DataExpiracaoToken: "2029-06-06T23:34:13" + Permissoes: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + - 21 + - 22 + - 23 + - 24 + - 25 + - 26 + - 27 + - 28 + - 29 + - 30 + - 31 + - 32 + - 33 + - 34 + - 35 + - 36 + - 37 + - 38 + - 39 + - 40 + - 41 + - 42 + - 43 + - 44 + - 45 + - 46 + - 47 + - 48 + - 49 + - 50 + - 51 + - 52 + - 53 + - 54 + - 55 + - 56 + - 57 + - 58 + - 59 + - 60 + - 61 + - 62 + - 63 + - 64 + - 65 + - 66 + - 67 + - 68 + - 69 + - 70 + - 71 + - 72 + - 73 + - 74 + - 75 + - 76 + - 77 + - 78 + - 79 + - 80 + - 81 + - 82 + - 83 + - 84 + - 85 + - 86 + - 87 + - 88 + - 89 + - 90 + - 91 + - 92 + - 93 + - 94 + - 95 + - 96 + - 97 + - 98 + - 99 + - 100 + - 101 + - 102 + - 103 + - 104 + - 105 + - 106 + - 107 + - 108 + - 109 + - 110 + - 111 + - 112 + - 113 + - 114 + - 115 + - 116 + - 117 + - 118 + - 119 + - 120 + - 121 + - 122 + - 123 + - 124 + - 125 + - 126 + - 127 + - 128 + - 129 + - 130 + - 131 + - 132 + - 133 + - 134 + - 135 + - 136 + - 137 + - 138 + - 139 + - 140 + - 141 + - 142 + - 143 + - 144 + - 145 + - 146 + - 147 + - 148 + - 149 + - 150 + - 151 + - 152 + - 153 + - 154 + - 155 + - 156 + - 157 + - 158 + - 159 + - 160 + - 161 + - 162 + - 163 + - 164 + - 165 + - 166 + - 167 + - 168 + - 169 + - 170 + - 171 + - 172 + - 173 + - 174 + - 175 + - 176 + - 177 + - 178 + - 179 + - 180 + - 181 + - 182 + - 183 + - 184 + - 185 + - 186 + - 187 + - 188 + - 189 + - 190 + - 191 + - 192 + - 193 + - 194 + - 195 + - 196 + - 197 + - 198 + - 199 + - 200 + - 201 + - 202 + - 203 + - 204 + - 205 + - 206 + - 207 + - 208 + - 209 + - 210 + - 211 + - 212 + - 213 + - 214 + - 215 + - 216 + - 217 + - 218 + - 219 + - 220 + - 221 + - 222 + - 223 + - 224 + - 225 + - 226 + - 227 + - 228 + - 229 + - 230 + - 231 + - 232 + - 233 + - 234 + - 235 + - 236 + - 237 + - 238 + - 239 + - 240 + - 241 + - 242 + - 243 + - 244 + - 245 + - 246 + - 247 + - 248 + - 249 + - 250 + - 251 + - 252 + - 253 + - 254 + - 255 + - 256 + - 257 + - 258 + - 259 + - 260 + - 261 + - 262 + - 263 + - 264 + - 265 + - 266 + - 267 + - 268 + - 269 + - 270 + - 271 + - 272 + - 273 + - 274 + - 275 + - 276 + - 277 + - 278 + - 279 + - 280 + - 281 + - 282 + - 283 + - 284 + - 285 + - 286 + - 287 + - 288 + - 289 + - 290 + - 291 + - 292 + - 293 + - 294 + - 295 + - 296 + - 297 + - 298 + - 299 + - 300 diff --git a/mocks/github.yaml b/mocks/github.yaml new file mode 100644 index 0000000000..5c08166d60 --- /dev/null +++ b/mocks/github.yaml @@ -0,0 +1,9 @@ +- method: GET + path: /github/repos/prefeiturasp/SME-NovoSGP/tags + features: + delay: 0 + response: + status: 200 + body: + - name: "v.1000" + - name: "v.2000" \ No newline at end of file diff --git a/mocks/jurema.yaml b/mocks/jurema.yaml new file mode 100644 index 0000000000..ef6bd60394 --- /dev/null +++ b/mocks/jurema.yaml @@ -0,0 +1,8 @@ +- method: GET + path: /jurema/v1/learning_objectives + features: + delay: 0 + response: + status: 200 + body: + message: "ok" \ No newline at end of file diff --git a/src/SME.SGP.Api/Configuracoes/RegistraDocumentacaoSwagger.cs b/src/SME.SGP.Api/Configuracoes/RegistraDocumentacaoSwagger.cs index c2e9ee874e..a88aa05f8c 100644 --- a/src/SME.SGP.Api/Configuracoes/RegistraDocumentacaoSwagger.cs +++ b/src/SME.SGP.Api/Configuracoes/RegistraDocumentacaoSwagger.cs @@ -9,10 +9,10 @@ public static class RegistraDocumentacaoSwagger { public static void Registrar(IServiceCollection services) { - var sp = services.BuildServiceProvider(); - - var versaoService = sp.GetService(); - var versaoAtual = versaoService?.RecuperarUltimaVersao().Result; + var serviceProvider = services.BuildServiceProvider(); + var versaoService = serviceProvider.GetService()!; + var versaoAtual = versaoService.RecuperarUltimaVersao() + .GetAwaiter().GetResult(); services.AddSwaggerGen(c => { diff --git a/src/SME.SGP.Api/Configuracoes/RegistrarMvc.cs.rej b/src/SME.SGP.Api/Configuracoes/RegistrarMvc.cs.rej new file mode 100644 index 0000000000..f266f25bd0 --- /dev/null +++ b/src/SME.SGP.Api/Configuracoes/RegistrarMvc.cs.rej @@ -0,0 +1,53 @@ +diff a/src/SME.SGP.Api/Configuracoes/RegistrarMvc.cs b/src/SME.SGP.Api/Configuracoes/RegistrarMvc.cs (rejected hunks) +@@ -4,35 +4,37 @@ using Microsoft.AspNetCore.Mvc; + using Microsoft.Extensions.DependencyInjection; + using SME.SGP.Api.Filtros; + using SME.SGP.Api.Middlewares; +-using SME.SGP.Infra; +-using System.Text.Json.Serialization; + ++//namespace SME.SGP.Api.Configuracoes + namespace SME.SGP.Api + { + public static class RegistrarMvc + { + public static void Registrar(IServiceCollection services) + { +- var serviceProvider = services.BuildServiceProvider(); + ++ ++ ++ + services.Configure(options => + { + options.SuppressModelStateInvalidFilter = true; + }); + +- var conexao = serviceProvider.GetService(); +- var mediator = serviceProvider.GetService(); +- + services.AddMvc(options => +- { +- options.EnableEndpointRouting = true; +- options.Filters.Add(new ValidaDtoAttribute()); +- options.Filters.Add(new FiltroExcecoesAttribute(mediator)); +- options.Filters.Add(new DisposeConnectionFilter(conexao)); +- }) ++ { ++ options.EnableEndpointRouting = true; ++ options.Filters.Add(); ++ options.Filters.Add(); ++ //nao entendi esse filtro, ele recebou uma conexao fixa que sempre vai estar closed depois ++ //da primeira execucao ? Nao esta errada essa declaracao nao se for usar DI nao ? ++ options.Filters.Add(); ++ //consulta deveria ter um filtro tambem pra encerrar a conexao ? ++ options.Filters.Add(); ++ }) + .AddNewtonsoftJson() + .AddFluentValidation() +- .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); ++ .SetCompatibilityVersion(CompatibilityVersion.Version_3_0); + } + } + } +\ No newline at end of file diff --git a/src/SME.SGP.Api/Controllers/ArmazenamentoController.cs b/src/SME.SGP.Api/Controllers/ArmazenamentoController.cs index 40c2884238..1af35618ad 100644 --- a/src/SME.SGP.Api/Controllers/ArmazenamentoController.cs +++ b/src/SME.SGP.Api/Controllers/ArmazenamentoController.cs @@ -18,20 +18,16 @@ public class ArmazenamentoController : ControllerBase [ProducesResponseType(200)] [ProducesResponseType(401)] [ProducesResponseType(typeof(RetornoBaseDto), 500)] - //[RequestSizeLimit(200 * 1024 * 1024)] - public async Task Upload([FromForm] IFormFile file, [FromServices] IUploadDeArquivoUseCase useCase) + public async Task Upload([FromForm] IFormFile file, + [FromServices] IUploadDeArquivoUseCase useCase) { - try + if (file.Length > 0) { - if (file.Length > 0) - return Ok(await useCase.Executar(file)); - - return BadRequest(); - } - catch (Exception ex) - { - throw; + var guid = await useCase.Executar(file); + return Ok(guid); } + + return BadRequest(); } [HttpGet("{codigoArquivo}")] diff --git a/src/SME.SGP.Api/Controllers/DiarioBordoController.cs b/src/SME.SGP.Api/Controllers/DiarioBordoController.cs index 133df74395..43cd148d0b 100644 --- a/src/SME.SGP.Api/Controllers/DiarioBordoController.cs +++ b/src/SME.SGP.Api/Controllers/DiarioBordoController.cs @@ -106,6 +106,7 @@ public async Task AdicionarObservacao(long diarioBordoId, [FromBo [ProducesResponseType(typeof(AuditoriaDto), 200)] [ProducesResponseType(typeof(RetornoBaseDto), 500)] [Permissao(Permissao.DDB_C, Policy = "Bearer")] + //typo alterarrObservacao public async Task AlterarrObservacao(long observacaoId, [FromBody] ObservacaoDiarioBordoDto dto, [FromServices] IAlterarObservacaoDiarioBordoUseCase alterarObservacaoDiarioBordoUseCase) { return Ok(await alterarObservacaoDiarioBordoUseCase.Executar(dto.Observacao, observacaoId, dto.UsuariosIdNotificacao)); diff --git a/src/SME.SGP.Api/Controllers/FechamentoTurmaController.cs b/src/SME.SGP.Api/Controllers/FechamentoTurmaController.cs index 3f51cb0fed..04215548cc 100644 --- a/src/SME.SGP.Api/Controllers/FechamentoTurmaController.cs +++ b/src/SME.SGP.Api/Controllers/FechamentoTurmaController.cs @@ -50,7 +50,7 @@ public async Task Reprocessar(long fechamentoId, [FromServices] I [ProducesResponseType(typeof(RetornoBaseDto), 500)] [ProducesResponseType(typeof(RetornoBaseDto), 601)] [Permissao(Permissao.FB_A, Policy = "Bearer")] - public async Task Reprocessar(IEnumerable fechamentoId, [FromServices] IComandosFechamentoTurmaDisciplina comandos) + public IActionResult Reprocessar(IEnumerable fechamentoId, [FromServices] IComandosFechamentoTurmaDisciplina comandos) { comandos.Reprocessar(fechamentoId); return Ok(); diff --git a/src/SME.SGP.Api/Controllers/VersaoController.cs b/src/SME.SGP.Api/Controllers/VersaoController.cs index f489812fd8..4c12ec3a14 100644 --- a/src/SME.SGP.Api/Controllers/VersaoController.cs +++ b/src/SME.SGP.Api/Controllers/VersaoController.cs @@ -5,9 +5,13 @@ namespace SME.SGP.Api.Controllers { + + //o frontend esta solicitando essa url na pagina de login + //pelo que vi no blame passou a ser autorizada, esta certa essa modificacao? ou o front esta solicitando no momento errado + //ou essa autorizacao nao deveria existir aqui [ApiController] [Route("api/v1/versoes")] - [Authorize("Bearer")] + [AllowAnonymous] public class VersaoController : ControllerBase { [HttpGet] diff --git a/src/SME.SGP.Api/Filtros/DisposeConnectionFilter.cs b/src/SME.SGP.Api/Filtros/DisposeConnectionFilter.cs index 973c224b7e..4714a54917 100644 --- a/src/SME.SGP.Api/Filtros/DisposeConnectionFilter.cs +++ b/src/SME.SGP.Api/Filtros/DisposeConnectionFilter.cs @@ -1,10 +1,11 @@ -using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Filters; using SME.SGP.Infra; -using System; namespace SME.SGP.Api.Filtros { - public class DisposeConnectionFilter : IActionFilter + public class DisposeConnectionFilter : IActionFilter, IAsyncActionFilter { private readonly ISgpContext sgpContext; @@ -12,19 +13,22 @@ public DisposeConnectionFilter(ISgpContext sgpContext) { this.sgpContext = sgpContext ?? throw new ArgumentNullException(nameof(sgpContext)); } + public void OnActionExecuted(ActionExecutedContext context) { - if (sgpContext != null && sgpContext.State == System.Data.ConnectionState.Open) - { - sgpContext.Close(); - sgpContext.Dispose(); - } - + sgpContext.Close(); } public void OnActionExecuting(ActionExecutingContext context) { + sgpContext.Open(); + } + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + await sgpContext.OpenAsync(); + await next(); + await sgpContext.CloseAsync(); } } } diff --git a/src/SME.SGP.Api/Filtros/DisposeConnectionFilterConsulta.cs b/src/SME.SGP.Api/Filtros/DisposeConnectionFilterConsulta.cs new file mode 100644 index 0000000000..cfa63a09b9 --- /dev/null +++ b/src/SME.SGP.Api/Filtros/DisposeConnectionFilterConsulta.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Filters; +using SME.SGP.Infra.Interfaces; + +namespace SME.SGP.Api.Filtros +{ + public class DisposeConnectionFilterConsulta : IActionFilter, IAsyncActionFilter + { + private readonly ISgpContextConsultas sgpContextConsultas; + + public DisposeConnectionFilterConsulta(ISgpContextConsultas sgpContextConsultas) + { + this.sgpContextConsultas = + sgpContextConsultas ?? throw new ArgumentNullException(nameof(sgpContextConsultas)); + } + + public void OnActionExecuted(ActionExecutedContext context) + { + sgpContextConsultas.Close(); + } + + public void OnActionExecuting(ActionExecutingContext context) + { + sgpContextConsultas.Open(); + } + + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + await sgpContextConsultas.OpenAsync(); + await next(); + await sgpContextConsultas.CloseAsync(); + } + } +} \ No newline at end of file diff --git a/src/SME.SGP.Api/Middlewares/FiltroExcecoes.cs b/src/SME.SGP.Api/Middlewares/FiltroExcecoes.cs index 7cf3ffbe72..61f4e37a1a 100644 --- a/src/SME.SGP.Api/Middlewares/FiltroExcecoes.cs +++ b/src/SME.SGP.Api/Middlewares/FiltroExcecoes.cs @@ -7,16 +7,19 @@ using SME.SGP.Infra.Excecoes; using System; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; namespace SME.SGP.Api.Middlewares { public class FiltroExcecoesAttribute : ExceptionFilterAttribute { private readonly IMediator mediator; + private readonly ILogger logger; - public FiltroExcecoesAttribute(IMediator mediator) + public FiltroExcecoesAttribute(IMediator mediator, ILogger logger) { this.mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); + this.logger = logger; } public override async void OnException(ExceptionContext context) @@ -26,25 +29,31 @@ public override async void OnException(ExceptionContext context) switch (context.Exception) { case NegocioException negocioException: - await SalvaLogAsync(LogNivel.Negocio, context.Exception.Message, internalIP, context.Exception.StackTrace, context.Exception.InnerException?.ToString()); + await SalvaLogAsync(LogNivel.Negocio, context.Exception.Message, internalIP, + context.Exception.StackTrace, context.Exception.InnerException?.ToString()); context.Result = new ResultadoBaseResult(context.Exception.Message, negocioException.StatusCode); break; case ValidacaoException validacaoException: - await SalvaLogAsync(LogNivel.Negocio, context.Exception.Message, internalIP, context.Exception.StackTrace,context.Exception.InnerException?.ToString()); + await SalvaLogAsync(LogNivel.Negocio, context.Exception.Message, internalIP, + context.Exception.StackTrace,context.Exception.InnerException?.ToString()); context.Result = new ResultadoBaseResult(new RetornoBaseDto(validacaoException.Erros)); break; default: - await SalvaLogAsync(LogNivel.Critico, context.Exception.Message, internalIP, context.Exception.StackTrace,context.Exception.InnerException?.ToString()); + await SalvaLogAsync(LogNivel.Critico, context.Exception.Message, internalIP, + context.Exception.StackTrace,context.Exception.InnerException?.ToString()); context.Result = new ResultadoBaseResult("Ocorreu um erro interno. Favor contatar o suporte.", 500); break; } + //poderia logar essa exception no logger para entender o que esta acontecendo em caso de erro + logger.LogError(context.Exception, ""); base.OnException(context); } public async Task SalvaLogAsync(LogNivel nivel, string erro, string observacoes, string stackTrace, string innerException) { - await mediator.Send(new SalvarLogViaRabbitCommand(erro, nivel, LogContexto.Geral, observacoes, rastreamento: stackTrace,innerException:innerException)); + await mediator.Send(new SalvarLogViaRabbitCommand(erro, nivel, LogContexto.Geral, observacoes, + rastreamento: stackTrace,innerException:innerException)); } } } \ No newline at end of file diff --git a/src/SME.SGP.Api/Program.cs b/src/SME.SGP.Api/Program.cs index fdbc36bfb4..1f7cd70818 100644 --- a/src/SME.SGP.Api/Program.cs +++ b/src/SME.SGP.Api/Program.cs @@ -6,18 +6,17 @@ namespace SME.SGP.Api { public class Program { - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((hostingContext, config) => - { - config.AddEnvironmentVariables(); - config.AddUserSecrets(); - }) - .UseStartup(); - public static void Main(string[] args) { - CreateWebHostBuilder(args).Build().Run(); + WebHost.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((_, configurationBuilder) => + { + configurationBuilder.AddEnvironmentVariables(); + configurationBuilder.AddUserSecrets(); + }) + .UseStartup() + .Build() + .Run(); } } } \ No newline at end of file diff --git a/src/SME.SGP.Api/SME.SGP.Api.csproj b/src/SME.SGP.Api/SME.SGP.Api.csproj index 7f08206819..4c20f4f904 100644 --- a/src/SME.SGP.Api/SME.SGP.Api.csproj +++ b/src/SME.SGP.Api/SME.SGP.Api.csproj @@ -5,6 +5,7 @@ InProcess Linux bcb42d2a-866e-4723-8909-02682cfd7327 + false @@ -19,12 +20,11 @@ - - + diff --git a/src/SME.SGP.Api/Startup.cs b/src/SME.SGP.Api/Startup.cs index 8cebb32ef1..524b0b5a1f 100644 --- a/src/SME.SGP.Api/Startup.cs +++ b/src/SME.SGP.Api/Startup.cs @@ -4,7 +4,9 @@ using Elastic.Apm.SqlClient; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -70,7 +72,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) .AllowCredentials()); app.UseMetricServer(); - app.UseHttpMetrics(); app.UseAuthentication(); @@ -96,7 +97,7 @@ public void ConfigureServices(IServiceCollection services) var configTamanhoLimiteRequest = Configuration.GetSection("SGP_MaxRequestSizeBody").Value ?? "104857600"; - services.Configure(options => + services.Configure(options => { options.Limits.MaxRequestBodySize = long.Parse(configTamanhoLimiteRequest); }); @@ -130,7 +131,8 @@ public void ConfigureServices(IServiceCollection services) services.Configure(options => { options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("pt-BR"); - options.SupportedCultures = new List { new("pt-BR"), new("pt-BR") }; + //ta duplicado esse culture mesmo ? + options.SupportedCultures = new List {new("pt-BR")}; }); services.AddHealthChecksUiSgp() diff --git a/src/SME.SGP.Api/Startup.cs.rej b/src/SME.SGP.Api/Startup.cs.rej new file mode 100644 index 0000000000..9dc1711f31 --- /dev/null +++ b/src/SME.SGP.Api/Startup.cs.rej @@ -0,0 +1,16 @@ +diff a/src/SME.SGP.Api/Startup.cs b/src/SME.SGP.Api/Startup.cs (rejected hunks) +@@ -83,9 +84,11 @@ namespace SME.SGP.Api + if (threadPoolOptions.WorkerThreads > 0 && threadPoolOptions.CompletionPortThreads > 0) + ThreadPool.SetMinThreads(threadPoolOptions.WorkerThreads, threadPoolOptions.CompletionPortThreads); + +- Console.WriteLine("CURRENT------", Directory.GetCurrentDirectory()); +- Console.WriteLine("COMBINE------", Path.Combine(Directory.GetCurrentDirectory(), @"Imagens")); +- ++ //ideal é sempre usar log para logar essas coisas ++ //esses parametros tambem nao serao printados no console do jeito que estao ++ Console.WriteLine("CURRENT {0}:", Directory.GetCurrentDirectory()); ++ Console.WriteLine("COMBINE {0}:", Path.Combine(Directory.GetCurrentDirectory(), @"Imagens")); ++ + app.UseHealthChecksSgp(); + app.UseHealthCheckPrometheusSgp(); + } diff --git a/src/SME.SGP.Api/appsettings.json b/src/SME.SGP.Api/appsettings.json index 21a72d57f3..911a2573ee 100644 --- a/src/SME.SGP.Api/appsettings.json +++ b/src/SME.SGP.Api/appsettings.json @@ -1,8 +1,44 @@ { "ConnectionStrings": { - "SGP_Postgres": "", + "SGP_Postgres": "Host=localhost;Port=5432;Database=sgp_db;Username=postgres;Password=postgres;Timeout=30;Pooling=True;Maximum Pool Size=40;Application Name=SGP_DB", + "SGP_PostgresConsultas": "Host=localhost;Port=5432;Database=sgp_db;Username=postgres;Password=postgres;Timeout=30;Pooling=True;Maximum Pool Size=40;Application Name=SGP_DB_CONSULTA", "SGP_Redis": "" }, + "ElasticApm" : { + "ServerUrl": "http://localhost:8080/apm/" + }, + "JwtTokenSettings": { + "Audience": "ClientApp", + "ExpiresInMinutes": "525960", + "Issuer": "IPT", + "IssuerSigningKey": "f0d9ai0f908dsamufmud89saum0fud0sa89uf0d9s8af098dsa" + }, + "UrlApiEOL": "http://localhost:8080/eol/", + "UrlApiJurema": "http://localhost:8080/jurema/", + "UrlApiAE": "http://localhost:8080/ae/", + "ConfiguracaoRabbitLog" : { + "Port" : 5672, + "HostName": "localhost", + "Password": "rabbitmq", + "UserName": "rabbitmq", + "Virtualhost": "dev" + }, + "ConfiguracaoRabbit": { + "Port" : 5672, + "HostName": "localhost", + "Password": "rabbitmq", + "UserName": "rabbitmq", + "Virtualhost": "dev" + }, + "UrlApiGithub": "http://localhost:8080/github/", + "UsuarioGithub": "xxxxx", + "SenhaGithub": "xxxxx", + "Telemetria" : { + "ApplicationInsights": false, + "Apm": false + }, + + "API_URL": "", "ASPNETCORE_ENVIRONMENT": "", "ApiKeyEolApi": "", @@ -10,16 +46,10 @@ "ObjetivosAprendizagem": "" }, "FF_BackgroundEnabled": "", - "JwtTokenSettings": { - "Audience": "", - "ExpiresInMinutes": "", - "Issuer": "", - "IssuerSigningKey": "" - }, "Logging": { "LogLevel": { - "Default": "", - "Microsoft": "" + "Default": "Error", + "Microsoft": "Error" } }, "Nome_Instancia_Redis": "", @@ -28,8 +58,6 @@ "DSN": "" }, "TZ": "", - "UrlApiEOL": "", - "UrlApiJurema": "", "UrlFrontEnd": "", "AE_ChaveIntegracao": "", "ApplicationInsights": { @@ -40,22 +68,12 @@ "Username": "", "Password": "" }, - "ConfiguracaoRabbit": { - "HostName": "", - "Password": "", - "UserName": "", - "Virtualhost": "" - }, "HangfireUser": { "Admin": "", "Basic": "" }, - "SenhaGithub": "", "TRACKING_ID": "", - "UrlApiAE": "", - "UrlApiGithub": "", "UrlBackEnd": "", "UrlServidorRelatorios": "", - "UsuarioGithub": "", "VIEW_ID": "" } diff --git a/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterAbrangenciaDresUseCase.cs b/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterAbrangenciaDresUseCase.cs index 22cab6fbc5..2d1962e048 100644 --- a/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterAbrangenciaDresUseCase.cs +++ b/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterAbrangenciaDresUseCase.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using SME.SGP.Infra.Utilitarios; namespace SME.SGP.Aplicacao { @@ -16,13 +17,17 @@ public ObterAbrangenciaDresUseCase(IMediator mediator) : base(mediator) { } - public async Task> Executar(Modalidade? modalidade, int periodo = 0, bool consideraHistorico = false, int anoLetivo = 0, string filtro = "") + public async Task> Executar(Modalidade? modalidade, int periodo = 0, + bool consideraHistorico = false, int anoLetivo = 0, string filtro = "") { - var login = await mediator - .Send(new ObterLoginAtualQuery()); - var perfil = await mediator - .Send(new ObterPerfilAtualQuery()); + //Como essas instancia de query nao possuem parametro definido da pra usar sempre a mesma instancia + //evitando alocacao de memoria + var loginTask = mediator + .Send(ObterLoginAtualQuery.Instance); + + var perfilTask = mediator + .Send(ObterPerfilAtualQuery.Instance); var filtroEhCodigo = false; @@ -32,8 +37,22 @@ public async Task> Executar(Modalidade? mo filtroEhCodigo = true; } + //tem varios casos de use cases de computacoes distintas que estao aguardando umas as outras para executar + //nesses casos pode disparar todas ao mesmo tempo ja que sao interdependentes e acumular no final o resultado + //Um caso é utilizar whenall da plataforma + await UtilTasks.WhenAll(loginTask, perfilTask); + + //Outro caso é usar o await depois de todas as chamadas assincronas + var login = await loginTask; + var perfil = await perfilTask; + return await mediator - .Send(new ObterAbrangenciaDresQuery(login, perfil, modalidade, periodo, consideraHistorico, anoLetivo, filtro, filtroEhCodigo)); + .Send(new ObterAbrangenciaDresQuery(login, perfil, modalidade, periodo, consideraHistorico, anoLetivo, + filtro, filtroEhCodigo)); } + + + + } } \ No newline at end of file diff --git a/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterModalidadesPorAnoUseCase.cs b/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterModalidadesPorAnoUseCase.cs index 007169db22..099bba0762 100644 --- a/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterModalidadesPorAnoUseCase.cs +++ b/src/SME.SGP.Aplicacao/CasosDeUso/Abrangencia/ObterModalidadesPorAnoUseCase.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using SME.SGP.Infra.Utilitarios; namespace SME.SGP.Aplicacao { @@ -20,15 +21,31 @@ public ObterModalidadesPorAnoUseCase(IMediator mediator) public async Task> Executar(int anoLetivo, bool consideraHistorico, bool consideraNovasModalidades) { - var login = await mediator - .Send(new ObterLoginAtualQuery()); + //Como essas instancia de query nao possuem parametro definido da pra usar sempre a mesma instancia + //evitando alocacao de memoria para esses casos + var loginTask = mediator + .Send(ObterLoginAtualQuery.Instance); - var perfil = await mediator - .Send(new ObterPerfilAtualQuery()); + //Como essas instancia de query nao possuem parametro definido da pra usar sempre a mesma instancia + //evitando alocacao de memoria para esses casos + var perfilTask = mediator + .Send(ObterPerfilAtualQuery.Instance); - var modalidadesQueSeraoIgnoradas = await mediator + var modalidadesQueSeraoIgnoradasTask = mediator .Send(new ObterNovasModalidadesPorAnoQuery(anoLetivo, consideraNovasModalidades)); + //tem varios casos de use cases de computacoes distintas que estao aguardando umas as outras para executar com awaits encadeados + //nesses casos pode disparar todas ao mesmo tempo ja que sao interdependentes e acumular no final o resultado + //Um caso é utilizar whenall da plataforma + await UtilTasks.WhenAll(loginTask, perfilTask,modalidadesQueSeraoIgnoradasTask); + + //Outro caso é usar o await depois de todas as chamadas assincronas serem feitas, pra todos os efeitos nao da pra ter certeza se nesses + //casos que o comportamento bloqueia da mesma maneira na sequencia que não é desejavel e ainda nesses casos seriam 3 chamadas de state machine + //contra apenas uma da utilizacao de whenAll + Result + var login = loginTask.Result; //exemplo com Result que nesse caso é garantido estar computado e nao cria state machine + var perfil = await perfilTask; //exemplo com await ja Completed. Nesse caso vai criar state machine que vai executar direto, so fica codigo compilado a mais so, nao tem punicao. + var modalidadesQueSeraoIgnoradas = await modalidadesQueSeraoIgnoradasTask; + return await mediator .Send(new ObterModalidadesPorAnoQuery(anoLetivo, consideraHistorico, login, perfil, modalidadesQueSeraoIgnoradas)); } diff --git a/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSgpTratarUseCase.cs b/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSgpTratarUseCase.cs index 28b6e2235f..9786b3b784 100644 --- a/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSgpTratarUseCase.cs +++ b/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSgpTratarUseCase.cs @@ -25,15 +25,17 @@ public async Task Executar(MensagemRabbit mensagemRabbit) { var fila = mensagemRabbit.Mensagem.ToString(); - var factory = new ConnectionFactory + var configuracaoRabbit = configuration.GetSection("ConfiguracaoRabbit"); + var connectionFactory = new ConnectionFactory { - HostName = configuration.GetSection("ConfiguracaoRabbit:HostName").Value, - UserName = configuration.GetSection("ConfiguracaoRabbit:UserName").Value, - Password = configuration.GetSection("ConfiguracaoRabbit:Password").Value, - VirtualHost = configuration.GetSection("ConfiguracaoRabbit:Virtualhost").Value + Port = configuracaoRabbit.GetValue("Port"), + HostName = configuracaoRabbit.GetValue("HostName"), + UserName = configuracaoRabbit.GetValue("UserName"), + Password = configuracaoRabbit.GetValue("Password"), + VirtualHost = configuracaoRabbit.GetValue("Virtualhost") }; - await policy.ExecuteAsync(() => TratarMensagens(fila, factory)); + await policy.ExecuteAsync(() => TratarMensagens(fila, connectionFactory)); return await Task.FromResult(true); } @@ -52,6 +54,7 @@ private async Task TratarMensagens(string fila, ConnectionFactory factory) break; else { + //essa mensagem não é persistente ? await Task.Run(() => _channel.BasicPublish(ExchangeSgpRabbit.Sgp, fila, null, mensagemParaEnviar.Body.ToArray())); } } diff --git a/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSrTratarUseCase.cs b/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSrTratarUseCase.cs index a39c58a5cd..a3c51948ec 100644 --- a/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSrTratarUseCase.cs +++ b/src/SME.SGP.Aplicacao/CasosDeUso/RabbitDeadletter/RabbitDeadletterSrTratarUseCase.cs @@ -6,10 +6,18 @@ using SME.SGP.Aplicacao.Interfaces; using SME.SGP.Infra; using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; using System.Threading.Tasks; +using RabbitMQ.Client.Events; namespace SME.SGP.Aplicacao.CasosDeUso { + + + //nao seria mais interessante trabalhar com modelo de consumer de mensagem ao inves de polling? channel.BasicConsume algo do tipo + //e nao ficar relancando todas vezes public class RabbitDeadletterSrTratarUseCase : IRabbitDeadletterSrTratarUseCase { private readonly IConfiguration configuration; @@ -21,42 +29,110 @@ public RabbitDeadletterSrTratarUseCase(IConfiguration configuration, IReadOnlyPo this.policy = registry.Get(PoliticaPolly.PublicaFila); } + public async Task Executar(MensagemRabbit mensagemRabbit) { var fila = mensagemRabbit.Mensagem.ToString(); - var factory = new ConnectionFactory + var configuracaoRabbit = configuration.GetSection("ConfiguracaoRabbit"); + var connectionFactory = new ConnectionFactory { - HostName = configuration.GetSection("ConfiguracaoRabbit:HostName").Value, - UserName = configuration.GetSection("ConfiguracaoRabbit:UserName").Value, - Password = configuration.GetSection("ConfiguracaoRabbit:Password").Value, - VirtualHost = configuration.GetSection("ConfiguracaoRabbit:Virtualhost").Value + Port = configuracaoRabbit.GetValue("Port"), + HostName = configuracaoRabbit.GetValue("HostName"), + UserName = configuracaoRabbit.GetValue("UserName"), + Password = configuracaoRabbit.GetValue("Password"), + VirtualHost = configuracaoRabbit.GetValue("Virtualhost") }; - await policy.ExecuteAsync(() => TratarMensagens(fila, factory)); + await policy.ExecuteAsync(() => TratarMensagens(fila, connectionFactory)); - return await Task.FromResult(true); + //da pra retornar direto aqui nao ? + return true; } private async Task TratarMensagens(string fila, ConnectionFactory factory) { - using (var conexaoRabbit = factory.CreateConnection()) - { - using (IModel _channel = conexaoRabbit.CreateModel()) - { - while (true) - { - var mensagemParaEnviar = _channel.BasicGet($"{fila}.deadletter", true); - - if (mensagemParaEnviar == null) - break; - else - { - await Task.Run(() => _channel.BasicPublish(ExchangeSgpRabbit.ServidorRelatorios, fila, null, mensagemParaEnviar.Body.ToArray())); - } - } - } + using var conexaoRabbit = factory.CreateConnection(); + using var channel = conexaoRabbit.CreateModel(); + + //Nao seria ideal gerenciar esses tipos de controle de loop com algum dispose para suportar graceful shutdown + //caso precise parar essas threads dos workers fora do laco de while ? + //while (running) algo assim com dispose que seta running para false + //ou ate mesmo algo mais inteligente no while como readers como enumerables + + //var basicGetResults = BasicGetResults(channel, $"{fila}.deadletter"); + var basicGetResults = new BasicGetResultEnumerable(channel, $"{fila}.deadletter"); + foreach(var basicGetResult in basicGetResults) + { + //essa mensagem não é persistente ? + await Task.Run(() => channel.BasicPublish(ExchangeSgpRabbit.ServidorRelatorios, fila, null, basicGetResult.Body.ToArray())); + } + + } + + //Ou metodo estatico com yield return ou algo do tipo + public IEnumerable BasicGetResults(IModel channel, string fila) + { + BasicGetResult basicGetResult; + while ((basicGetResult = channel.BasicGet(fila, true)) is not null) + { + yield return basicGetResult; } } + + //Ou talvez extrair esse reader em uma classe separada que outros usariam para o modelo de pooling + public class BasicGetResultEnumerable : IEnumerable,IDisposable + { + private readonly IModel _channel; + private readonly string _fila; + + public BasicGetResultEnumerable(IModel channel, string fila) + { + _channel = channel; + _fila = fila; + } + + public IEnumerator GetEnumerator() => new BasicGetResultEnumerator(_channel,_fila); + IEnumerator IEnumerable.GetEnumerator() => new BasicGetResultEnumerator(_channel,_fila); + + public void Dispose() + { + + } + + } + + public class BasicGetResultEnumerator : IEnumerator + { + private readonly IModel _channel; + private readonly string _fila; + private BasicGetResult _current; + + public BasicGetResultEnumerator(IModel channel, string fila) + { + _channel = channel; + _fila = fila; + } + + public bool MoveNext() + { + _current = _channel.BasicGet(_fila, true); + return _current is not null; + } + + public void Reset() + { + + } + + public BasicGetResult Current => _current; + object IEnumerator.Current => _current; + + public void Dispose() + { + + } + } + } } diff --git a/src/SME.SGP.Aplicacao/CasosDeUso/RotasAgendamentoSync/RotasAgendamentoTratarUseCase.cs b/src/SME.SGP.Aplicacao/CasosDeUso/RotasAgendamentoSync/RotasAgendamentoTratarUseCase.cs index 8b3f511948..7cbd5f33c7 100644 --- a/src/SME.SGP.Aplicacao/CasosDeUso/RotasAgendamentoSync/RotasAgendamentoTratarUseCase.cs +++ b/src/SME.SGP.Aplicacao/CasosDeUso/RotasAgendamentoSync/RotasAgendamentoTratarUseCase.cs @@ -30,15 +30,17 @@ public async Task Executar(MensagemRabbit mensagemRabbit) { var fila = mensagemRabbit.Mensagem.ToString(); - var factory = new ConnectionFactory + var configuracaoRabbit = configuration.GetSection("ConfiguracaoRabbit"); + var connectionFactory = new ConnectionFactory { - HostName = configuration.GetSection("ConfiguracaoRabbit:HostName").Value, - UserName = configuration.GetSection("ConfiguracaoRabbit:UserName").Value, - Password = configuration.GetSection("ConfiguracaoRabbit:Password").Value, - VirtualHost = configuration.GetSection("ConfiguracaoRabbit:Virtualhost").Value + Port = configuracaoRabbit.GetValue("Port"), + HostName = configuracaoRabbit.GetValue("HostName"), + UserName = configuracaoRabbit.GetValue("UserName"), + Password = configuracaoRabbit.GetValue("Password"), + VirtualHost = configuracaoRabbit.GetValue("Virtualhost") }; - await policy.ExecuteAsync(() => TratarMensagens(fila, factory)); + await policy.ExecuteAsync(() => TratarMensagens(fila, connectionFactory)); return true; } diff --git a/src/SME.SGP.Aplicacao/Comandos/ComandosNotificacao.cs b/src/SME.SGP.Aplicacao/Comandos/ComandosNotificacao.cs index dec2984d43..a2290497e1 100644 --- a/src/SME.SGP.Aplicacao/Comandos/ComandosNotificacao.cs +++ b/src/SME.SGP.Aplicacao/Comandos/ComandosNotificacao.cs @@ -86,15 +86,15 @@ public async Task> MarcarComoLida(IList MapearParaDominio(NotificacaoDto notificacaoDto) { - var notificacao = new Notificacao() + var notificacao = new Notificacao { Categoria = notificacaoDto.Categoria, DreId = notificacaoDto.DreId, @@ -107,27 +107,22 @@ private Notificacao MapearParaDominio(NotificacaoDto notificacaoDto) Codigo = notificacaoDto.Codigo }; - TrataUsuario(notificacao, notificacaoDto.UsuarioRf); - - return notificacao; + return await TrataUsuario(notificacao, notificacaoDto.UsuarioRf); } private Notificacao ObterPorIdENotificarCasoNaoExista(long notificacaoId) { - Notificacao notificacao = repositorioNotificacao.ObterPorId(notificacaoId); - if (notificacao == null) - { - throw new NegocioException($"Notificação com id: '{notificacaoId}' não encontrada."); - } - - return notificacao; + return repositorioNotificacao.ObterPorId(notificacaoId) ?? + throw new NegocioException($"Notificação com id: '{notificacaoId}' não encontrada."); } - private async void TrataUsuario(Notificacao notificacao, string usuarioRf) + //Evitar uso de async void que pode derrubar uma instancia inteira de aplicacao caso lance uma exception + private async Task TrataUsuario(Notificacao notificacao, string usuarioRf) { var usuario = await servicoUsuario.ObterUsuarioPorCodigoRfLoginOuAdiciona(usuarioRf); notificacao.Usuario = usuario; notificacao.UsuarioId = usuario.Id; + return notificacao; } } } \ No newline at end of file diff --git a/src/SME.SGP.Aplicacao/Comandos/ComandosPlanoAnual.cs b/src/SME.SGP.Aplicacao/Comandos/ComandosPlanoAnual.cs index f9286663ee..9188628f0c 100644 --- a/src/SME.SGP.Aplicacao/Comandos/ComandosPlanoAnual.cs +++ b/src/SME.SGP.Aplicacao/Comandos/ComandosPlanoAnual.cs @@ -87,6 +87,9 @@ public void Migrar(MigrarPlanoAnualDto migrarPlanoAnualDto) } } unitOfWork.PersistirTransacao(); + + + //Nao tem rotina de rollback pra esse caso? } public async Task> Salvar(PlanoAnualDto planoAnualDto) diff --git a/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs b/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs index 6a4e67ca4c..8fa0bdc376 100644 --- a/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs +++ b/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs @@ -173,6 +173,7 @@ public async Task ModificarPerfil(Guid perfil) }; var dadosAcesso = await servicoEOL.CarregarDadosAcessoPorLoginPerfil(loginAtual, perfil, administradorSuporte); + //aqui pode dar nullpointer em dadosAcesso nao? var permissionamentos = dadosAcesso.Permissoes.ToList(); if (permissionamentos == null || !permissionamentos.Any()) @@ -236,6 +237,9 @@ public async Task RevalidarLogin() // Busca lista de permissões do EOL var dadosAcesso = await servicoEOL.CarregarDadosAcessoPorLoginPerfil(login, guidPerfil); + //aqui pode dar nullpointer em dadosAcesso nao? + + var permissionamentos = dadosAcesso.Permissoes.ToList(); if (!permissionamentos.Any()) diff --git a/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs.rej b/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs.rej new file mode 100644 index 0000000000..d3f359b839 --- /dev/null +++ b/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs.rej @@ -0,0 +1,94 @@ +diff a/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs b/src/SME.SGP.Aplicacao/Comandos/ComandosUsuario.cs (rejected hunks) +@@ -1,12 +1,12 @@ +-using MediatR; ++using System; ++using System.Collections.Generic; ++using System.Linq; ++using System.Threading.Tasks; ++using MediatR; + using SME.SGP.Aplicacao.Integracoes; + using SME.SGP.Dominio; + using SME.SGP.Dominio.Interfaces; + using SME.SGP.Infra; +-using System; +-using System.Collections.Generic; +-using System.Linq; +-using System.Threading.Tasks; + + namespace SME.SGP.Aplicacao + { +@@ -91,26 +91,28 @@ namespace SME.SGP.Aplicacao + { + login = login.Trim().ToLower(); + var retornoAutenticacaoEol = await servicoAutenticacao.AutenticarNoEol(login, senha); +- + return await ObterAutenticacao(retornoAutenticacaoEol, login); + } +- +- public async Task ObterAutenticacao((UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool) ++ ++ ++ //sugestao de nomear tuplas se for manter ou trocar para records ou tipos de estrutura mais flexiveis ++ //que encapsulem o retorno. Nomeando a tuple fica bem mais legivel a logica executada ++ public async Task ObterAutenticacao((UsuarioAutenticacaoRetornoDto UsuarioAutenticacaoRetornoDto, string CodigoRf, IEnumerable Perfis, bool PossuiCargoCJ, bool PossuiPerfilCJ) + retornoAutenticacaoEol, string login, AdministradorSuporteDto administradorSuporte = null) + { +- if (!retornoAutenticacaoEol.Item1.Autenticado) +- return retornoAutenticacaoEol.Item1; ++ if (!retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.Autenticado) ++ return retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto; + + var dadosUsuario = await servicoEOL.ObterMeusDados(login); + +- var usuario = await servicoUsuario.ObterUsuarioPorCodigoRfLoginOuAdiciona(retornoAutenticacaoEol.Item2, login, dadosUsuario.Nome, dadosUsuario.Email, true); ++ var usuario = await servicoUsuario.ObterUsuarioPorCodigoRfLoginOuAdiciona(retornoAutenticacaoEol.CodigoRf, login, dadosUsuario.Nome, dadosUsuario.Email, true); + +- retornoAutenticacaoEol.Item1.PerfisUsuario = await servicoPerfil.DefinirPerfilPrioritario(retornoAutenticacaoEol.Item3, usuario); ++ retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.PerfisUsuario = await servicoPerfil.DefinirPerfilPrioritario(retornoAutenticacaoEol.Perfis, usuario); + +- var perfis = retornoAutenticacaoEol.Item1.PerfisUsuario.Perfis.Select(x => x.CodigoPerfil).ToList(); +- servicoAbrangencia.RemoverAbrangenciasHistoricasIncorretas(login, perfis); ++ var perfis = retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.PerfisUsuario.Perfis.Select(x => x.CodigoPerfil).ToList(); ++ await servicoAbrangencia.RemoverAbrangenciasHistoricasIncorretas(login, perfis); + +- var perfilSelecionado = retornoAutenticacaoEol.Item1.PerfisUsuario.PerfilSelecionado; ++ var perfilSelecionado = retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.PerfisUsuario.PerfilSelecionado; + + var dadosAcesso = await servicoEOL.CarregarDadosAcessoPorLoginPerfil(login, perfilSelecionado, administradorSuporte); + +@@ -118,25 +120,25 @@ namespace SME.SGP.Aplicacao + + if (!permissionamentos.Any()) + { +- retornoAutenticacaoEol.Item1.Autenticado = false; +- return retornoAutenticacaoEol.Item1; ++ retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.Autenticado = false; ++ return retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto; + } +- +- retornoAutenticacaoEol.Item1.Token = dadosAcesso.Token; +- retornoAutenticacaoEol.Item1.DataHoraExpiracao = dadosAcesso.DataExpiracaoToken; ++ ++ retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.Token = dadosAcesso.Token; ++ retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.DataHoraExpiracao = dadosAcesso.DataExpiracaoToken; + + usuario.AtualizaUltimoLogin(); + await mediator.Send(new PublicarFilaSgpCommand(RotasRabbitSgp.AtualizaUltimoLoginUsuario, usuario)); + + await mediator.Send(new CarregarAbrangenciaUsuarioCommand(login, perfilSelecionado)); + +- retornoAutenticacaoEol.Item1.UsuarioLogin = usuario.Login; +- retornoAutenticacaoEol.Item1.UsuarioRf = usuario.CodigoRf; +- retornoAutenticacaoEol.Item1.AdministradorSuporte = administradorSuporte; ++ retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.UsuarioLogin = usuario.Login; ++ retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.UsuarioRf = usuario.CodigoRf; ++ retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto.AdministradorSuporte = administradorSuporte; + +- return retornoAutenticacaoEol.Item1; ++ return retornoAutenticacaoEol.UsuarioAutenticacaoRetornoDto; + } +- ++ + public async Task ModificarPerfil(Guid perfil) + { + var loginAtual = servicoUsuario.ObterLoginAtual(); diff --git a/src/SME.SGP.Aplicacao/Commands/Arquivos/MoverArquivosTemporarios/MoverArquivosTemporariosCommandHandler.cs b/src/SME.SGP.Aplicacao/Commands/Arquivos/MoverArquivosTemporarios/MoverArquivosTemporariosCommandHandler.cs index f8b97c6696..6f38a952a8 100644 --- a/src/SME.SGP.Aplicacao/Commands/Arquivos/MoverArquivosTemporarios/MoverArquivosTemporariosCommandHandler.cs +++ b/src/SME.SGP.Aplicacao/Commands/Arquivos/MoverArquivosTemporarios/MoverArquivosTemporariosCommandHandler.cs @@ -15,6 +15,12 @@ public class MoverArquivosTemporariosCommandHandler : IRequestHandler configuracaoArmazenamentoOptions) { @@ -23,16 +29,15 @@ public MoverArquivosTemporariosCommandHandler(IMediator mediator,IOptions Handle(MoverArquivosTemporariosCommand request, CancellationToken cancellationToken) { - var regex = new Regex(ArmazenamentoObjetos.EXPRESSAO_NOME_ARQUIVO); - var regexImagensPasta = new Regex(ArmazenamentoObjetos.EXPRESSAO_NOME_ARQUIVO_COM_PASTA); - var novo = regex.Matches(request.TextoEditorNovo).Cast().Select(c => c.Value).ToList(); - var atual = regex.Matches(!string.IsNullOrEmpty(request.TextoEditorAtual) ? request.TextoEditorAtual : string.Empty).Cast().Select(c => c.Value).ToList(); + var novo = Regex.Matches(request.TextoEditorNovo).Cast().Select(c => c.Value).ToList(); + var atual = Regex.Matches(!string.IsNullOrEmpty(request.TextoEditorAtual) ? request.TextoEditorAtual : string.Empty).Cast().Select(c => c.Value).ToList(); - var imagensEditorNovo = regexImagensPasta.Matches(request.TextoEditorNovo).Cast().Select(c => c.Value).ToList(); + var imagensEditorNovo = RegexImagensPasta.Matches(request.TextoEditorNovo).Cast().Select(c => c.Value).ToList(); novo = imagensEditorNovo.Any() ? RetornaImagensTemporariasParaMover(imagensEditorNovo) : novo; - var diferenca = novo.Any() ? novo.Except(atual) : new List(); + //precisaria nem alocar uma lista vazia + var diferenca = novo.Any() ? novo.Except(atual) : Enumerable.Empty(); foreach (var item in diferenca) { diff --git a/src/SME.SGP.Aplicacao/Commands/AtribuicaoCJ/InserirAtribuicaoCJ/InserirAtribuicaoCJCommandHandler.cs.rej b/src/SME.SGP.Aplicacao/Commands/AtribuicaoCJ/InserirAtribuicaoCJ/InserirAtribuicaoCJCommandHandler.cs.rej new file mode 100644 index 0000000000..c5799a74cd --- /dev/null +++ b/src/SME.SGP.Aplicacao/Commands/AtribuicaoCJ/InserirAtribuicaoCJ/InserirAtribuicaoCJCommandHandler.cs.rej @@ -0,0 +1,10 @@ +diff a/src/SME.SGP.Aplicacao/Commands/AtribuicaoCJ/InserirAtribuicaoCJ/InserirAtribuicaoCJCommandHandler.cs b/src/SME.SGP.Aplicacao/Commands/AtribuicaoCJ/InserirAtribuicaoCJ/InserirAtribuicaoCJCommandHandler.cs (rejected hunks) +@@ -96,7 +96,7 @@ namespace SME.SGP.Aplicacao + (!atribuicoesAtuais.Any(a => a.Id != atribuicaoCJ.Id && a.Substituir))) + { + if (ehHistorico) +- repositorioAbrangencia.ExcluirAbrangenciasHistoricas(abrangenciasAtuais.Select(a => a.Id).ToArray()); ++ await repositorioAbrangencia.ExcluirAbrangenciasHistoricas(abrangenciasAtuais.Select(a => a.Id).ToArray()); + else + repositorioAbrangencia.ExcluirAbrangencias(abrangenciasAtuais.Select(a => a.Id).ToArray()); + diff --git a/src/SME.SGP.Aplicacao/Commands/DiarioBordo/AlterarObservacaoDiarioBordo/AlterarObservacaoDiarioBordoCommandHandler.cs b/src/SME.SGP.Aplicacao/Commands/DiarioBordo/AlterarObservacaoDiarioBordo/AlterarObservacaoDiarioBordoCommandHandler.cs index 551a0a1f85..cf99922bcb 100644 --- a/src/SME.SGP.Aplicacao/Commands/DiarioBordo/AlterarObservacaoDiarioBordo/AlterarObservacaoDiarioBordoCommandHandler.cs +++ b/src/SME.SGP.Aplicacao/Commands/DiarioBordo/AlterarObservacaoDiarioBordo/AlterarObservacaoDiarioBordoCommandHandler.cs @@ -27,7 +27,6 @@ public AlterarObservacaoDiarioBordoCommandHandler(IRepositorioDiarioBordoObserva public async Task Handle(AlterarObservacaoDiarioBordoCommand request, CancellationToken cancellationToken) { var diarioBordoObservacao = await repositorioDiarioBordoObservacao.ObterPorIdAsync(request.ObservacaoId); - var usuario = await mediator.Send(new ObterUsuarioLogadoQuery()); if (diarioBordoObservacao == null) throw new NegocioException("Observação do diário de bordo não encontrada."); @@ -38,6 +37,7 @@ public async Task Handle(AlterarObservacaoDiarioBordoCommand reque await repositorioDiarioBordoObservacao.SalvarAsync(diarioBordoObservacao); var notificacoes = await repositorioDiarioBordoObservacaoNotificacao.ObterPorDiarioBordoObservacaoId(request.ObservacaoId); + var usuario = await mediator.Send(new ObterUsuarioLogadoQuery()); if (request.Observacao.Trim().Length < 200 && (request.UsuariosIdNotificacao == null || !request.UsuariosIdNotificacao.Any())) { diff --git a/src/SME.SGP.Aplicacao/Commands/FilaRabbit/PublicarFilaSgp/PublicarFilaSgpCommandHandler.cs b/src/SME.SGP.Aplicacao/Commands/FilaRabbit/PublicarFilaSgp/PublicarFilaSgpCommandHandler.cs index 5ef28bcfac..9e339efbd8 100644 --- a/src/SME.SGP.Aplicacao/Commands/FilaRabbit/PublicarFilaSgp/PublicarFilaSgpCommandHandler.cs +++ b/src/SME.SGP.Aplicacao/Commands/FilaRabbit/PublicarFilaSgp/PublicarFilaSgpCommandHandler.cs @@ -25,7 +25,7 @@ public async Task Handle(PublicarFilaSgpCommand command, CancellationToken { var usuario = command.Usuario ?? await ObtenhaUsuario(); - var administrador = await mediator.Send(new ObterAdministradorDoSuporteQuery()); + var administrador = await mediator.Send(ObterAdministradorDoSuporteQuery.Instance); var mensagem = new MensagemRabbit(command.Filtros, command.CodigoCorrelacao, diff --git a/src/SME.SGP.Aplicacao/Consultas/ConsultasProfessorTurma.cs b/src/SME.SGP.Aplicacao/Consultas/ConsultasProfessorTurma.cs index d5e0790c25..442f990196 100644 --- a/src/SME.SGP.Aplicacao/Consultas/ConsultasProfessorTurma.cs +++ b/src/SME.SGP.Aplicacao/Consultas/ConsultasProfessorTurma.cs @@ -101,6 +101,11 @@ private async Task ObterProfessorUeRFEOL(string codigoRF, in } public async Task> ObterTurmasAtribuidasAoProfessorPorEscolaEAnoLetivo(string rfProfessor, string codigoEscola, int anoLetivo) { + //Tem patterns mais interessantes para lidar com caches como ComputeIfAbsent por exemplo usando lazy delegates e genericos e formatos + // ex: var turmaDto = await cache.ObterAsync>(chave, () => funcaoquedeveserarmazenadaemcache, CacheEntryFormat.JSON); + // return turmaDto + //Outro caso utilizando patterns como decorators deixando a logica de cache envolta da chamada sem poluicao + //Ou ate mesmo usando dynamic proxies com diretive de cache especificas IEnumerable turmasDto = null; var chaveCache = $"Turmas-Professor-{rfProfessor}-ano-{anoLetivo}-escolal-{codigoEscola}"; var disciplinasCacheString = repositorioCache.Obter(chaveCache); diff --git a/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs b/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs index b2961b4680..6810977a54 100644 --- a/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs +++ b/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs @@ -11,8 +11,12 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Json; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; +using JsonSerializer = System.Text.Json.JsonSerializer; namespace SME.SGP.Aplicacao.Integracoes { @@ -20,6 +24,13 @@ public class ServicoEOL : IServicoEol { private readonly IMediator mediator; private readonly HttpClient httpClient; + private readonly JsonSerializerOptions options = new JsonSerializerOptions + { + Converters = + { + new JsonStringEnumConverter() + } + }; public ServicoEOL(HttpClient httpClient, IMediator mediator) { @@ -29,11 +40,14 @@ public ServicoEOL(HttpClient httpClient, IMediator mediator) public async Task AlterarEmail(string login, string email) { - var valoresParaEnvio = new List> { - { new KeyValuePair("usuario", login) }, - { new KeyValuePair("email", email) }}; + var valoresParaEnvio = new List> + { + {new KeyValuePair("usuario", login)}, + {new KeyValuePair("email", email)} + }; - var resposta = await httpClient.PostAsync($"AutenticacaoSgp/AlterarEmail", new FormUrlEncodedContent(valoresParaEnvio)); + var resposta = await httpClient.PostAsync($"AutenticacaoSgp/AlterarEmail", + new FormUrlEncodedContent(valoresParaEnvio)); if (resposta.IsSuccessStatusCode) return; @@ -45,16 +59,19 @@ public async Task AlterarEmail(string login, string email) public async Task AlterarSenha(string login, string novaSenha) { - var valoresParaEnvio = new List> { - { new KeyValuePair("usuario", login) }, - { new KeyValuePair("senha", novaSenha) }}; + var valoresParaEnvio = new List> + { + {new KeyValuePair("usuario", login)}, + {new KeyValuePair("senha", novaSenha)} + }; - var resposta = await httpClient.PostAsync($"AutenticacaoSgp/AlterarSenha", new FormUrlEncodedContent(valoresParaEnvio)); + var resposta = await httpClient.PostAsync($"AutenticacaoSgp/AlterarSenha", + new FormUrlEncodedContent(valoresParaEnvio)); return new AlterarSenhaRespostaDto { Mensagem = resposta.IsSuccessStatusCode ? "" : await resposta.Content.ReadAsStringAsync(), - StatusRetorno = (int)resposta.StatusCode, + StatusRetorno = (int) resposta.StatusCode, SenhaAlterada = resposta.IsSuccessStatusCode }; } @@ -75,7 +92,8 @@ public async Task> ObterComponentesCurricul public async Task TurmaPossuiComponenteCurricularPAP(string codigoTurma, string login, Guid idPerfil) { - var url = $"v1/componentes-curriculares/turmas/{codigoTurma}/funcionarios/{login}/perfis/{idPerfil}/validar/pap"; + var url = + $"v1/componentes-curriculares/turmas/{codigoTurma}/funcionarios/{login}/perfis/{idPerfil}/validar/pap"; var resposta = await httpClient.GetAsync(url); @@ -98,7 +116,8 @@ public async Task AtribuirCJSeNecessario(Guid usuarioId) { var parametros = JsonConvert.SerializeObject(usuarioId.ToString()); - var resposta = await httpClient.PostAsync("autenticacaoSgp/AtribuirPerfilCJ", new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); + var resposta = await httpClient.PostAsync("autenticacaoSgp/AtribuirPerfilCJ", + new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); if (resposta.IsSuccessStatusCode) return; @@ -108,20 +127,19 @@ public async Task AtribuirCJSeNecessario(Guid usuarioId) throw new NegocioException(mensagem); } - public async Task Autenticar(string login, string senha) + //O ideal pra esses tipo de casos é trabalhar com tipos opcionais. Optional, Either, Maybe.. + //Retornar null para qualquer caso não deixa claro pro chamador que o valor pode vir nulo + //no caso de c# ainda tem o tipo Nullable (se ativar no compilador) que tem o mesmo efeito como no exemplo + public async Task Autenticar(string login, string senha) { - var parametros = JsonConvert.SerializeObject(new { login, senha }); - var resposta = await httpClient.PostAsync($"v1/autenticacao", new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); - + var jsonContent = JsonContent.Create(new {login, senha}); + var resposta = await httpClient.PostAsync($"v1/autenticacao", jsonContent); if (resposta.IsSuccessStatusCode) { - var json = await resposta.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(json); - } - else - { - return null; + var contentStream = await resposta.Content.ReadAsStreamAsync(); + return await JsonSerializer.DeserializeAsync(contentStream, options); } + return null; } public IEnumerable BuscarCiclos() @@ -165,6 +183,7 @@ public async Task ExisteUsuarioComMesmoEmail(string login, string email) var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(json); } + return false; } @@ -177,17 +196,21 @@ public async Task ObterAbrangencia(string login, Guid var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(json); } + return null; } - public async Task ObterAbrangenciaCompactaVigente(string login, Guid perfil) + public async Task ObterAbrangenciaCompactaVigente(string login, + Guid perfil) { - var resposta = await httpClient.GetAsync($"abrangencia/compacta-vigente/{login}/perfil/{perfil.ToString()}"); + var resposta = + await httpClient.GetAsync($"abrangencia/compacta-vigente/{login}/perfil/{perfil.ToString()}"); if (resposta.IsSuccessStatusCode) { - var json = await resposta.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(json); + var contentStream = await resposta.Content.ReadAsStreamAsync(); + return await JsonSerializer.DeserializeAsync(contentStream, + options); } return null; @@ -216,6 +239,7 @@ public async Task ObterAdministradoresSGP(string codigoDreOuUe) var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(json); } + return null; } @@ -228,17 +252,21 @@ public async Task ObterAdministradoresSGPParaNotificar(string codigoDr var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(json); } + return null; } - public async Task> ObterAlunosPorNomeCodigoEol(string anoLetivo, string codigoUe, long codigoTurma, string nome, long? codigoEol, bool? somenteAtivos) + public async Task> ObterAlunosPorNomeCodigoEol(string anoLetivo, + string codigoUe, long codigoTurma, string nome, long? codigoEol, bool? somenteAtivos) { var alunos = new List(); var url = $"alunos/ues/{codigoUe}/anosLetivos/{anoLetivo}/autocomplete" - + (codigoTurma > 0 ? $"?codigoTurma={codigoTurma}" : null) - + (codigoEol.HasValue ? $"{(codigoTurma > 0 ? "&" : "?") + $"codigoEol={codigoEol}"}" : "") - + (nome != null ? $"{(codigoEol != null || codigoTurma > 0 ? "&" : "?") + $"nomeAluno={nome}"}" : "") - + (somenteAtivos == true ? $"&somenteAtivos={somenteAtivos}" : ""); + + (codigoTurma > 0 ? $"?codigoTurma={codigoTurma}" : null) + + (codigoEol.HasValue ? $"{(codigoTurma > 0 ? "&" : "?") + $"codigoEol={codigoEol}"}" : "") + + (nome != null + ? $"{(codigoEol != null || codigoTurma > 0 ? "&" : "?") + $"nomeAluno={nome}"}" + : "") + + (somenteAtivos == true ? $"&somenteAtivos={somenteAtivos}" : ""); var resposta = await httpClient.GetAsync(url); @@ -291,7 +319,8 @@ public async Task> ObterDisciplinasPorCodigoTurm } [Obsolete("Utilizar: ObterComponentesCurricularesPorCodigoTurmaLoginEPerfil", true)] - public async Task> ObterDisciplinasPorCodigoTurmaLoginEPerfil(string codigoTurma, string login, Guid perfil) + public async Task> ObterDisciplinasPorCodigoTurmaLoginEPerfil( + string codigoTurma, string login, Guid perfil) { var url = $"funcionarios/{login}/perfis/{perfil}/turmas/{codigoTurma}/disciplinas"; @@ -307,7 +336,8 @@ public async Task> ObterComponentesRegencia public async Task> ObterDisciplinasPorIdsSemAgrupamento(long[] ids) { var parametros = JsonConvert.SerializeObject(ids); - var resposta = await httpClient.PostAsync("disciplinas/SemAgrupamento", new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); + var resposta = await httpClient.PostAsync("disciplinas/SemAgrupamento", + new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); if (!resposta.IsSuccessStatusCode || resposta.StatusCode == HttpStatusCode.NoContent) { @@ -330,17 +360,22 @@ public IEnumerable ObterDres() var json = resposta.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } public IEnumerable ObterEscolasPorCodigo(string[] codigoUes) { - var resposta = httpClient.PostAsync("escolas", new StringContent(JsonConvert.SerializeObject(codigoUes), Encoding.UTF8, "application/json-patch+json")).Result; + var resposta = httpClient.PostAsync("escolas", + new StringContent(JsonConvert.SerializeObject(codigoUes), Encoding.UTF8, + "application/json-patch+json")) + .Result; if (resposta.IsSuccessStatusCode) { var json = resposta.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } @@ -352,6 +387,7 @@ public IEnumerable ObterEscolasPorDre(string dreId) var json = resposta.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } @@ -378,8 +414,11 @@ public EstruturaInstitucionalRetornoEolDTO ObterEstruturaInstuticionalVigentePor } else { - _ = mediator.Send(new SalvarLogViaRabbitCommand($"Ocorreu um erro na tentativa de buscar os dados de Estrutura Institucional Vigente - HttpCode {resposta.StatusCode} - Body {resposta.Content?.ReadAsStringAsync()?.Result ?? string.Empty}", LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; - throw new NegocioException($"Erro ao obter a estrutura organizacional vigente no EOL. URL base: {httpClient.BaseAddress}"); + _ = mediator.Send(new SalvarLogViaRabbitCommand( + $"Ocorreu um erro na tentativa de buscar os dados de Estrutura Institucional Vigente - HttpCode {resposta.StatusCode} - Body {resposta.Content?.ReadAsStringAsync()?.Result ?? string.Empty}", + LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; + throw new NegocioException( + $"Erro ao obter a estrutura organizacional vigente no EOL. URL base: {httpClient.BaseAddress}"); } } } @@ -387,9 +426,11 @@ public EstruturaInstitucionalRetornoEolDTO ObterEstruturaInstuticionalVigentePor return resultado; } - public EstruturaInstitucionalRetornoEolDTO ObterEstruturaInstuticionalVigentePorTurma(string[] codigosTurma = null) + public EstruturaInstitucionalRetornoEolDTO ObterEstruturaInstuticionalVigentePorTurma( + string[] codigosTurma = null) { - var filtroTurmas = new StringContent(JsonConvert.SerializeObject(codigosTurma ?? new string[] { }), UnicodeEncoding.UTF8, "application/json"); + var filtroTurmas = new StringContent(JsonConvert.SerializeObject(codigosTurma ?? new string[] { }), + UnicodeEncoding.UTF8, "application/json"); string url = $"abrangencia/estrutura-vigente"; @@ -402,12 +443,14 @@ public EstruturaInstitucionalRetornoEolDTO ObterEstruturaInstuticionalVigentePor } else { - _ = mediator.Send(new SalvarLogViaRabbitCommand($"Ocorreu um erro na tentativa de buscar os dados de Estrutura Institucional Vigente - HttpCode {resposta.StatusCode} - Body {resposta.Content?.ReadAsStringAsync()?.Result ?? string.Empty}", LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; + _ = mediator.Send(new SalvarLogViaRabbitCommand( + $"Ocorreu um erro na tentativa de buscar os dados de Estrutura Institucional Vigente - HttpCode {resposta.StatusCode} - Body {resposta.Content?.ReadAsStringAsync()?.Result ?? string.Empty}", + LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; return null; } } - + public async Task> ObterFuncionariosPorCargoUeAsync(string ueId, long cargoId) { var resposta = await httpClient.GetAsync($"escolas/{ueId}/funcionarios/cargos/{cargoId}"); @@ -416,12 +459,15 @@ public async Task> ObterFuncionariosPorCargoUe var json = resposta.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } - public async Task> ObterFuncionariosPorUe(BuscaFuncionariosFiltroDto buscaFuncionariosFiltroDto) + public async Task> ObterFuncionariosPorUe( + BuscaFuncionariosFiltroDto buscaFuncionariosFiltroDto) { - var jsonParaPost = new StringContent(JsonConvert.SerializeObject(buscaFuncionariosFiltroDto), UnicodeEncoding.UTF8, "application/json"); + var jsonParaPost = new StringContent(JsonConvert.SerializeObject(buscaFuncionariosFiltroDto), + UnicodeEncoding.UTF8, "application/json"); var resposta = await httpClient.PostAsync("funcionarios/", jsonParaPost); @@ -438,7 +484,7 @@ public async Task> ObterListaNomePorListaRF(IEnu { var resposta = await httpClient.PostAsync($"funcionarios/BuscarPorListaRF", new StringContent(JsonConvert.SerializeObject(codigosRF), - Encoding.UTF8, "application/json-patch+json")); + Encoding.UTF8, "application/json-patch+json")); if (!resposta.IsSuccessStatusCode) return null; @@ -451,11 +497,12 @@ public async Task> ObterListaNomePorListaRF(IEnu return JsonConvert.DeserializeObject>(json); } - public async Task> ObterListaResumosPorListaRF(IEnumerable codigosRF, int anoLetivo) + public async Task> ObterListaResumosPorListaRF(IEnumerable codigosRF, + int anoLetivo) { var resposta = await httpClient.PostAsync($"professores/{anoLetivo}/BuscarPorListaRF", new StringContent(JsonConvert.SerializeObject(codigosRF), - Encoding.UTF8, "application/json-patch+json")); + Encoding.UTF8, "application/json-patch+json")); if (!resposta.IsSuccessStatusCode) return null; @@ -476,6 +523,7 @@ public IEnumerable ObterListaTurmasPorProfessor(string co var json = resposta.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } @@ -484,46 +532,62 @@ public async Task ObterMeusDados(string login) var url = $"AutenticacaoSgp/{login}/dados"; var resposta = await httpClient.GetAsync(url); - if (!resposta.IsSuccessStatusCode) + if (resposta.IsSuccessStatusCode) { - await RegistrarLogAsync(resposta, "ObterMeusDados", "login = " + login); - throw new NegocioException("Não foi possível obter os dados do usuário"); + var contentStream = await resposta.Content.ReadAsStreamAsync(); + return await JsonSerializer.DeserializeAsync(contentStream); } - var json = await resposta.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(json); + + await RegistrarLogAsync(resposta, "ObterMeusDados", "login = " + login); + throw new NegocioException("Não foi possível obter os dados do usuário"); } - public async Task ObterPerfisPorLogin(string login) + public async Task ObterPerfisPorLogin(string login) { var resposta = await httpClient.GetAsync($"autenticacaoSgp/CarregarPerfisPorLogin/{login}"); if (resposta.IsSuccessStatusCode) { - var json = await resposta.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(json); + var contentStream = await resposta.Content.ReadAsStreamAsync(); + return await JsonSerializer.DeserializeAsync(contentStream); } + + //o ideal é ja falhar aqui a tentativa de carregar o perfil, pelo que vi o tratamento + //está propagando pra tudo que é chamador e nao tem nada que indique para o chamador que isso + //pode retornar null return null; } - public async Task CarregarDadosAcessoPorLoginPerfil(string login, Guid perfilGuid, AdministradorSuporteDto administradorSuporte = null) + public async Task CarregarDadosAcessoPorLoginPerfil(string login, + Guid perfilGuid, AdministradorSuporteDto administradorSuporte = null) { - HttpResponseMessage resposta; - - if (administradorSuporte != null) - resposta = await httpClient.GetAsync($"AutenticacaoSgp/CarregarDadosAcesso/usuarios/{login}/perfis/{perfilGuid}?loginAdm={administradorSuporte.Login}&nomeAdm={administradorSuporte.Nome}"); - else - resposta = await httpClient.GetAsync($"AutenticacaoSgp/CarregarDadosAcesso/usuarios/{login}/perfis/{perfilGuid}"); - - if (!resposta.IsSuccessStatusCode) - return null; - - var json = await resposta.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(json); + var uri = administradorSuporte is null + ? $"AutenticacaoSgp/CarregarDadosAcesso/usuarios/{login}/perfis/{perfilGuid}" + : $"AutenticacaoSgp/CarregarDadosAcesso/usuarios/{login}/perfis/{perfilGuid}?loginAdm={administradorSuporte.Login}&nomeAdm={administradorSuporte.Nome}"; + + var resposta = await httpClient.GetAsync(uri); + + if (resposta.IsSuccessStatusCode) + { + //pelo profile de memoria esta alocando gigas de memoria para trabalhar com string + //e depois converter para objeto, o ideal é usar implementacoes mais modernas + //que usam stream e fazem pouca alocacao de memoria na heap + var contentStream = await resposta.Content.ReadAsStreamAsync(); + return await JsonSerializer.DeserializeAsync(contentStream); + } + + //nao tem nada que indique para o chamador que isso + //pode retornar null, o ideal é lancar uma exceção caso nao consiga carregar os dados de perfil + //ou outra estrategia para continuar logando. + return null; } - public async Task> ObterProfessoresAutoComplete(int anoLetivo, string dreId, string ueId, string nomeProfessor) + public async Task> ObterProfessoresAutoComplete(int anoLetivo, string dreId, + string ueId, string nomeProfessor) { - var resposta = await httpClient.GetAsync($"professores/{anoLetivo}/AutoComplete/{dreId}?nome={nomeProfessor}&ueId={ueId}"); + var resposta = + await httpClient.GetAsync( + $"professores/{anoLetivo}/AutoComplete/{dreId}?nome={nomeProfessor}&ueId={ueId}"); if (!resposta.IsSuccessStatusCode) return null; @@ -534,9 +598,12 @@ public async Task> ObterProfessoresAutoComplete( return JsonConvert.DeserializeObject>(json); } - public async Task> ObterProfessoresAutoComplete(int anoLetivo, string dreId, string nomeProfessor, bool incluirEmei) + public async Task> ObterProfessoresAutoComplete(int anoLetivo, string dreId, + string nomeProfessor, bool incluirEmei) { - var resposta = await httpClient.GetAsync($"professores/{anoLetivo}/AutoComplete/{dreId}/{incluirEmei}?nome={nomeProfessor}"); + var resposta = + await httpClient.GetAsync( + $"professores/{anoLetivo}/AutoComplete/{dreId}/{incluirEmei}?nome={nomeProfessor}"); if (!resposta.IsSuccessStatusCode) return null; @@ -548,7 +615,8 @@ public async Task> ObterProfessoresAutoComplete( return JsonConvert.DeserializeObject>(json); } - public async Task> ObterProfessoresTitularesPorTurmas(IEnumerable codigosTurmas) + public async Task> ObterProfessoresTitularesPorTurmas( + IEnumerable codigosTurmas) { StringBuilder url = new StringBuilder(); @@ -564,7 +632,7 @@ public async Task> ObterProfessoresTi var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(json); } - + public async Task ObterNomeProfessorPeloRF(string rfProfessor) { StringBuilder url = new StringBuilder(); @@ -598,9 +666,12 @@ public async Task ObterResumoCore(string login) return JsonConvert.DeserializeObject(json); } - public async Task ObterResumoProfessorPorRFAnoLetivo(string codigoRF, int anoLetivo, bool buscarOutrosCargos = false) + public async Task ObterResumoProfessorPorRFAnoLetivo(string codigoRF, int anoLetivo, + bool buscarOutrosCargos = false) { - var resposta = await httpClient.GetAsync($"professores/{codigoRF}/BuscarPorRf/{anoLetivo}?buscarOutrosCargos={buscarOutrosCargos}"); + var resposta = + await httpClient.GetAsync( + $"professores/{codigoRF}/BuscarPorRf/{anoLetivo}?buscarOutrosCargos={buscarOutrosCargos}"); if (!resposta.IsSuccessStatusCode) throw new NegocioException("Ocorreu uma falha ao consultar o professor"); @@ -615,7 +686,8 @@ public async Task ObterResumoProfessorPorRFAnoLetivo(string public async Task ObterProfessorPorRFUeDreAnoLetivo(string codigoRF, int anoLetivo, string dreId, string ueId, bool buscarOutrosCargos = false, bool buscarPorTodasDre = false) { - if (string.IsNullOrWhiteSpace(codigoRF) || anoLetivo == 0 || (!buscarPorTodasDre && (string.IsNullOrWhiteSpace(dreId) || string.IsNullOrWhiteSpace(ueId)))) + if (string.IsNullOrWhiteSpace(codigoRF) || anoLetivo == 0 || (!buscarPorTodasDre && (string.IsNullOrWhiteSpace(dreId) || + string.IsNullOrWhiteSpace(ueId)))) throw new NegocioException("É necessario informar o codigoRF Dre, UE e o ano letivo"); string paramUeId = string.Empty, paramDreId = string.Empty; @@ -697,12 +769,15 @@ public async Task ObterProfessorPorRFUeDreAnoLetivo(string c public IEnumerable ObterSupervisoresPorCodigo(string[] codigoSupervisores) { - var resposta = httpClient.PostAsync("funcionarios/supervisores", new StringContent(JsonConvert.SerializeObject(codigoSupervisores), Encoding.UTF8, "application/json-patch+json")).Result; + var resposta = httpClient.PostAsync("funcionarios/supervisores", + new StringContent(JsonConvert.SerializeObject(codigoSupervisores), Encoding.UTF8, + "application/json-patch+json")).Result; if (resposta.IsSuccessStatusCode) { var json = resposta.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } @@ -714,22 +789,28 @@ public IEnumerable ObterSupervisoresPorDre(string dreId) var json = resposta.Content.ReadAsStringAsync().Result; return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } - public async Task> ObterTurmasAtribuidasAoProfessorPorEscolaEAnoLetivo(string rfProfessor, string codigoEscola, int anoLetivo) + public async Task> ObterTurmasAtribuidasAoProfessorPorEscolaEAnoLetivo(string rfProfessor, + string codigoEscola, int anoLetivo) { - var resposta = await httpClient.GetAsync($"professores/{rfProfessor}/escolas/{codigoEscola}/turmas/anos_letivos/{anoLetivo}"); + var resposta = + await httpClient.GetAsync( + $"professores/{rfProfessor}/escolas/{codigoEscola}/turmas/anos_letivos/{anoLetivo}"); if (resposta.IsSuccessStatusCode) { var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(json); } + return null; } - public async Task> ObterTurmasParaCopiaPlanoAnual(string codigoRf, long componenteCurricularId, int codigoTurma) + public async Task> ObterTurmasParaCopiaPlanoAnual(string codigoRf, + long componenteCurricularId, int codigoTurma) { var parametros = JsonConvert.SerializeObject(new { @@ -738,13 +819,15 @@ public async Task> ObterTurmasParaCopia codigoTurma }); - var resposta = await httpClient.PostAsync($"funcionarios/BuscarTurmasElegiveis", new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); + var resposta = await httpClient.PostAsync($"funcionarios/BuscarTurmasElegiveis", + new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); var turmas = new List(); if (resposta.IsSuccessStatusCode) { var json = await resposta.Content.ReadAsStringAsync(); turmas = JsonConvert.DeserializeObject>(json); } + return turmas; } @@ -757,6 +840,7 @@ public async Task> ObterTurmasPorUE(string ueId, var json = resposta.Content.ReadAsStringAsync().Result; turmas = JsonConvert.DeserializeObject>(json); } + return turmas; } @@ -764,7 +848,8 @@ public async Task PodePersistirTurma(string professorRf, string codigoTurm { var dataString = data.ToString("s"); - var resposta = await httpClient.GetAsync($"professores/{professorRf}/turmas/{codigoTurma}/atribuicao/verificar/data?dataConsulta={dataString}"); + var resposta = await httpClient.GetAsync( + $"professores/{professorRf}/turmas/{codigoTurma}/atribuicao/verificar/data?dataConsulta={dataString}"); if (!resposta.IsSuccessStatusCode) throw new NegocioException("Não foi possível validar a atribuição do professor no EOL."); @@ -773,11 +858,13 @@ public async Task PodePersistirTurma(string professorRf, string codigoTurm return JsonConvert.DeserializeObject(json); } - public async Task PodePersistirTurmaDisciplina(string professorRf, string codigoTurma, string disciplinaId, DateTime data) + public async Task PodePersistirTurmaDisciplina(string professorRf, string codigoTurma, + string disciplinaId, DateTime data) { var dataString = data.ToString("s"); - var resposta = await httpClient.GetAsync($"professores/{professorRf}/turmas/{codigoTurma}/disciplinas/{disciplinaId}/atribuicao/verificar/data?={dataString}"); + var resposta = await httpClient.GetAsync( + $"professores/{professorRf}/turmas/{codigoTurma}/disciplinas/{disciplinaId}/atribuicao/verificar/data?={dataString}"); if (!resposta.IsSuccessStatusCode) throw new NegocioException("Não foi possível validar a atribuição do professor no EOL."); @@ -786,9 +873,11 @@ public async Task PodePersistirTurmaDisciplina(string professorRf, string return JsonConvert.DeserializeObject(json); } - public async Task VerificaAtribuicaoProfessorTurma(string professorRf, string codigoTurma) + public async Task VerificaAtribuicaoProfessorTurma(string professorRf, + string codigoTurma) { - var resposta = await httpClient.GetAsync($"professores/{professorRf}/turmas/{codigoTurma}/atribuicao/status"); + var resposta = + await httpClient.GetAsync($"professores/{professorRf}/turmas/{codigoTurma}/atribuicao/status"); if (resposta.IsSuccessStatusCode) { var json = resposta.Content.ReadAsStringAsync().Result; @@ -802,10 +891,13 @@ public async Task VerificaAtribuicaoProfessorTur public async Task ReiniciarSenha(string login) { - IList> valoresParaEnvio = new List> { - { new KeyValuePair("login", login) }}; + IList> valoresParaEnvio = new List> + { + {new KeyValuePair("login", login)} + }; - var resposta = await httpClient.PostAsync($"AutenticacaoSgp/ReiniciarSenha", new FormUrlEncodedContent(valoresParaEnvio)); + var resposta = await httpClient.PostAsync($"AutenticacaoSgp/ReiniciarSenha", + new FormUrlEncodedContent(valoresParaEnvio)); if (!resposta.IsSuccessStatusCode) throw new NegocioException("Não foi possível reiniciar a senha deste usuário"); @@ -813,10 +905,13 @@ public async Task ReiniciarSenha(string login) public async Task RelecionarUsuarioPerfis(string login) { - IList> valoresParaEnvio = new List> { - { new KeyValuePair("login", login) }}; + IList> valoresParaEnvio = new List> + { + {new KeyValuePair("login", login)} + }; - var resposta = await httpClient.PostAsync($"AutenticacaoSgp/RelacionarUsuarioPerfis", new FormUrlEncodedContent(valoresParaEnvio)); + var resposta = await httpClient.PostAsync($"AutenticacaoSgp/RelacionarUsuarioPerfis", + new FormUrlEncodedContent(valoresParaEnvio)); if (resposta.IsSuccessStatusCode) { @@ -833,7 +928,8 @@ public async Task RemoverCJSeNecessario(Guid usuarioId) { var parametros = JsonConvert.SerializeObject(usuarioId.ToString()); - var resposta = await httpClient.PostAsync("autenticacaoSgp/RemoverPerfilCJ", new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); + var resposta = await httpClient.PostAsync("autenticacaoSgp/RemoverPerfilCJ", + new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); if (resposta.IsSuccessStatusCode) return; @@ -852,6 +948,7 @@ public async Task ValidarProfessor(string professorRf) var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(json); } + return false; } @@ -889,8 +986,11 @@ private string[] ObterCodigosDres() } else { - _ = mediator.Send(new SalvarLogViaRabbitCommand($"Ocorreu um erro na tentativa de buscar os codigos das Dres no EOL - HttpCode {resposta.StatusCode} - Body {resposta.Content?.ReadAsStringAsync()?.Result ?? string.Empty} - URL: {httpClient.BaseAddress}", LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; - throw new NegocioException($"Erro ao obter os códigos de DREs no EOL. URL base: {httpClient.BaseAddress}"); + _ = mediator.Send(new SalvarLogViaRabbitCommand( + $"Ocorreu um erro na tentativa de buscar os codigos das Dres no EOL - HttpCode {resposta.StatusCode} - Body {resposta.Content?.ReadAsStringAsync()?.Result ?? string.Empty} - URL: {httpClient.BaseAddress}", + LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; + throw new NegocioException( + $"Erro ao obter os códigos de DREs no EOL. URL base: {httpClient.BaseAddress}"); } } @@ -936,7 +1036,9 @@ private void RegistrarLog(HttpResponseMessage resposta, string rotina, string pa if (resposta.StatusCode != HttpStatusCode.NotFound) { var mensagem = resposta.Content.ReadAsStringAsync().Result; - _ = mediator.Send(new SalvarLogViaRabbitCommand($"Ocorreu um erro ao {rotina} no EOL, código de erro: {resposta.StatusCode}, mensagem: {mensagem ?? "Sem mensagem"},Parametros:{parametros}, Request: {JsonConvert.SerializeObject(resposta.RequestMessage)}, ", LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; + _ = mediator.Send(new SalvarLogViaRabbitCommand( + $"Ocorreu um erro ao {rotina} no EOL, código de erro: {resposta.StatusCode}, mensagem: {mensagem ?? "Sem mensagem"},Parametros:{parametros}, Request: {JsonConvert.SerializeObject(resposta.RequestMessage)}, ", + LogNivel.Negocio, LogContexto.ApiEol, string.Empty)).Result; } } @@ -945,25 +1047,32 @@ private async Task RegistrarLogAsync(HttpResponseMessage resposta, string rotina if (resposta.StatusCode != HttpStatusCode.NotFound) { var mensagem = await resposta.Content.ReadAsStringAsync(); - await mediator.Send(new SalvarLogViaRabbitCommand($"Ocorreu um erro ao {rotina} no EOL, código de erro: {resposta.StatusCode}, mensagem: {mensagem ?? "Sem mensagem"},Parametros:{parametros}, Request: {JsonConvert.SerializeObject(resposta.RequestMessage)}, ", LogNivel.Negocio, LogContexto.ApiEol, string.Empty)); + await mediator.Send(new SalvarLogViaRabbitCommand( + $"Ocorreu um erro ao {rotina} no EOL, código de erro: {resposta.StatusCode}, mensagem: {mensagem ?? "Sem mensagem"},Parametros:{parametros}, Request: {JsonConvert.SerializeObject(resposta.RequestMessage)}, ", + LogNivel.Negocio, LogContexto.ApiEol, string.Empty)); } } - public async Task> ObterFuncionariosPorDre(Guid perfil, FiltroFuncionarioDto filtroFuncionariosDto) + public async Task> ObterFuncionariosPorDre(Guid perfil, + FiltroFuncionarioDto filtroFuncionariosDto) { - var resposta = await httpClient.GetAsync($@"funcionarios/perfis/{perfil}/dres/{filtroFuncionariosDto.CodigoDRE}?CodigoUe={filtroFuncionariosDto.CodigoUE}&CodigoRf={filtroFuncionariosDto.CodigoRF}&NomeServidor={filtroFuncionariosDto.NomeServidor}"); + var resposta = await httpClient.GetAsync( + $@"funcionarios/perfis/{perfil}/dres/{filtroFuncionariosDto.CodigoDRE}?CodigoUe={filtroFuncionariosDto.CodigoUE}&CodigoRf={filtroFuncionariosDto.CodigoRF}&NomeServidor={filtroFuncionariosDto.NomeServidor}"); if (resposta.IsSuccessStatusCode) { var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } - public async Task> ObterComponentesCurricularesPorAnosEModalidade(string codigoUe, Modalidade modalidade, string[] anosEscolares, int anoLetivo) + public async Task> ObterComponentesCurricularesPorAnosEModalidade( + string codigoUe, Modalidade modalidade, string[] anosEscolares, int anoLetivo) { - var url = $@"v1/componentes-curriculares/ues/{codigoUe}/modalidades/{(int)modalidade}/anos/{anoLetivo}/anos-escolares?anosEscolares={string.Join("&anosEscolares=", anosEscolares)}"; + var url = + $@"v1/componentes-curriculares/ues/{codigoUe}/modalidades/{(int) modalidade}/anos/{anoLetivo}/anos-escolares?anosEscolares={string.Join("&anosEscolares=", anosEscolares)}"; var resposta = await httpClient.GetAsync(url); @@ -972,10 +1081,13 @@ public async Task> ObterComponentesCurricul var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } - public async Task> ObterComponentesCurricularesTurmasProgramaPorAnoEModalidade(string codigoUe, Modalidade modalidade, int anoLetivo) + public async Task> + ObterComponentesCurricularesTurmasProgramaPorAnoEModalidade(string codigoUe, Modalidade modalidade, + int anoLetivo) { var url = $@"v1/componentes-curriculares/ues/{codigoUe}/modalidades/{modalidade}/anos/{anoLetivo}"; @@ -986,6 +1098,7 @@ public async Task> ObterComponentesCurricul var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(json); } + return Enumerable.Empty(); } @@ -1001,12 +1114,15 @@ public async Task AtribuirPerfil(string codigoRf, Guid perfil) throw new NegocioException(mensagem); } - public async Task PodePersistirTurmaNoPeriodo(string professorRf, string codigoTurma, long componenteCurricularId, DateTime dataInicio, DateTime dataFim) + public async Task PodePersistirTurmaNoPeriodo(string professorRf, string codigoTurma, + long componenteCurricularId, DateTime dataInicio, DateTime dataFim) { var dataInicioString = dataInicio.ToString("s"); var dataFimString = dataFim.ToString("s"); - var resposta = await httpClient.PostAsync($"professores/{professorRf}/turmas/{codigoTurma}/componentes/{componenteCurricularId}/atribuicao/periodo/inicio/{dataInicioString}/fim/{dataFimString}", new StringContent("")); + var resposta = await httpClient.PostAsync( + $"professores/{professorRf}/turmas/{codigoTurma}/componentes/{componenteCurricularId}/atribuicao/periodo/inicio/{dataInicioString}/fim/{dataFimString}", + new StringContent("")); if (!resposta.IsSuccessStatusCode) throw new NegocioException("Não foi possível validar a atribuição do professor no EOL."); @@ -1022,7 +1138,8 @@ public async Task> ObterDisciplinasPorIdsAgrupadas(lo var url = @"disciplinas/turma/"; if (codigoTurma != null) url += $"?codigoTurma={codigoTurma}"; - var resposta = await httpClient.PostAsync(url, new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); + var resposta = await httpClient.PostAsync(url, + new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); if (!resposta.IsSuccessStatusCode || resposta.StatusCode == HttpStatusCode.NoContent) { @@ -1053,7 +1170,8 @@ public async Task ObterNecessidadesEspeciaisAluno( public async Task> DefinirTurmasRegulares(string[] codigosTurmas) { var parametros = JsonConvert.SerializeObject(codigosTurmas); - var resposta = await httpClient.PostAsync("turmas/turmas-regulares", new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); + var resposta = await httpClient.PostAsync("turmas/turmas-regulares", + new StringContent(parametros, Encoding.UTF8, "application/json-patch+json")); if (!resposta.IsSuccessStatusCode || resposta.StatusCode == HttpStatusCode.NoContent) { @@ -1065,10 +1183,13 @@ public async Task> DefinirTurmasRegulares(string[] codigosTu return JsonConvert.DeserializeObject>(json); } - - public async Task> ListagemTurmasComComponente(string codigoUe, string modalidade, int bimestre, string codigoTurma, int anoLetivo, int qtdeRegistros, int qtdeRegistrosIgnorados) + + public async Task> ListagemTurmasComComponente( + string codigoUe, string modalidade, int bimestre, string codigoTurma, int anoLetivo, int qtdeRegistros, + int qtdeRegistrosIgnorados) { - var url = $@"turmas/{codigoUe}/{modalidade}/{bimestre}/{codigoTurma}/{anoLetivo}/{qtdeRegistros}/{qtdeRegistrosIgnorados}/listagem-turmas"; + var url = + $@"turmas/{codigoUe}/{modalidade}/{bimestre}/{codigoTurma}/{anoLetivo}/{qtdeRegistros}/{qtdeRegistrosIgnorados}/listagem-turmas"; var resposta = await httpClient.GetAsync(url); @@ -1076,10 +1197,12 @@ public async Task>(json); + return JsonConvert + .DeserializeObject>(json); } - public async Task> ObterProfessoresTitularesPorUe(string ueCodigo, DateTime dataReferencia) + public async Task> ObterProfessoresTitularesPorUe(string ueCodigo, + DateTime dataReferencia) { var url = $"professores/titulares/ue/{ueCodigo}/{dataReferencia.ToString("yyyy-MM-dd")}"; var resposta = await httpClient.GetAsync(url); @@ -1124,16 +1247,18 @@ public async Task ObtenhaAutenticacaoSemSenha(string logi return JsonConvert.DeserializeObject(json); } - public async Task> ObterUsuarioFuncionario(Guid perfil, FiltroFuncionarioDto filtroFuncionariosDto) + public async Task> ObterUsuarioFuncionario(Guid perfil, + FiltroFuncionarioDto filtroFuncionariosDto) { - var resposta = await httpClient.GetAsync($@"funcionarios/perfis/{perfil}?CodigoDre={filtroFuncionariosDto.CodigoDRE}&CodigoUe={filtroFuncionariosDto.CodigoUE}&CodigoRf={filtroFuncionariosDto.CodigoRF}&NomeServidor={filtroFuncionariosDto.NomeServidor}"); + var resposta = await httpClient.GetAsync( + $@"funcionarios/perfis/{perfil}?CodigoDre={filtroFuncionariosDto.CodigoDRE}&CodigoUe={filtroFuncionariosDto.CodigoUE}&CodigoRf={filtroFuncionariosDto.CodigoRF}&NomeServidor={filtroFuncionariosDto.NomeServidor}"); if (resposta.IsSuccessStatusCode) { var json = await resposta.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject>(json); - } + return Enumerable.Empty(); } } diff --git a/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs.rej b/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs.rej new file mode 100644 index 0000000000..419c992e60 --- /dev/null +++ b/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs.rej @@ -0,0 +1,48 @@ +diff a/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs b/src/SME.SGP.Aplicacao/Integracoes/ServicoEOL.cs (rejected hunks) +@@ -258,23 +286,29 @@ namespace SME.SGP.Aplicacao.Integracoes + return await mediator.Send(new ObterComponentesCurricularesEolPorCodigoTurmaLoginEPerfilQuery(codigoTurma, login, perfil, realizarAgrupamentoComponente, checaMotivoDisponibilizacao)); + } + +- public async Task> ObterComponentesCurricularesPorLoginEIdPerfil(string login, Guid idPerfil) ++ public async Task> ObterComponentesCurricularesPorLoginEIdPerfil( ++ string login, Guid idPerfil) + { + var url = $"v1/componentes-curriculares/funcionarios/{login}/perfis/{idPerfil}"; + return await ObterComponentesCurriculares(url); + } + +- public async Task> ObterComponentesCurricularesPorCodigoTurmaLoginEPerfilParaPlanejamento(string codigoTurma, string login, Guid perfil) ++ public async Task> ++ ObterComponentesCurricularesPorCodigoTurmaLoginEPerfilParaPlanejamento(string codigoTurma, string login, ++ Guid perfil) + { +- var url = $"v1/componentes-curriculares/turmas/{codigoTurma}/funcionarios/{login}/perfis/{perfil}/planejamento"; ++ var url = ++ $"v1/componentes-curriculares/turmas/{codigoTurma}/funcionarios/{login}/perfis/{perfil}/planejamento"; + return await ObterComponentesCurriculares(url); + } + +- public async Task> ObterDadosAluno(string codigoAluno, int anoLetivo, bool consideraHistorico, bool filtrarSituacao = true) ++ public async Task> ObterDadosAluno(string codigoAluno, int anoLetivo, ++ bool consideraHistorico, bool filtrarSituacao = true) + { + var alunos = new List(); + +- var resposta = await httpClient.GetAsync($"alunos/{codigoAluno}/turmas/anosLetivos/{anoLetivo}/historico/{consideraHistorico}/filtrar-situacao/{filtrarSituacao}"); ++ var resposta = await httpClient.GetAsync( ++ $"alunos/{codigoAluno}/turmas/anosLetivos/{anoLetivo}/historico/{consideraHistorico}/filtrar-situacao/{filtrarSituacao}"); + if (resposta.IsSuccessStatusCode) + { + var json = await resposta.Content.ReadAsStringAsync(); +@@ -845,7 +948,10 @@ namespace SME.SGP.Aplicacao.Integracoes + { + return disciplinas.Select(x => new DisciplinaDto + { +- CodigoComponenteCurricular = !x.Territorio? x.CdComponenteCurricular : long.Parse(x.CdComponenteCurricular.ToString().Substring(x.CdComponenteCurricular.ToString().Length - 4)), ++ CodigoComponenteCurricular = !x.Territorio ++ ? x.CdComponenteCurricular ++ : long.Parse(x.CdComponenteCurricular.ToString() ++ .Substring(x.CdComponenteCurricular.ToString().Length - 4)), + Nome = x.Descricao, + Regencia = x.EhRegencia, + Compartilhada = x.EhCompartilhada, diff --git a/src/SME.SGP.Aplicacao/Interfaces/Comandos/IComandosUsuario.cs.rej b/src/SME.SGP.Aplicacao/Interfaces/Comandos/IComandosUsuario.cs.rej new file mode 100644 index 0000000000..fa7d8867ac --- /dev/null +++ b/src/SME.SGP.Aplicacao/Interfaces/Comandos/IComandosUsuario.cs.rej @@ -0,0 +1,14 @@ +diff a/src/SME.SGP.Aplicacao/Interfaces/Comandos/IComandosUsuario.cs b/src/SME.SGP.Aplicacao/Interfaces/Comandos/IComandosUsuario.cs (rejected hunks) +@@ -33,8 +33,10 @@ namespace SME.SGP.Aplicacao + + Task AutenticarSuporte(string login); + ++ //sugestao de nomear tuplas se for manter ou trocar para records ou tipos de estrutura mais flexiveis ++ //que encapsulem o retorno + Task ObterAutenticacao( +- (UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool) retornoAutenticacaoEol, ++ (UsuarioAutenticacaoRetornoDto UsuarioAutenticacaoRetornoDto, string CodigoRf, IEnumerable Perfis, bool PossuiCargoCJ, bool PossuiPerfilCJ) retornoAutenticacaoEol, + string login, AdministradorSuporteDto administradorSuporte = null); + } + } +\ No newline at end of file diff --git a/src/SME.SGP.Aplicacao/Interfaces/Integracoes/IServicoEOL.cs b/src/SME.SGP.Aplicacao/Interfaces/Integracoes/IServicoEOL.cs index a764e6c877..f0f1e6c717 100644 --- a/src/SME.SGP.Aplicacao/Interfaces/Integracoes/IServicoEOL.cs +++ b/src/SME.SGP.Aplicacao/Interfaces/Integracoes/IServicoEOL.cs @@ -21,7 +21,7 @@ public interface IServicoEol Task AtribuirPerfil(string codigoRf, Guid perfil); - Task Autenticar(string login, string senha); + Task Autenticar(string login, string senha); IEnumerable BuscarCiclos(); @@ -78,7 +78,7 @@ public interface IServicoEol Task ObterPerfisPorLogin(string login); - Task CarregarDadosAcessoPorLoginPerfil(string login, Guid perfilGuid, AdministradorSuporteDto administradorSuporte = null); + Task CarregarDadosAcessoPorLoginPerfil(string login, Guid perfilGuid, AdministradorSuporteDto administradorSuporte = null); Task> ObterProfessoresAutoComplete(int anoLetivo, string dreId, string ueId, string nomeProfessor); diff --git a/src/SME.SGP.Aplicacao/Interfaces/Servicos/IServicoAutenticacao.cs b/src/SME.SGP.Aplicacao/Interfaces/Servicos/IServicoAutenticacao.cs index 3e784f7555..735d478266 100644 --- a/src/SME.SGP.Aplicacao/Interfaces/Servicos/IServicoAutenticacao.cs +++ b/src/SME.SGP.Aplicacao/Interfaces/Servicos/IServicoAutenticacao.cs @@ -9,7 +9,9 @@ public interface IServicoAutenticacao { Task AlterarSenha(string login, string senhaAtual, string novaSenha); - Task<(UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool)> AutenticarNoEol(string login, string senha); + //sugestao de nomear tuplas se for manter ou trocar para records ou tipos de estrutura mais flexiveis + //que encapsulem o retorno + Task<(UsuarioAutenticacaoRetornoDto UsuarioAutenticacaoRetornoDto, string CodigoRf, IEnumerable Perfis, bool PossuiCargoCJ, bool PossuiPerfilCJ)> AutenticarNoEol(string login, string senha); bool TemPerfilNoToken(string guid); diff --git a/src/SME.SGP.Aplicacao/Queries/Aluno/ObterAlunosAtivosPorTurmaCodigo/ObterAlunosAtivosPorTurmaCodigoQueryHandler.cs.rej b/src/SME.SGP.Aplicacao/Queries/Aluno/ObterAlunosAtivosPorTurmaCodigo/ObterAlunosAtivosPorTurmaCodigoQueryHandler.cs.rej new file mode 100644 index 0000000000..8b86b4bc72 --- /dev/null +++ b/src/SME.SGP.Aplicacao/Queries/Aluno/ObterAlunosAtivosPorTurmaCodigo/ObterAlunosAtivosPorTurmaCodigoQueryHandler.cs.rej @@ -0,0 +1,12 @@ +diff a/src/SME.SGP.Aplicacao/Queries/Aluno/ObterAlunosAtivosPorTurmaCodigo/ObterAlunosAtivosPorTurmaCodigoQueryHandler.cs b/src/SME.SGP.Aplicacao/Queries/Aluno/ObterAlunosAtivosPorTurmaCodigo/ObterAlunosAtivosPorTurmaCodigoQueryHandler.cs (rejected hunks) +@@ -28,7 +28,9 @@ namespace SME.SGP.Aplicacao + if (!resposta.IsSuccessStatusCode) + throw new NegocioException("Não foi possível buscar alunos ativos no EOL."); + +- var json = resposta.Content.ReadAsStringAsync().Result; ++ //Outro caso por exemplo ainda mais simples de .Result que poderia ser await ja que está num metodo async ++ //Sempre passar para frente tambem cancellationTokens ++ var json = await resposta.Content.ReadAsStringAsync(cancellationToken); + return JsonConvert.DeserializeObject>(json); + } + } diff --git a/src/SME.SGP.Aplicacao/Queries/Usuario/ObterAdministradorDoSuporte/ObterAdministradorDoSuporteQuery.cs b/src/SME.SGP.Aplicacao/Queries/Usuario/ObterAdministradorDoSuporte/ObterAdministradorDoSuporteQuery.cs index b7ef1785db..90e9594512 100644 --- a/src/SME.SGP.Aplicacao/Queries/Usuario/ObterAdministradorDoSuporte/ObterAdministradorDoSuporteQuery.cs +++ b/src/SME.SGP.Aplicacao/Queries/Usuario/ObterAdministradorDoSuporte/ObterAdministradorDoSuporteQuery.cs @@ -5,5 +5,6 @@ namespace SME.SGP.Aplicacao { public class ObterAdministradorDoSuporteQuery : IRequest { + public static ObterAdministradorDoSuporteQuery Instance => new(); } } diff --git a/src/SME.SGP.Aplicacao/Queries/Usuario/ObterLoginAtual/ObterLoginAtualQuery.cs b/src/SME.SGP.Aplicacao/Queries/Usuario/ObterLoginAtual/ObterLoginAtualQuery.cs index a6902a42fb..162651574e 100644 --- a/src/SME.SGP.Aplicacao/Queries/Usuario/ObterLoginAtual/ObterLoginAtualQuery.cs +++ b/src/SME.SGP.Aplicacao/Queries/Usuario/ObterLoginAtual/ObterLoginAtualQuery.cs @@ -7,5 +7,7 @@ namespace SME.SGP.Aplicacao { public class ObterLoginAtualQuery : IRequest { + //Como tem chamadas sem parametros seria interessante disponibilizar a mesma instancia sempre para nao precisar fazer alocacao + public static ObterLoginAtualQuery Instance => new(); } } diff --git a/src/SME.SGP.Aplicacao/Queries/Usuario/ObterPerfilAtual/ObterPerfilAtualQuery.cs b/src/SME.SGP.Aplicacao/Queries/Usuario/ObterPerfilAtual/ObterPerfilAtualQuery.cs index ab08c4e9e6..7368ec4793 100644 --- a/src/SME.SGP.Aplicacao/Queries/Usuario/ObterPerfilAtual/ObterPerfilAtualQuery.cs +++ b/src/SME.SGP.Aplicacao/Queries/Usuario/ObterPerfilAtual/ObterPerfilAtualQuery.cs @@ -7,5 +7,7 @@ namespace SME.SGP.Aplicacao { public class ObterPerfilAtualQuery : IRequest { + //Como tem chamadas sem parametros seria interessante disponibilizar a mesma instancia sempre para nao precisar fazer alocacao + public static ObterPerfilAtualQuery Instance => new(); } } diff --git a/src/SME.SGP.Aplicacao/SME.SGP.Aplicacao.csproj b/src/SME.SGP.Aplicacao/SME.SGP.Aplicacao.csproj index cfe14ef582..3d4aa425f1 100644 --- a/src/SME.SGP.Aplicacao/SME.SGP.Aplicacao.csproj +++ b/src/SME.SGP.Aplicacao/SME.SGP.Aplicacao.csproj @@ -4,6 +4,7 @@ net5.0 latest 874d00b9-29fa-4e52-be2b-2ea73c09535a + false diff --git a/src/SME.SGP.Aplicacao/Servicos/ServicoAbrangencia.cs b/src/SME.SGP.Aplicacao/Servicos/ServicoAbrangencia.cs index b61fd7008c..fc9168ab8f 100644 --- a/src/SME.SGP.Aplicacao/Servicos/ServicoAbrangencia.cs +++ b/src/SME.SGP.Aplicacao/Servicos/ServicoAbrangencia.cs @@ -59,14 +59,14 @@ public void RemoverAbrangencias(long[] ids) repositorioAbrangencia.ExcluirAbrangencias(ids); } - public void RemoverAbrangenciasHistoricas(long[] ids) + public async Task RemoverAbrangenciasHistoricas(long[] ids) { - repositorioAbrangencia.ExcluirAbrangenciasHistoricas(ids); + await repositorioAbrangencia.ExcluirAbrangenciasHistoricas(ids); } - public void RemoverAbrangenciasHistoricasIncorretas(string login, List perfis) + public async Task RemoverAbrangenciasHistoricasIncorretas(string login, List perfis) { - var abrangenciasHistorica = ObterAbrangenciaHistorica(login).Result; + var abrangenciasHistorica = await ObterAbrangenciaHistorica(login); long[] idsRemover = abrangenciasHistorica .Where(a => a.perfil != Perfis.PERFIL_PAEE && a.perfil != Perfis.PERFIL_PAP @@ -80,7 +80,7 @@ public void RemoverAbrangenciasHistoricasIncorretas(string login, List per ).Select(a => a.Id).ToArray(); if (idsRemover.Any()) - RemoverAbrangenciasHistoricas(idsRemover); + await RemoverAbrangenciasHistoricas(idsRemover); } public async Task> ObterAbrangenciaHistorica(string login) @@ -91,8 +91,13 @@ public async Task> ObterAbrangenciaHistoric public async Task Salvar(string login, Guid perfil, bool ehLogin) { if (ehLogin) + { await TrataAbrangenciaLogin(login, perfil); - else await TrataAbrangenciaModificaoPerfil(login, perfil); + } + else + { + await TrataAbrangenciaModificaoPerfil(login, perfil); + } } public void SalvarAbrangencias(IEnumerable abrangencias, string login) @@ -295,11 +300,13 @@ private async Task BuscaAbrangenciaEPersiste(string login, Guid perfil) turmas = estrutura.Item3; // sincronizamos a abrangencia do login + perfil - unitOfWork.IniciarTransacao(); + await unitOfWork.IniciarTransacaoAsync(); SincronizarAbrangencia(abrangenciaSintetica, abrangenciaEol.Abrangencia?.Abrangencia, ehSupervisor, dres, ues, turmas, login, perfil); - unitOfWork.PersistirTransacao(); + await unitOfWork.PersistirTransacaoAsync(); + + //nao tem rollback essa logica ? } } } diff --git a/src/SME.SGP.Aplicacao/Servicos/ServicoAutenticacao.cs b/src/SME.SGP.Aplicacao/Servicos/ServicoAutenticacao.cs index 138dea6fbf..5e066ac1ab 100644 --- a/src/SME.SGP.Aplicacao/Servicos/ServicoAutenticacao.cs +++ b/src/SME.SGP.Aplicacao/Servicos/ServicoAutenticacao.cs @@ -20,7 +20,7 @@ public ServicoAutenticacao(IServicoEol servicoEOL) public async Task AlterarSenha(string login, string senhaAtual, string novaSenha) { var autenticacao = await servicoEOL.Autenticar(login, senhaAtual); - if (autenticacao == null || autenticacao.Status != AutenticacaoStatusEol.Ok) + if (autenticacao is null || autenticacao.Status != AutenticacaoStatusEol.Ok) { throw new NegocioException("Senha atual incorreta.", HttpStatusCode.Unauthorized); } @@ -32,37 +32,42 @@ public async Task AlterarSenha(string login, string senhaAtual, string novaSenha } } - public async Task<(UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool)> AutenticarNoEol(string login, string senha) + public async Task<(UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool)> AutenticarNoEol( + string login, string senha) { var retornoServicoEol = await servicoEOL.Autenticar(login, senha); return await ObterAutenticacao(retornoServicoEol); } - public async Task<(UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool)> AutenticarNoEolSemSenha(string login) + public async Task<(UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool)> + AutenticarNoEolSemSenha(string login) { var retornoServicoEol = await servicoEOL.ObtenhaAutenticacaoSemSenha(login); return await ObterAutenticacao(retornoServicoEol); } - private async Task<(UsuarioAutenticacaoRetornoDto, string, IEnumerable, bool, bool)> ObterAutenticacao(AutenticacaoApiEolDto retornoServicoEol) + private async Task<(UsuarioAutenticacaoRetornoDto UsuarioAutenticacaoRetornoDto, string CodigoRf, IEnumerable Perfis, bool PossuiCargoCJ, bool PossuiPerfilCJ)> ObterAutenticacao( + AutenticacaoApiEolDto? retornoServicoEol) { var retornoDto = new UsuarioAutenticacaoRetornoDto(); - if (retornoServicoEol == null) + if (retornoServicoEol is null) + { return (retornoDto, "", null, false, false); - + } + retornoDto.Autenticado = retornoServicoEol.Status is AutenticacaoStatusEol.Ok or AutenticacaoStatusEol.SenhaPadrao; retornoDto.ModificarSenha = retornoServicoEol.Status == AutenticacaoStatusEol.SenhaPadrao; retornoDto.UsuarioId = retornoServicoEol.UsuarioId; var perfis = await servicoEOL.ObterPerfisPorLogin(retornoServicoEol.CodigoRf); - - if (perfis == null) + if (perfis is null) throw new NegocioException("Usuário sem perfis de acesso."); - return (retornoDto, retornoServicoEol.CodigoRf, perfis.Perfis, perfis.PossuiCargoCJ, perfis.PossuiPerfilCJ); + return (retornoDto, retornoServicoEol.CodigoRf, perfis.Perfis, perfis.PossuiCargoCJ, + perfis.PossuiPerfilCJ); } public bool TemPerfilNoToken(string guid) diff --git a/src/SME.SGP.Aplicacao/Workers/WorkerRabbitMQBase.cs b/src/SME.SGP.Aplicacao/Workers/WorkerRabbitMQBase.cs index 7748700db6..96b596d41b 100644 --- a/src/SME.SGP.Aplicacao/Workers/WorkerRabbitMQBase.cs +++ b/src/SME.SGP.Aplicacao/Workers/WorkerRabbitMQBase.cs @@ -21,6 +21,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using SME.SGP.Dados.Contexto; namespace SME.SGP.Aplicacao.Workers { @@ -179,15 +180,18 @@ public async Task TratarMensagem(BasicDeliverEventArgs ea) var comandoRabbit = Comandos[rota]; var transacao = telemetriaOptions.Apm ? Agent.Tracer.StartTransaction(rota, apmTransactionType) : null; + using var scope = serviceScopeFactory.CreateScope(); + + await using var sgpContext = scope.ServiceProvider.GetRequiredService(); + await sgpContext.OpenAsync(); try { - using var scope = serviceScopeFactory.CreateScope(); AtribuirContextoAplicacao(mensagemRabbit, scope); var casoDeUso = scope.ServiceProvider.GetService(comandoRabbit.TipoCasoUso); + //nao seria melhor seguir uma interface e refatorar para nao usar reflexao que custa caro? var metodo = UtilMethod.ObterMetodo(comandoRabbit.TipoCasoUso, "Executar"); - await servicoTelemetria.RegistrarAsync(async () => await metodo.InvokeAsync(casoDeUso, new object[] { mensagemRabbit }), "RabbitMQ", @@ -245,6 +249,7 @@ await servicoTelemetria.RegistrarAsync(async () => finally { transacao?.End(); + await sgpContext.CloseAsync(); } } else @@ -297,6 +302,7 @@ private void NotificarErroUsuario(string message, string usuarioRf, string nomeP var mensagem = JsonConvert.SerializeObject(request); var body = Encoding.UTF8.GetBytes(mensagem); + //essa mensagem não é persistente ? canalRabbit.BasicPublish(ExchangeSgpRabbit.Sgp, RotasRabbitSgp.RotaNotificacaoUsuario, null, body); } } @@ -315,6 +321,7 @@ public Task StartAsync(CancellationToken stoppingToken) catch (Exception ex) { await mediator.Send(new SalvarLogViaRabbitCommand($"Erro ao tratar mensagem {ea.DeliveryTag} - {ea.RoutingKey}", LogNivel.Critico, LogContexto.WorkerRabbit, ex.Message)); + //senao conseguir rejeitar por algum motivo a instancia do worker nao vai conseguir subir canalRabbit.BasicReject(ea.DeliveryTag, false); } }; diff --git a/src/SME.SGP.Auditoria.Worker/WorkerRabbitAuditoria.cs b/src/SME.SGP.Auditoria.Worker/WorkerRabbitAuditoria.cs index 24a0e4b4e5..e50164dfe6 100644 --- a/src/SME.SGP.Auditoria.Worker/WorkerRabbitAuditoria.cs +++ b/src/SME.SGP.Auditoria.Worker/WorkerRabbitAuditoria.cs @@ -21,10 +21,14 @@ public class WorkerRabbitAuditoria : IHostedService private readonly TelemetriaOptions telemetriaOptions; private readonly IServiceScopeFactory serviceScopeFactory; - public WorkerRabbitAuditoria(IConnectionFactory factory, IOptions telemetriaOptions, IServiceScopeFactory serviceScopeFactory) + public WorkerRabbitAuditoria(IConnectionFactory factory, IOptions telemetriaOptions, + IServiceScopeFactory serviceScopeFactory) { - this.serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory), "Service Scope Factory não localizado"); - this.telemetriaOptions = telemetriaOptions.Value ?? throw new ArgumentNullException(nameof(telemetriaOptions)); + this.serviceScopeFactory = serviceScopeFactory ?? + throw new ArgumentNullException(nameof(serviceScopeFactory), + "Service Scope Factory não localizado"); + this.telemetriaOptions = + telemetriaOptions.Value ?? throw new ArgumentNullException(nameof(telemetriaOptions)); conexaoRabbit = factory.CreateConnection(); canalRabbit = conexaoRabbit.CreateModel(); @@ -44,12 +48,14 @@ private void DeclararFilas() args.Add("x-dead-letter-exchange", RotasRabbitAuditoria.ExchangeSgpDeadLetter); canalRabbit.QueueDeclare(RotasRabbitAuditoria.PersistirAuditoriaDB, true, false, false, args); - canalRabbit.QueueBind(RotasRabbitAuditoria.PersistirAuditoriaDB, RotasRabbitAuditoria.ExchangeSgp, RotasRabbitAuditoria.PersistirAuditoriaDB, null); + canalRabbit.QueueBind(RotasRabbitAuditoria.PersistirAuditoriaDB, RotasRabbitAuditoria.ExchangeSgp, + RotasRabbitAuditoria.PersistirAuditoriaDB, null); var filaDeadLetter = $"{RotasRabbitAuditoria.PersistirAuditoriaDB}.deadletter"; canalRabbit.QueueDeclare(filaDeadLetter, true, false, false, null); - canalRabbit.QueueBind(filaDeadLetter, RotasRabbitAuditoria.ExchangeSgpDeadLetter, RotasRabbitAuditoria.PersistirAuditoriaDB, null); + canalRabbit.QueueBind(filaDeadLetter, RotasRabbitAuditoria.ExchangeSgpDeadLetter, + RotasRabbitAuditoria.PersistirAuditoriaDB, null); } public Task StartAsync(CancellationToken stoppingToken) @@ -87,38 +93,77 @@ private void RegistrarConsumerSgp(EventingBasicConsumer consumer) canalRabbit.BasicConsume(RotasRabbitAuditoria.PersistirAuditoriaDB, false, consumer); } - private Task TratarMensagem(BasicDeliverEventArgs ea) + private async Task TratarMensagem(BasicDeliverEventArgs basicDeliverEventArgs) { - var mensagem = Encoding.UTF8.GetString(ea.Body.Span); - var rota = ea.RoutingKey; - var mensagemRabbit = JsonConvert.DeserializeObject(mensagem); - var transacao = telemetriaOptions.Apm ? Agent.Tracer.StartTransaction(rota, "WorkerRabbitAuditoria") : null; - try + Func fnTaskAuditoria = async (basicDeliverEventArg) => { using var scope = serviceScopeFactory.CreateScope(); - var registrarAuditoriaUseCase = scope.ServiceProvider.GetService(); - if (telemetriaOptions.Apm) - transacao.CaptureSpan("RegistrarAuditoriaDB", "RabbitMQ", () => - registrarAuditoriaUseCase.Executar(mensagemRabbit)).Wait(); - else - registrarAuditoriaUseCase.Executar(mensagemRabbit).Wait(); + var mensagem = Encoding.UTF8.GetString(basicDeliverEventArgs.Body.Span); + var mensagemRabbit = JsonConvert.DeserializeObject(mensagem); - canalRabbit.BasicAck(ea.DeliveryTag, false); - } - catch (Exception ex) + var registrarAuditoriaUseCase = scope.ServiceProvider.GetService()!; + await registrarAuditoriaUseCase.Executar(mensagemRabbit); + + var deliveryTag = basicDeliverEventArg.DeliveryTag; + canalRabbit.BasicAck(deliveryTag, false); + + //tem que pensar no caso de como fica caso a auditoria tenha sido enviada para o elastic + //e o rabbit nao conseguiu confirmar o recebimento da mensagem + //talvez alguma estrategia de idempotencia para verificar se a mensagem ja foi auditada anteriormente + //caso aconteca um reenfileiramento + }; + + Action fnTaskAuditoriaException = (basicDeliverEventArg, _) => { - transacao?.CaptureException(ex); + var deliveryTag = basicDeliverEventArg.DeliveryTag; + canalRabbit.BasicReject(deliveryTag, false); + }; - canalRabbit.BasicReject(ea.DeliveryTag, false); - } - finally + ///talvez encapsular e execucao do apm para algo mais generico sem boilerplate (method around) + var rota = basicDeliverEventArgs.RoutingKey; + await Apm.RunConditionalityWithSingleTransactionSpanAsync(telemetriaOptions.Apm, rota, + "WorkerRabbitAuditoria", "RegistrarAuditoriaDB", "RabbitMQ", + basicDeliverEventArgs, fnTaskAuditoria, fnTaskAuditoriaException); + } + + + //talvez mover para alguma classe publica caso precise utilizar o apm novamente. + private sealed class Apm + { + public static async Task RunConditionalityWithSingleTransactionSpanAsync(bool useApm, string transactionName, + string transactionType, string spanName, string spanType, T1 t1, Func handler, + Action exceptionHandler) { - transacao?.End(); + if (useApm) + { + var transaction = Agent.Tracer.StartTransaction(transactionName, transactionType); + try + { + await transaction.CaptureSpan(spanName, spanType, async () => await handler(t1)); + } + catch (Exception ex) + { + exceptionHandler(t1, ex); + } + finally + { + transaction.End(); + } + } + else + { + try + { + await handler(t1); + } + catch (Exception ex) + { + exceptionHandler(t1, ex); + } + } } - - return Task.CompletedTask; } } } \ No newline at end of file diff --git a/src/SME.SGP.Dados.Cache/RepositorioCache.cs.rej b/src/SME.SGP.Dados.Cache/RepositorioCache.cs.rej new file mode 100644 index 0000000000..e9abeb5563 --- /dev/null +++ b/src/SME.SGP.Dados.Cache/RepositorioCache.cs.rej @@ -0,0 +1,42 @@ +diff a/src/SME.SGP.Dados.Cache/RepositorioCache.cs b/src/SME.SGP.Dados.Cache/RepositorioCache.cs (rejected hunks) +@@ -140,15 +140,10 @@ namespace SME.SGP.Dados.Repositorios + NomeChave = nomeChave + }; + +- try +- { ++ + await servicoTelemetria.RegistrarAsync(async () => await RemoverValor(nomeChave), + NomeServicoCache, $"{NomeServicoCache} Remover async", "", param.ToString()); +- } +- catch (Exception) +- { +- throw; +- } ++ //new precisaria capturar para relancar + } + + public async Task SalvarAsync(string nomeChave, string valor, int minutosParaExpirar = 720, bool utilizarGZip = false) +@@ -160,8 +155,7 @@ namespace SME.SGP.Dados.Repositorios + UtilizarGZip = utilizarGZip + }; + +- try +- { ++ + if (!string.IsNullOrWhiteSpace(valor) && valor != "[]") + { + if (utilizarGZip) +@@ -173,11 +167,7 @@ namespace SME.SGP.Dados.Repositorios + await servicoTelemetria.RegistrarAsync(async () => await SalvarValor(nomeChave, valor, minutosParaExpirar), + NomeServicoCache, $"{NomeServicoCache} Salvar async", "", param.ToString()); + } +- } +- catch (Exception) +- { +- throw; +- } ++ //new precisaria capturar para relancar + } + + public async Task SalvarAsync(string nomeChave, object valor, int minutosParaExpirar = 720, bool utilizarGZip = false) diff --git a/src/SME.SGP.Dados.ElasticSearch/RepositorioElasticBase.cs b/src/SME.SGP.Dados.ElasticSearch/RepositorioElasticBase.cs index 4866cc7f41..ee117edadd 100644 --- a/src/SME.SGP.Dados.ElasticSearch/RepositorioElasticBase.cs +++ b/src/SME.SGP.Dados.ElasticSearch/RepositorioElasticBase.cs @@ -19,8 +19,8 @@ public abstract class RepositorioElasticBase : IRepositorioElasticBas private readonly ElasticOptions elasticOptions; protected RepositorioElasticBase(IElasticClient elasticClient, - IServicoTelemetria servicoTelemetria, - IOptions elasticOptions) + IServicoTelemetria servicoTelemetria, + IOptions elasticOptions) { _elasticClient = elasticClient; this.servicoTelemetria = servicoTelemetria; @@ -29,12 +29,12 @@ protected RepositorioElasticBase(IElasticClient elasticClient, public async Task ExisteAsync(string indice, string id, string nomeConsulta, object parametro = null) { - ExistsResponse response = await servicoTelemetria.RegistrarComRetornoAsync(async () => - await _elasticClient.DocumentExistsAsync(DocumentPath.Id(id).Index(indice)), - "Elastic", - nomeConsulta, - indice, - parametro?.ToString()); + ExistsResponse response = await servicoTelemetria.RegistrarComRetornoAsync(async () => + await _elasticClient.DocumentExistsAsync(DocumentPath.Id(id).Index(indice)), + "Elastic", + nomeConsulta, + indice, + parametro?.ToString()); if (!response.IsValid) throw new Exception(response.ServerError?.ToString(), response.OriginalException); @@ -44,12 +44,13 @@ await _elasticClient.DocumentExistsAsync(DocumentPath.Id(id).Index(in public async Task ObterAsync(string indice, string id, string nomeConsulta, object parametro = null) { - GetResponse response = await servicoTelemetria.RegistrarComRetornoAsync>(async () => - await _elasticClient.GetAsync(DocumentPath.Id(id).Index(indice)), - "Elastic", - nomeConsulta, - indice, - parametro?.ToString()); + GetResponse response = await servicoTelemetria.RegistrarComRetornoAsync>( + async () => + await _elasticClient.GetAsync(DocumentPath.Id(id).Index(indice)), + "Elastic", + nomeConsulta, + indice, + parametro?.ToString()); if (response.IsValid) return response.Source; @@ -57,31 +58,36 @@ await _elasticClient.GetAsync(DocumentPath.Id(id).Index(indice)), return null; } - public async Task> ObterListaAsync(string indice, IEnumerable ids, string nomeConsulta, object parametro = null) + public async Task> ObterListaAsync(string indice, IEnumerable ids, + string nomeConsulta, object parametro = null) { - IEnumerable> response = await servicoTelemetria.RegistrarComRetornoAsync>>(async () => - await _elasticClient.GetManyAsync(ids, indice), - "Elastic", - nomeConsulta, - indice, - parametro?.ToString()); + IEnumerable> response = + await servicoTelemetria.RegistrarComRetornoAsync>>(async () => + await _elasticClient.GetManyAsync(ids, indice), + "Elastic", + nomeConsulta, + indice, + parametro?.ToString()); return response.Select(item => item.Source).ToList(); } - public async Task> ObterListaAsync(string indice, Func, QueryContainer> request, string nomeConsulta, object parametro = null) + public async Task> ObterListaAsync(string indice, + Func, QueryContainer> request, string nomeConsulta, + object parametro = null) { var listaDeRetorno = ObtenhaInstancia(); - ISearchResponse response = await servicoTelemetria.RegistrarComRetornoAsync>(async () => - await _elasticClient.SearchAsync(s => s.Index(indice) - .Query(request) - .Scroll("10s") - .Size(QUANTIDADE_RETORNO)), - "Elastic", - nomeConsulta, - indice, - parametro?.ToString()); + ISearchResponse response = + await servicoTelemetria.RegistrarComRetornoAsync>(async () => + await _elasticClient.SearchAsync(s => s.Index(indice) + .Query(request) + .Scroll("10s") + .Size(QUANTIDADE_RETORNO)), + "Elastic", + nomeConsulta, + indice, + parametro?.ToString()); if (!response.IsValid) throw new Exception(response.ServerError?.ToString(), response.OriginalException); @@ -90,12 +96,12 @@ await _elasticClient.SearchAsync(s => s.Index(indice) while (response.Documents.Any() && response.Documents.Count == QUANTIDADE_RETORNO) { - response = await servicoTelemetria.RegistrarComRetornoAsync>(async () => - await _elasticClient.ScrollAsync ("10s", response.ScrollId), - "Elastic", - nomeConsulta + " scroll", - indice, - parametro?.ToString()); + response = await servicoTelemetria.RegistrarComRetornoAsync>(async () => + await _elasticClient.ScrollAsync("10s", response.ScrollId), + "Elastic", + nomeConsulta + " scroll", + indice, + parametro?.ToString()); listaDeRetorno.AddRange(response.Documents); } @@ -104,15 +110,17 @@ await _elasticClient.SearchAsync(s => s.Index(indice) return listaDeRetorno; } - public async Task> ObterTodosAsync(string indice, string nomeConsulta, object parametro = null) + public async Task> ObterTodosAsync(string indice, string nomeConsulta, + object parametro = null) { var search = new SearchDescriptor(indice).MatchAll(); - ISearchResponse response = await servicoTelemetria.RegistrarComRetornoAsync>(async () => - await _elasticClient.SearchAsync(search), - "Elastic", - nomeConsulta, - indice, - parametro?.ToString()); + ISearchResponse response = + await servicoTelemetria.RegistrarComRetornoAsync>(async () => + await _elasticClient.SearchAsync(search), + "Elastic", + nomeConsulta, + indice, + parametro?.ToString()); if (!response.IsValid) throw new Exception(response.ServerError?.ToString(), response.OriginalException); @@ -123,12 +131,13 @@ await _elasticClient.SearchAsync(search), public async Task ObterTotalDeRegistroAsync(string indice, string nomeConsulta, object parametro = null) { var search = new SearchDescriptor(indice).MatchAll(); - ISearchResponse response = await servicoTelemetria.RegistrarComRetornoAsync>(async () => - await _elasticClient.SearchAsync(search), - "Elastic", - nomeConsulta, - indice, - parametro?.ToString()); + ISearchResponse response = + await servicoTelemetria.RegistrarComRetornoAsync>(async () => + await _elasticClient.SearchAsync(search), + "Elastic", + nomeConsulta, + indice, + parametro?.ToString()); if (!response.IsValid) throw new Exception(response.ServerError?.ToString(), response.OriginalException); @@ -142,8 +151,9 @@ public virtual async Task InserirAsync(TEntidade entidade, string indice = if (!string.IsNullOrEmpty(nomeIndice)) { - var response = await servicoTelemetria.RegistrarComRetornoAsync>(async () => - await _elasticClient.IndexAsync(entidade, descriptor => descriptor.Index(nomeIndice)), + //esses tipos nao sao compativeis, como removeu dynamic pode remover que ele vai fazer inferencia para IndexResponse + var response = await servicoTelemetria.RegistrarComRetornoAsync(async () => + await _elasticClient.IndexAsync(entidade, descriptor => descriptor.Index(nomeIndice)), "Elastic", $"Insert {entidade.GetType().Name}", nomeIndice, @@ -158,9 +168,7 @@ await _elasticClient.IndexAsync(entidade, descriptor => descriptor.Index(nomeInd private string ObterNomeIndice(string indice = "") { - var nomeIndice = string.IsNullOrEmpty(indice) ? - elasticOptions.IndicePadrao : - indice; + var nomeIndice = string.IsNullOrEmpty(indice) ? elasticOptions.IndicePadrao : indice; return $"{elasticOptions.Prefixo}{nomeIndice}"; } @@ -170,7 +178,7 @@ private List ObtenhaInstancia() Type tipoGenerico = typeof(List<>); Type construtor = tipoGenerico.MakeGenericType(typeof(TEntidade)); - return (List)Activator.CreateInstance(construtor); + return (List) Activator.CreateInstance(construtor); } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Dados/Contexto/SgpContext.cs b/src/SME.SGP.Dados/Contexto/SgpContext.cs index c8fd572239..5bc7165dfb 100644 --- a/src/SME.SGP.Dados/Contexto/SgpContext.cs +++ b/src/SME.SGP.Dados/Contexto/SgpContext.cs @@ -4,115 +4,135 @@ using SME.SGP.Infra.Interfaces; using System; using System.Data; +using System.Data.Common; +using System.Threading.Tasks; namespace SME.SGP.Dados.Contexto { public class SgpContext : ISgpContext { - private readonly IDbConnection conexao; //Raphael - Trocado classe concreta de PgConnection pra IDbConnection + private readonly NpgsqlConnection conexao; private readonly IContextoAplicacao contextoAplicacao; - public SgpContext(IConfiguration configuration, IContextoAplicacao contextoAplicacao, string stringConexao = "SGP_Postgres") + public SgpContext(IConfiguration configuration, IContextoAplicacao contextoAplicacao, + string stringConexao = "SGP_Postgres") { - conexao = new NpgsqlConnection(configuration.GetConnectionString(stringConexao)); + //o NpgsqlConnection tem suporte a async, dava pra tirar vantagem disso + //ao trocar para interface deixa mais extensivel e testavel porem do jeito que esta hoje perde as vantagens + //que a implementacao do NpgsqlConnection oferece. + //Uma opcao seria complementar o ISGPContext com metodos async + //e tirar proveito nos casos de chamada que suportem async/await + var connectionString = configuration.GetConnectionString(stringConexao); + this.conexao = new NpgsqlConnection(connectionString); this.contextoAplicacao = contextoAplicacao ?? throw new ArgumentNullException(nameof(contextoAplicacao)); - Open(); + //Pelo profile boa parte do tempo esta sendo de espera de abertura de conexao e wait de thread + //em escala abrindo desse jeito sync o throughput da aplicacao tende a diminuir + //talvez mover a abertura para o comeco do request no filter } - //Ctor para ser usado com o teste. public SgpContext(IDbConnection conexao, IContextoAplicacao contextoAplicacao) { - this.conexao = conexao; + this.conexao = conexao as NpgsqlConnection; this.contextoAplicacao = contextoAplicacao; } - public IDbConnection Conexao + public IDbConnection Conexao => conexao; + + public string ConnectionString { - get - { - //if (conexao.State != ConnectionState.Open) - // Open(); - return conexao; - } + get => conexao.ConnectionString; + set => conexao.ConnectionString = value; } - public string ConnectionString { get { return Conexao.ConnectionString; } set { Conexao.ConnectionString = value; } } + public int ConnectionTimeout => conexao.ConnectionTimeout; - public int ConnectionTimeout => Conexao.ConnectionTimeout; + public string Database => conexao.Database; - public string Database => Conexao.Database; - - public ConnectionState State => Conexao.State; - - public string UsuarioLogado => - contextoAplicacao.UsuarioLogado; + public ConnectionState State => conexao.State; public string UsuarioLogadoNomeCompleto => - contextoAplicacao.NomeUsuario; + contextoAplicacao.NomeUsuario; + public string PerfilUsuario => contextoAplicacao.PerfilUsuario; public string UsuarioLogadoRF => - contextoAplicacao.ObterVariavel("RF") ?? "0"; + contextoAplicacao.ObterVariavel("RF") ?? "0"; public string Administrador => contextoAplicacao.Administrador; - public IDbTransaction BeginTransaction() + public async Task OpenAsync() { - if (conexao.State == ConnectionState.Closed) - conexao.Open(); + if (IsNotOpened) + { + await conexao.OpenAsync(); + } + } - return conexao.BeginTransaction(); + public async Task CloseAsync() + { + if (IsNotClosed) + { + await conexao.CloseAsync(); + } } - public IDbTransaction BeginTransaction(IsolationLevel il) + public async Task BeginTransactionAsync() { - return conexao.BeginTransaction(il); + await OpenAsync(); + return await conexao.BeginTransactionAsync(); } - public void ChangeDatabase(string databaseName) + public IDbTransaction BeginTransaction() { - throw new NotImplementedException(); + Open(); + return conexao.BeginTransaction(); } - public void Close() + public IDbTransaction BeginTransaction(IsolationLevel il) { - conexao.Close(); + return conexao.BeginTransaction(il); } - public IDbCommand CreateCommand() + public void ChangeDatabase(string databaseName) { - return conexao.CreateCommand(); + conexao.ChangeDatabase(databaseName); } - protected virtual void Dispose(bool disposing) + public void Open() { - if (conexao.State == ConnectionState.Open) - conexao.Close(); + if (IsNotOpened) + { + conexao.Open(); + } } - public void Dispose() + public void Close() { - Dispose(true); - GC.SuppressFinalize(this); + if (IsNotClosed) + { + conexao.Close(); + } } - public void Open() + private bool IsNotOpened => conexao.State is not ConnectionState.Open; + + private bool IsNotClosed => conexao.State is not ConnectionState.Closed; + + public IDbCommand CreateCommand() { - if (conexao.State != ConnectionState.Open) - conexao.Open(); + return conexao.CreateCommand(); } - public void AbrirConexao() + public void Dispose() { - Open(); + Close(); + GC.SuppressFinalize(this); } - public void FecharConexao() + public async ValueTask DisposeAsync() { - if (conexao.State != ConnectionState.Closed) - { - Close(); - } + await conexao.CloseAsync(); + await conexao.DisposeAsync(); } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Dados/Contexto/SgpContextConsultas.cs b/src/SME.SGP.Dados/Contexto/SgpContextConsultas.cs index 4f7abfb25f..168fa12d4d 100644 --- a/src/SME.SGP.Dados/Contexto/SgpContextConsultas.cs +++ b/src/SME.SGP.Dados/Contexto/SgpContextConsultas.cs @@ -11,7 +11,7 @@ public SgpContextConsultas(IConfiguration configuration, IContextoAplicacao cont { } - public SgpContextConsultas(IDbConnection conexao, IContextoAplicacao contextoAplicacao): base(conexao, contextoAplicacao) //Raphael. Coloquei esse construtor que é usado em teste. + public SgpContextConsultas(IDbConnection conexao, IContextoAplicacao contextoAplicacao): base(conexao, contextoAplicacao) { } diff --git a/src/SME.SGP.Dados/Interceptors/DapperInterceptor.cs b/src/SME.SGP.Dados/Interceptors/DapperInterceptor.cs index 2c61aa2afe..4a990e4340 100644 --- a/src/SME.SGP.Dados/Interceptors/DapperInterceptor.cs +++ b/src/SME.SGP.Dados/Interceptors/DapperInterceptor.cs @@ -6,229 +6,276 @@ using System.Data; using System.Threading.Tasks; +//namespace => SME.SGP.Dados.Interceptors namespace SME.SGP.Dados { - public static class DapperExtensionMethods { private static IServicoTelemetria servicoTelemetria; public static void Init(IServicoTelemetria servicoTelemetriaSgp) { + //o ideal seria o servico de telemetria vir por parametro nos metodos + //pela natureza estatica de methods extension complica a vida de se trabalhar com DI + //talvez o que ajude para evitar a chamada de services.BuildServiceProvider seja criar um metodo estatico que receba o service provider e nos metodos de chamada + //use o provedor para montar a interface de telemetria, como iserviceprovider é uma interface daria pra mockar tranquilo em outros casos servicoTelemetria = servicoTelemetriaSgp; } - public static IEnumerable Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, string queryName = "query") - { - - throw new NotImplementedException("Telemtria não implementada para esta função;"); - - //var result = servicoTelemetria.RegistrarAsync( async () => await Task.FromResult(SqlMapper.Query(cnn, sql, param, transaction, buffered, commandTimeout, commandType)), "Postgres", "Query", sql); - - - //return default; - //var inicioOperacao = DateTime.UtcNow; - //var timer = System.Diagnostics.Stopwatch.StartNew(); - //IEnumerable result = default; - //try - //{ - // var transactionElk = Agent.Tracer.CurrentTransaction; - - // transactionElk.CaptureSpan("Query", "Postgres", () => - // { - // result = SqlMapper.Query(cnn, sql, param, transaction, buffered, commandTimeout, commandType); - // }); - - // timer.Stop(); - - // insightsClient?.TrackDependency("PostgreSQL", "Query", sql, inicioOperacao, timer.Elapsed, true); - // return result; - //} - //catch (Exception ex) - //{ - // insightsClient?.TrackDependency("PostgreSQL", "Query", $"{sql} -> erro: {ex.Message}", inicioOperacao, timer.Elapsed, false); - // throw ex; - //} - - } - public static IEnumerable Query(this IDbConnection Connection, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, string queryName = "") + public static IEnumerable Query(this IDbConnection cnn, string sql, object param = null, + IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, + CommandType? commandType = null, string queryName = "query") { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Query(Connection, sql, param, transaction, buffered, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - - return result; + throw new NotImplementedException("Telemetria não implementada para esta função;"); + //remover sempre codigo comentado } - public static async Task> QueryAsync(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string queryName = "") + public static IEnumerable Query(this IDbConnection Connection, string sql, object param = null, + IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, + CommandType? commandType = null, string queryName = "") { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryAsync(cnn, sql, param, transaction, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - - return result; - + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Query(Connection, sql, param, transaction, buffered, commandTimeout, commandType), + "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static async Task QueryFirstOrDefaultAsync(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + public static async Task> QueryAsync(this IDbConnection cnn, string sql, object param = null, + IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, + string queryName = "") { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryFirstOrDefaultAsync(cnn, sql, param, transaction, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - - return result; - + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryAsync(cnn, sql, param, transaction, commandTimeout, commandType), + "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") - { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - return result; - } - public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + public static async Task QueryFirstOrDefaultAsync(this IDbConnection cnn, string sql, object param = null, + IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, + string queryName = "Query Postgres") { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - - return result; + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryFirstOrDefaultAsync(cnn, sql, param, transaction, commandTimeout, + commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") - { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - return result; - } - public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + public static IEnumerable Query(this IDbConnection cnn, string sql, + Func map, object param = null, IDbTransaction transaction = null, + bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, + string queryName = "Query Postgres") { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - - return result; + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, + commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") - { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - return result; - } - public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + public static IEnumerable Query(this IDbConnection cnn, string sql, + Func map, object param = null, IDbTransaction transaction = null, + bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, + string queryName = "Query Postgres") { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - - return result; + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, + commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static async Task> QueryAsync(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") - { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - return result; - } - public static async Task> QueryAsync(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + public static IEnumerable Query(this IDbConnection cnn, + string sql, Func map, object param = null, + IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, + CommandType? commandType = null, string queryName = "Query Postgres") { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - - return result; + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, + commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static async Task> QueryAsync(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") - { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); - return result; + public static IEnumerable Query( + this IDbConnection cnn, string sql, Func map, + object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", + int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + { + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, + commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static async Task> QueryAsync(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + + public static IEnumerable Query( + this IDbConnection cnn, string sql, Func map, + object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", + int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, + commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); + } - return result; + public static IEnumerable Query( + this IDbConnection cnn, string sql, + Func map, object param = null, + IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, + CommandType? commandType = null, string queryName = "Query Postgres") + { + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Query(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, + commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static async Task> QueryAsync(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + + public static async Task> QueryAsync(this IDbConnection cnn, + string sql, Func map, object param = null, IDbTransaction transaction = null, + bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, + string queryName = "Query Postgres") { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, + commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); + } - return result; + public static async Task> QueryAsync( + this IDbConnection cnn, string sql, Func map, object param = null, + IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, + CommandType? commandType = null, string queryName = "Query Postgres") + { + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, + commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static async Task> QueryAsync(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + + public static async Task> QueryAsync( + this IDbConnection cnn, string sql, Func map, + object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", + int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") { - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, + commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); + } - return result; + public static async Task> QueryAsync( + this IDbConnection cnn, string sql, Func map, + object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", + int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + { + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, + commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static int Execute(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, string queryName = "Command Postgres") + + public static async Task> + QueryAsync(this IDbConnection cnn, string sql, + Func map, object param = null, + IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", + int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Execute(cnn, sql, param, transaction, commandTimeout, commandType), "Postgres", $"Command {queryName}", sql, param?.ToString()); + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, + commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); + } - return result; + public static async Task> + QueryAsync(this IDbConnection cnn, + string sql, Func map, + object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", + int? commandTimeout = null, CommandType? commandType = null, string queryName = "Query Postgres") + { + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await SqlMapper.QueryAsync(cnn, sql, map, param, transaction, buffered, splitOn, + commandTimeout, commandType), "Postgres", $"Query {queryName}", sql, param?.ToString()); } - public static int Execute(this IDbConnection cnn, CommandDefinition command, string queryName = "Command Postgres") + public static int Execute(this IDbConnection cnn, string sql, object param = null, + IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, + string queryName = "Command Postgres") { - var result = servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Execute(cnn, command), "Postgres", $"Command {queryName}", command.ToString()); + return servicoTelemetria.RegistrarComRetorno( + () => SqlMapper.Execute(cnn, sql, param, transaction, commandTimeout, commandType), "Postgres", + $"Command {queryName}", sql, param?.ToString()); + } - return result; + public static int Execute(this IDbConnection cnn, CommandDefinition command, + string queryName = "Command Postgres") + { + return servicoTelemetria.RegistrarComRetorno(() => SqlMapper.Execute(cnn, command), "Postgres", + $"Command {queryName}", command.ToString()); } #region Repositório Base - public static IEnumerable GetAll(this IDbConnection connection, bool buffered = true) where TEntity : class + public static IEnumerable GetAll(this IDbConnection connection, bool buffered = true) + where TEntity : class { - //Descobrir como obter a classe;; - //var entidade = this. TEntity?.GetType()?.Name; - - var result = servicoTelemetria.RegistrarComRetorno(() => Dommel.DommelMapper.GetAll(connection, buffered: buffered), "Postgres", $"GetAll Entidade ??", "GetAll"); - - return result; + return servicoTelemetria.RegistrarComRetorno( + () => Dommel.DommelMapper.GetAll(connection, buffered: buffered), "Postgres", + $"GetAll Entidade ??", "GetAll"); } - public static object Insert(this IDbConnection connection, TEntity entity, IDbTransaction transaction = null) where TEntity : class + + public static object Insert(this IDbConnection connection, TEntity entity, + IDbTransaction transaction = null) where TEntity : class { var entidade = entity?.GetType()?.Name; - - var result = servicoTelemetria.RegistrarComRetorno(() => Dommel.DommelMapper.Insert(connection, entity, transaction), "Postgres", $"Insert Entidade {entidade}", "Insert"); - - return result; + return servicoTelemetria.RegistrarComRetorno( + () => Dommel.DommelMapper.Insert(connection, entity, transaction), "Postgres", + $"Insert Entidade {entidade}", "Insert"); } - public static bool Update(this IDbConnection connection, TEntity entity, IDbTransaction transaction = null) + public static bool Update(this IDbConnection connection, TEntity entity, + IDbTransaction transaction = null) { var entidade = entity?.GetType()?.Name; - - var result = servicoTelemetria.RegistrarComRetorno(() => Dommel.DommelMapper.Update(connection, entity, transaction), "Postgres", $"Update Entidade {entidade}", "Insert"); - - return result; + return servicoTelemetria.RegistrarComRetorno( + () => Dommel.DommelMapper.Update(connection, entity, transaction), "Postgres", + $"Update Entidade {entidade}", "Insert"); } + public static TEntity Get(this IDbConnection connection, object id) where TEntity : class { - //var entidade = entity?.GetType()?.Name; - - var result = servicoTelemetria.RegistrarComRetorno(() => Dommel.DommelMapper.Get(connection, id), "Postgres", $"Get Entidade ??", "Get"); - - return result; + return servicoTelemetria.RegistrarComRetorno(() => Dommel.DommelMapper.Get(connection, id), + "Postgres", $"Get Entidade ??", "Get"); } - public static bool Delete(this IDbConnection connection, TEntity entity, IDbTransaction transaction = null, string queryName = "Command Postgres") + + public static bool Delete(this IDbConnection connection, TEntity entity, + IDbTransaction transaction = null, string queryName = "Command Postgres") { + //esse tipo de codigo pode tentar fazer boxing e alocar memoria dependendo do tipo (Struct, Class, Enum) etc var entidade = entity?.GetType()?.Name; - var result = servicoTelemetria.RegistrarComRetorno(() => Dommel.DommelMapper.Delete(connection, entity, transaction), "Postgres", $"Get Entidade {entidade}", "Get"); - - return result; + return servicoTelemetria.RegistrarComRetorno( + () => Dommel.DommelMapper.Delete(connection, entity, transaction), "Postgres", + $"Get Entidade {entidade}", "Get"); } - public static async Task GetAsync(this IDbConnection connection, object id) where TEntity : class - { - //var entidade = entity?.GetType()?.Name; - - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await Dommel.DommelMapper.GetAsync(connection, id), "Postgres", $"GetAsync Entidade ??", "GetAsync"); - return result; - - } - public static async Task UpdateAsync(this IDbConnection connection, TEntity entity, IDbTransaction transaction = null) + public static async Task GetAsync(this IDbConnection connection, object id) + where TEntity : class { - var entidade = entity?.GetType()?.Name; - - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await Dommel.DommelMapper.UpdateAsync(connection, entity, transaction), "Postgres", $"UpdateAsync Entidade {entidade}", "UpdateAsync"); + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await Dommel.DommelMapper.GetAsync(connection, id), "Postgres", + $"GetAsync Entidade ??", "GetAsync"); + } - return result; + public static async Task UpdateAsync(this IDbConnection connection, TEntity entity, + IDbTransaction transaction = null) + { + //talvez usar typeof pra saber o tipo generico da entidade sem fazer boxing e alocar memoria + var entidade = TypeOf(); + //essas chamadas de delegates vao ficar fazendo alocacao de memoria e ainda vao captura os parametros + //do metodo, nao seria melhor criar assinaturas genericas que recebem os + //parametros sem alocar uma funcao + return await servicoTelemetria.RegistrarComRetornoAsync(connection, entity, transaction, + async (c, e, t) => await Dommel.DommelMapper.UpdateAsync(c, e, t), "Postgres", + $"UpdateAsync Entidade {entidade}", "UpdateAsync"); } - public static async Task InsertAsync(this IDbConnection connection, TEntity entity, IDbTransaction transaction = null) where TEntity : class + + public static async Task InsertAsync(this IDbConnection connection, TEntity entity, + IDbTransaction transaction = null) where TEntity : class { var entidade = entity?.GetType()?.Name; + return await servicoTelemetria.RegistrarComRetornoAsync( + async () => await Dommel.DommelMapper.InsertAsync(connection, entity, transaction), "Postgres", + $"UpdateAsync Entidade {entidade}", "UpdateAsync"); + } - var result = await servicoTelemetria.RegistrarComRetornoAsync(async () => await Dommel.DommelMapper.InsertAsync(connection, entity, transaction), "Postgres", $"UpdateAsync Entidade {entidade}", "UpdateAsync"); - - return result; - + private static string TypeOf() + { + return typeof(T).Name; } + #endregion } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Dados/Repositorios/RepositorioAbrangencia.cs b/src/SME.SGP.Dados/Repositorios/RepositorioAbrangencia.cs index ca58ef64bb..d7da80fd5a 100644 --- a/src/SME.SGP.Dados/Repositorios/RepositorioAbrangencia.cs +++ b/src/SME.SGP.Dados/Repositorios/RepositorioAbrangencia.cs @@ -74,7 +74,7 @@ public void ExcluirAbrangencias(IEnumerable ids) } } - public void ExcluirAbrangenciasHistoricas(IEnumerable ids) + public async Task ExcluirAbrangenciasHistoricas(IEnumerable ids) { const string comando = @"delete from public.abrangencia where id in (#ids) and historico = true"; @@ -82,7 +82,7 @@ public void ExcluirAbrangenciasHistoricas(IEnumerable ids) { var iteracao = ids.Skip(i).Take(900); - database.Conexao.Execute(comando.Replace("#ids", string.Join(",", iteracao.Concat(new long[] { 0 })))); + await database.Conexao.ExecuteAsync(comando.Replace("#ids", string.Join(",", iteracao.Concat(new long[] { 0 })))); } } @@ -203,7 +203,7 @@ public async Task> ObterAbrangenciaHistoric query.AppendLine("from"); query.AppendLine("public.v_abrangencia_sintetica where login = @login and historico"); - return (await database.Conexao.QueryAsync(query.ToString(), new { login })).AsList(); + return await database.Conexao.QueryAsync(query.ToString(), new { login }); } public async Task ObterAbrangenciaTurma(string turma, string login, Guid perfil, bool consideraHistorico = false, bool abrangenciaPermitida = false) diff --git a/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs b/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs index 9d486772b5..c494531b3c 100644 --- a/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs +++ b/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs @@ -7,17 +7,19 @@ namespace SME.SGP.Dados.Repositorios { - public class RepositorioAcompanhamentoAlunoConsulta : RepositorioBase, IRepositorioAcompanhamentoAlunoConsulta + public class RepositorioAcompanhamentoAlunoConsulta : RepositorioBase, + IRepositorioAcompanhamentoAlunoConsulta { public RepositorioAcompanhamentoAlunoConsulta(ISgpContextConsultas conexao, IServicoAuditoria servicoAuditoria) : base(conexao, servicoAuditoria) { } - public async Task ObterAcompanhamentoPorTurmaAlunoESemestre(long turmaId, string alunoCodigo, int semestre) + public async Task ObterAcompanhamentoPorTurmaAlunoESemestre(long turmaId, + string alunoCodigo, int semestre) { - try - { - var query = @"select aas.* + //esse try catch fica sem sentido ja que so pega e relanca + //e ainda acaba alterando a stack trace original, nao entendi a motivacao + var query = @"select aas.* from acompanhamento_aluno_semestre aas inner join acompanhamento_aluno aa on aa.id = aas.acompanhamento_aluno_id where aa.turma_id = @turmaId @@ -25,20 +27,16 @@ from acompanhamento_aluno_semestre aas and aas.semestre = @semestre and not aas.excluido "; - return await database.Conexao.QueryFirstOrDefaultAsync(query, new { turmaId, alunoCodigo, semestre }); - } - catch (System.Exception ex) - { - throw ex; - } - + return await database.Conexao.QueryFirstOrDefaultAsync(query, + new {turmaId, alunoCodigo, semestre}); } public async Task ObterPorTurmaEAluno(long turmaId, string alunoCodigo) { - var query = @"select id from acompanhamento_aluno where not excluido and turma_id = @turmaId and aluno_codigo = @alunoCodigo"; + var query = + @"select id from acompanhamento_aluno where not excluido and turma_id = @turmaId and aluno_codigo = @alunoCodigo"; - return await database.Conexao.QueryFirstOrDefaultAsync(query, new { turmaId, alunoCodigo }); + return await database.Conexao.QueryFirstOrDefaultAsync(query, new {turmaId, alunoCodigo}); } public async Task ObterTotalAlunosComAcompanhamentoPorTurmaSemestre(long turmaId, int semestre, string[] codigosAlunos) @@ -58,7 +56,6 @@ and not aa.excluido public async Task ObterTotalAlunosTurmaSemestre(long turmaId, int semestre) { - var whereBimestre = semestre == 1 ? " and pe.bimestre in (1,2) " : "and pe.bimestre in (3, 4)"; var query = $@"select count(distinct rfa.codigo_aluno) @@ -71,7 +68,7 @@ where not rfa.excluido and t.id = @turmaId {whereBimestre}"; - return await database.Conexao.QueryFirstOrDefaultAsync(query, new { turmaId, semestre }); + return await database.Conexao.QueryFirstOrDefaultAsync(query, new {turmaId, semestre}); } public async Task ObterUltimoSemestreAcompanhamentoGerado(string alunoCodigo) diff --git a/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs.rej b/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs.rej new file mode 100644 index 0000000000..a4ae5718c1 --- /dev/null +++ b/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs.rej @@ -0,0 +1,12 @@ +diff a/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs b/src/SME.SGP.Dados/Repositorios/RepositorioAcompanhamentoAlunoConsulta.cs (rejected hunks) +@@ -85,7 +82,7 @@ namespace SME.SGP.Dados.Repositorios + WHERE aa2.aluno_codigo = @alunoCodigo) + AND aa.aluno_codigo = @alunoCodigo"; + +- return await database.Conexao.QueryFirstOrDefaultAsync(sql, new { alunoCodigo }); ++ return await database.Conexao.QueryFirstOrDefaultAsync(sql, new {alunoCodigo}); + } + } +-} ++} +\ No newline at end of file diff --git a/src/SME.SGP.Dados/Repositorios/RepositorioComunicado.cs b/src/SME.SGP.Dados/Repositorios/RepositorioComunicado.cs index f22ed6d679..bee8cb026b 100644 --- a/src/SME.SGP.Dados/Repositorios/RepositorioComunicado.cs +++ b/src/SME.SGP.Dados/Repositorios/RepositorioComunicado.cs @@ -291,7 +291,8 @@ END agruparModalidade private string MontarCondicoesDaConsultaObterComunicadosParaFiltroDaDashboard(FiltroObterComunicadosParaFiltroDaDashboardDto filtro, string comunicadoAlias, string comunicadoTumaAlias, string turmaAlias, string comunicadoModalidadeAlias) { - var where = new StringBuilder($" WHERE {comunicadoAlias}.ano_letivo = @anoLetivo "); + //aqui ta pegando nome de coluna invalido e dando erro, provavel bug + var where = new StringBuilder($" WHERE {comunicadoAlias}.ano_letivo = @AnoLetivo "); where.Append(!string.IsNullOrWhiteSpace(filtro.CodigoDre) ? $" AND {comunicadoAlias}.codigo_dre = @CodigoDre" : $" AND {comunicadoAlias}.codigo_dre is null"); diff --git a/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs b/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs index 3ffcf8ec63..486e9510f1 100644 --- a/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs +++ b/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs @@ -75,4 +75,4 @@ public async Task> ObterConsolidacoesConselhoClasseNotaIdsPorC } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs.rej b/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs.rej new file mode 100644 index 0000000000..e5d306170a --- /dev/null +++ b/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs.rej @@ -0,0 +1,70 @@ +diff a/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs b/src/SME.SGP.Dados/Repositorios/RepositorioConselhoClasseConsolidadoNota.cs (rejected hunks) +@@ -15,47 +15,49 @@ namespace SME.SGP.Dados + this.database = database; + } + +- public Task ObterConselhoClasseConsolidadoPorTurmaBimestreAlunoNotaAsync(long consolidadoTurmaAlunoId, int? bimestre, long? componenteCurricularId) ++ public Task ++ ObterConselhoClasseConsolidadoPorTurmaBimestreAlunoNotaAsync(long consolidadoTurmaAlunoId, int? bimestre, ++ long? componenteCurricularId) + { +- var query = $@" select id,consolidado_conselho_classe_aluno_turma_id,bimestre,nota,conceito_id,componente_curricular_id ++ var query = ++ $@" select id,consolidado_conselho_classe_aluno_turma_id,bimestre,nota,conceito_id,componente_curricular_id + from consolidado_conselho_classe_aluno_turma_nota + where consolidado_conselho_classe_aluno_turma_id = @consolidadoTurmaAlunoId "; + +- query += (bimestre.HasValue && bimestre.Value > 0) ? " and bimestre = @bimestre " : " and bimestre is null "; ++ query += (bimestre.HasValue && bimestre.Value > 0) ++ ? " and bimestre = @bimestre " ++ : " and bimestre is null "; + + if (componenteCurricularId.HasValue) + query += " and componente_curricular_id = @componenteCurricularId"; + +- return database.Conexao.QueryFirstOrDefaultAsync(query, new { consolidadoTurmaAlunoId, bimestre, componenteCurricularId }); ++ return database.Conexao.QueryFirstOrDefaultAsync(query, ++ new {consolidadoTurmaAlunoId, bimestre, componenteCurricularId}); + } + +- public Task ObterConselhoClasseConsolidadoAlunoNotaPorConsolidadoBimestreDisciplinaAsync(long consolidacaoId, int bimestre, long disciplinaId) ++ public Task ++ ObterConselhoClasseConsolidadoAlunoNotaPorConsolidadoBimestreDisciplinaAsync(long consolidacaoId, ++ int bimestre, long disciplinaId) + { +- var query = $@" select id,consolidado_conselho_classe_aluno_turma_id,bimestre,nota,conceito_id,componente_curricular_id ++ var query = ++ $@" select id,consolidado_conselho_classe_aluno_turma_id,bimestre,nota,conceito_id,componente_curricular_id + from consolidado_conselho_classe_aluno_turma_nota + where consolidado_conselho_classe_aluno_turma_id = @consolidacaoId + {(bimestre == 0 ? " and bimestre is null " : " and bimestre = @bimestre")} + and componente_curricular_id = @disciplinaId"; + +- return database.Conexao.QueryFirstOrDefaultAsync(query, new { consolidacaoId, bimestre, disciplinaId }); ++ return database.Conexao.QueryFirstOrDefaultAsync(query, ++ new {consolidacaoId, bimestre, disciplinaId}); + } + + public async Task SalvarAsync(ConselhoClasseConsolidadoTurmaAlunoNota consolidadoNota) + { +- try ++ if (consolidadoNota.Id > 0) + { +- if (consolidadoNota.Id > 0) +- { +- var sucesso = await database.Conexao.UpdateAsync(consolidadoNota); +- return sucesso ? consolidadoNota.Id : 0; +- } +- else +- return (long)(await database.Conexao.InsertAsync(consolidadoNota)); +- } +- catch (System.Exception ex) +- { +- throw ex; ++ var sucesso = await database.Conexao.UpdateAsync(consolidadoNota); ++ return sucesso ? consolidadoNota.Id : 0; + } ++ return (long) await database.Conexao.InsertAsync(consolidadoNota); + } + + public async Task ExcluirConsolidacaoConselhoClasseNotaPorIdsConsolidacaoAlunoEBimestre(long[] idsConsolidacao) diff --git a/src/SME.SGP.Dados/Repositorios/RepositorioTurmaConsulta.cs b/src/SME.SGP.Dados/Repositorios/RepositorioTurmaConsulta.cs index 9711eeb7b2..c2073e9097 100644 --- a/src/SME.SGP.Dados/Repositorios/RepositorioTurmaConsulta.cs +++ b/src/SME.SGP.Dados/Repositorios/RepositorioTurmaConsulta.cs @@ -102,8 +102,6 @@ inner join dre d on where turma_id = @turmaCodigo"; - contexto.AbrirConexao(); - return (await contexto.QueryAsync(query, (turma, ue, dre) => { ue.AdicionarDre(dre); diff --git a/src/SME.SGP.Dados/SME.SGP.Dados.csproj b/src/SME.SGP.Dados/SME.SGP.Dados.csproj index cc82338355..f99e28c1a2 100644 --- a/src/SME.SGP.Dados/SME.SGP.Dados.csproj +++ b/src/SME.SGP.Dados/SME.SGP.Dados.csproj @@ -2,6 +2,7 @@ net5.0 + false diff --git a/src/SME.SGP.Dados/UnitOfWork.cs b/src/SME.SGP.Dados/UnitOfWork.cs index 6721a472a2..b44d6e8396 100644 --- a/src/SME.SGP.Dados/UnitOfWork.cs +++ b/src/SME.SGP.Dados/UnitOfWork.cs @@ -1,54 +1,114 @@ using SME.SGP.Dominio; using SME.SGP.Infra; using System.Data; +using System.Data.Common; +using System.Threading.Tasks; namespace SME.SGP.Dados { + //O conceito de unit of work está implementado bem estranhamente ao meu ver, + //No maximo essa implementacao externaliza o conceito de transacao e depende muito + //do desenvolvedor gerenciar o ciclo de vida de abertura, commit e rollback,etc + + //Implementacoes mais comuns de UOW tendem a garantir que todos os repositorios compartilhem o mesmo contexto e que nao possam ser acessados + //por outra forma de injecao a nao ser pelo proprio unit of work que vai garantir que todos os repos vao usar o mesmo contexto de conexao, transacao, etc + + //Eu aconselho a trabalhar com AOP usando dinamic proxies e controlando transacoes com custom attributes + //anotando os metodos de comandos que precisa ser executados dentro de uma mesma transacao corrente + + //Outro caso mais facil de implementar é trabalhar com filtros no escopo de web IActionFilter, IAsyncActionFilter + //que abrem uma transacao no comeco do request e ou faz commit ou rollback no fim do request dependendo se lancou ou nao exception + + //de todos os modos nao é aconselhavel depender de um desenvolvedor lembrar de gerenciar o ciclo de vida de uma transacao public class UnitOfWork : IUnitOfWork { private readonly ISgpContext sgpContext; - private IDbTransaction transacao; - public bool TransacaoAberta { get; set; } + private DbTransaction dbTransaction; public UnitOfWork(ISgpContext sgpContext) { this.sgpContext = sgpContext ?? throw new System.ArgumentNullException(nameof(sgpContext)); } - public void Dispose() - { - if (TransacaoAberta) - Rollback(); - } + //eu nao vazaria a transacao para o lado de fora do uow + //ja que esta sendo usado como scoped o dispose vai ser chamado no final do request public IDbTransaction IniciarTransacao() { - if (transacao == null || transacao?.Connection?.State == null && !TransacaoAberta) + if (HasTransaction) { - transacao = sgpContext.BeginTransaction(); - TransacaoAberta = true; + return dbTransaction; } - - return transacao; + + dbTransaction = sgpContext.BeginTransaction() as DbTransaction; + return dbTransaction; } public void PersistirTransacao() { - if (transacao != null && TransacaoAberta) + if (HasTransaction) { - transacao.Commit(); - TransacaoAberta = false; - transacao = null; + dbTransaction.Commit(); + dbTransaction = null; } } public void Rollback() { - if (transacao != null && transacao.Connection != null && TransacaoAberta) + if (HasTransaction) + { + dbTransaction.Rollback(); + dbTransaction = null; + } + } + + public async Task IniciarTransacaoAsync() + { + if (HasTransaction) + { + return dbTransaction; + } + + return await sgpContext.BeginTransactionAsync(); + } + + public async Task PersistirTransacaoAsync() + { + if (HasTransaction) { - transacao.Rollback(); - TransacaoAberta = false; + await dbTransaction.CommitAsync(); + dbTransaction = null; } } + + public async Task RollbackAsync() + { + if (HasTransaction) + { + await dbTransaction.RollbackAsync(); + dbTransaction = null; + } + } + + public async Task CommitAsync() + { + if (HasTransaction) + { + await dbTransaction.CommitAsync(); + dbTransaction = null; + } + } + + private bool HasTransaction => dbTransaction is not null; + + public void Dispose() + { + Rollback(); + } + + public async ValueTask DisposeAsync() + { + await RollbackAsync(); + } } } \ No newline at end of file diff --git a/src/SME.SGP.Dominio.Interfaces/Repositorios/IRepositorioAbrangencia.cs b/src/SME.SGP.Dominio.Interfaces/Repositorios/IRepositorioAbrangencia.cs index 84de2574cf..9f14be7428 100644 --- a/src/SME.SGP.Dominio.Interfaces/Repositorios/IRepositorioAbrangencia.cs +++ b/src/SME.SGP.Dominio.Interfaces/Repositorios/IRepositorioAbrangencia.cs @@ -15,7 +15,7 @@ public interface IRepositorioAbrangencia void ExcluirAbrangencias(IEnumerable ids); - void ExcluirAbrangenciasHistoricas(IEnumerable ids); + Task ExcluirAbrangenciasHistoricas(IEnumerable ids); void InserirAbrangencias(IEnumerable abrangencias, string login); diff --git a/src/SME.SGP.Dominio.Interfaces/SME.SGP.Dominio.Interfaces.csproj b/src/SME.SGP.Dominio.Interfaces/SME.SGP.Dominio.Interfaces.csproj index 8c0e98776f..a357514988 100644 --- a/src/SME.SGP.Dominio.Interfaces/SME.SGP.Dominio.Interfaces.csproj +++ b/src/SME.SGP.Dominio.Interfaces/SME.SGP.Dominio.Interfaces.csproj @@ -2,6 +2,7 @@ net5.0 + false diff --git a/src/SME.SGP.Dominio.Interfaces/Servicos/IServicoAbrangencia.cs b/src/SME.SGP.Dominio.Interfaces/Servicos/IServicoAbrangencia.cs index 93c728371f..f8b41af726 100644 --- a/src/SME.SGP.Dominio.Interfaces/Servicos/IServicoAbrangencia.cs +++ b/src/SME.SGP.Dominio.Interfaces/Servicos/IServicoAbrangencia.cs @@ -10,9 +10,9 @@ public interface IServicoAbrangencia { void RemoverAbrangencias(long[] ids); - void RemoverAbrangenciasHistoricas(long[] ids); + Task RemoverAbrangenciasHistoricas(long[] ids); - void RemoverAbrangenciasHistoricasIncorretas(string login, List perfis); + Task RemoverAbrangenciasHistoricasIncorretas(string login, List perfis); Task> ObterAbrangenciaHistorica(string login); diff --git a/src/SME.SGP.Dominio.Servicos/SME.SGP.Dominio.Servicos.csproj b/src/SME.SGP.Dominio.Servicos/SME.SGP.Dominio.Servicos.csproj index 13ab8a56f3..f2eac028d2 100644 --- a/src/SME.SGP.Dominio.Servicos/SME.SGP.Dominio.Servicos.csproj +++ b/src/SME.SGP.Dominio.Servicos/SME.SGP.Dominio.Servicos.csproj @@ -2,6 +2,7 @@ net5.0 + false diff --git a/src/SME.SGP.Dominio/IUnitOfWork.cs b/src/SME.SGP.Dominio/IUnitOfWork.cs index 1aba5ac64c..f8e73d76c1 100644 --- a/src/SME.SGP.Dominio/IUnitOfWork.cs +++ b/src/SME.SGP.Dominio/IUnitOfWork.cs @@ -1,14 +1,18 @@ using System; using System.Data; +using System.Threading.Tasks; namespace SME.SGP.Dominio { - public interface IUnitOfWork : IDisposable + public interface IUnitOfWork : IDisposable,IAsyncDisposable { IDbTransaction IniciarTransacao(); - void PersistirTransacao(); - void Rollback(); + + Task IniciarTransacaoAsync(); + Task PersistirTransacaoAsync(); + Task RollbackAsync(); + Task CommitAsync(); } } \ No newline at end of file diff --git a/src/SME.SGP.Dominio/SME.SGP.Dominio.csproj b/src/SME.SGP.Dominio/SME.SGP.Dominio.csproj index c71dd9e120..cf6fa86d1d 100644 --- a/src/SME.SGP.Dominio/SME.SGP.Dominio.csproj +++ b/src/SME.SGP.Dominio/SME.SGP.Dominio.csproj @@ -2,6 +2,7 @@ netstandard2.1 + false diff --git a/src/SME.SGP.Infra.Mensageria/IoC/RegistrarRabbit.cs b/src/SME.SGP.Infra.Mensageria/IoC/RegistrarRabbit.cs index ed17dbb1f1..4cd3c17f89 100644 --- a/src/SME.SGP.Infra.Mensageria/IoC/RegistrarRabbit.cs +++ b/src/SME.SGP.Infra.Mensageria/IoC/RegistrarRabbit.cs @@ -40,10 +40,11 @@ public static void ConfigurarRabbit(this IServiceCollection services, IConfigura var serviceProvider = services.BuildServiceProvider(); var options = serviceProvider.GetService>().Value; - services.AddSingleton(serviceProvider => + services.AddSingleton(_ => { var factory = new ConnectionFactory { + Port = options.Port, HostName = options.HostName, UserName = options.UserName, Password = options.Password, diff --git a/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbit.cs b/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbit.cs index 9ff181c065..03c760fe38 100644 --- a/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbit.cs +++ b/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbit.cs @@ -3,6 +3,7 @@ public abstract class ConfiguracaoRabbit { public static string Secao => ""; + public int Port { get; set; } public string HostName { get; set; } public string UserName { get; set; } public string Password { get; set; } diff --git a/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbitOptions.cs b/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbitOptions.cs index fe766d5808..9afbc9076c 100644 --- a/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbitOptions.cs +++ b/src/SME.SGP.Infra.Mensageria/Options/ConfiguracaoRabbitOptions.cs @@ -4,4 +4,4 @@ public class ConfiguracaoRabbitOptions : ConfiguracaoRabbit { public new static string Secao => "ConfiguracaoRabbit"; } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Infra.Mensageria/RabbitModelPooledObjectPolicy.cs b/src/SME.SGP.Infra.Mensageria/RabbitModelPooledObjectPolicy.cs index 54532441d1..e392ce7336 100644 --- a/src/SME.SGP.Infra.Mensageria/RabbitModelPooledObjectPolicy.cs +++ b/src/SME.SGP.Infra.Mensageria/RabbitModelPooledObjectPolicy.cs @@ -7,42 +7,43 @@ namespace SME.SGP.Infra { public class RabbitModelPooledObjectPolicy : IPooledObjectPolicy { - private readonly IConnection conexao; + private readonly IConnection _connection; public RabbitModelPooledObjectPolicy(ConfiguracaoRabbit configuracaoRabbitOptions) { - conexao = GetConnection(configuracaoRabbitOptions ?? throw new ArgumentNullException(nameof(configuracaoRabbitOptions))); + _connection = CreateConnection(configuracaoRabbitOptions ?? + throw new ArgumentNullException(nameof(configuracaoRabbitOptions))); } - private IConnection GetConnection(ConfiguracaoRabbit configuracaoRabbit) + private IConnection CreateConnection(ConfiguracaoRabbit configuracaoRabbit) { - var factory = new ConnectionFactory() + var connectionFactory = new ConnectionFactory() { + Port = configuracaoRabbit.Port, HostName = configuracaoRabbit.HostName, UserName = configuracaoRabbit.UserName, Password = configuracaoRabbit.Password, VirtualHost = configuracaoRabbit.VirtualHost }; - - return factory.CreateConnection(); + return connectionFactory.CreateConnection(); } public IModel Create() { - var channel = conexao.CreateModel(); - channel.ConfirmSelect(); - return channel; + var model = _connection.CreateModel(); + model.ConfirmSelect(); + return model; } - public bool Return(IModel obj) + public bool Return(IModel model) { - if (obj.IsOpen) - return true; - else + if (model.IsOpen) { - obj?.Dispose(); - return false; + return true; } + + model.Dispose(); + return false; } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs b/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs index 8c73eb433c..6b5c58798f 100644 --- a/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs +++ b/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs @@ -19,7 +19,8 @@ public abstract class ServicoMensageria : IServicoMensageria private readonly IServicoTelemetria servicoTelemetria; private readonly IAsyncPolicy policy; - public ServicoMensageria(IConexoesRabbit conexaoRabbit, IServicoTelemetria servicoTelemetria, IReadOnlyPolicyRegistry registry) + public ServicoMensageria(IConexoesRabbit conexaoRabbit, IServicoTelemetria servicoTelemetria, + IReadOnlyPolicyRegistry registry) { this.conexaoRabbit = conexaoRabbit ?? throw new ArgumentNullException(nameof(conexaoRabbit)); this.servicoTelemetria = servicoTelemetria ?? throw new ArgumentNullException(nameof(servicoTelemetria)); @@ -56,24 +57,35 @@ private Task PublicarMensagem(string rota, byte[] body, string exchange = null, props.Persistent = true; channel.BasicPublish(exchange, rota, true, props, body); + //essa task retornava como completa mesmo que tenha dado erro ? + return Task.CompletedTask; + } + catch (Exception ex) + { + //nao deveria no caso de exception devolver uma task com erro ? + return Task.FromException(ex); } finally { conexaoRabbit.Return(channel); } - - return Task.CompletedTask; } - + public virtual string ObterParametrosMensagem(T mensagemRabbit) - => ""; + { + //nao precisa alocar string vazia + return String.Empty; + } } public class ServicoMensageriaSGP : ServicoMensageria, IServicoMensageriaSGP { - public ServicoMensageriaSGP(IConexoesRabbitFilasSGP conexaoRabbit, IServicoTelemetria servicoTelemetria, IReadOnlyPolicyRegistry registry) - : base(conexaoRabbit, servicoTelemetria, registry) { } + public ServicoMensageriaSGP(IConexoesRabbitFilasSGP conexaoRabbit, IServicoTelemetria servicoTelemetria, + IReadOnlyPolicyRegistry registry) + : base(conexaoRabbit, servicoTelemetria, registry) + { + } } public class ServicoMensageriaLogs : ServicoMensageria, IServicoMensageriaLogs diff --git a/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs.rej b/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs.rej new file mode 100644 index 0000000000..d0d7b2e276 --- /dev/null +++ b/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs.rej @@ -0,0 +1,38 @@ +diff a/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs b/src/SME.SGP.Infra.Mensageria/ServicoMensageria.cs (rejected hunks) +@@ -32,11 +33,10 @@ namespace SME.SGP.Infra + NullValueHandling = NullValueHandling.Ignore + }); + var body = Encoding.UTF8.GetBytes(mensagem); +- +- await servicoTelemetria.RegistrarAsync(async () => +- await policy.ExecuteAsync(async () => await PublicarMensagem(rota, body, exchange, canalRabbit)), +- "RabbitMQ", nomeAcao, rota, ObterParametrosMensagem(request)); +- ++ Func fnTaskPublicarMensagem = async () => await PublicarMensagem(rota, body, exchange, canalRabbit); ++ Func fnTaskPolicy = async () => await policy.ExecuteAsync(fnTaskPublicarMensagem); ++ await servicoTelemetria.RegistrarAsync(fnTaskPolicy, "RabbitMQ", nomeAcao, ++ rota, ObterParametrosMensagem(request)); + return true; + } + +@@ -75,11 +86,14 @@ namespace SME.SGP.Infra + { + var json = JsonConvert.SerializeObject(mensagemLog); + var mensagem = JsonConvert.DeserializeObject(json); +- return mensagem!.Mensagem +", ExcecaoInterna:" + mensagem.ExcecaoInterna; ++ //poderia alocar menos strings para esses casos com interpolacao ++ return $"{mensagem!.Mensagem}, ExcecaoInterna:{mensagem.ExcecaoInterna}"; + } + +- public ServicoMensageriaLogs(IConexoesRabbitFilasLog conexaoRabbit, IServicoTelemetria servicoTelemetria, IReadOnlyPolicyRegistry registry) +- : base(conexaoRabbit, servicoTelemetria, registry) { } ++ public ServicoMensageriaLogs(IConexoesRabbitFilasLog conexaoRabbit, IServicoTelemetria servicoTelemetria, ++ IReadOnlyPolicyRegistry registry) ++ : base(conexaoRabbit, servicoTelemetria, registry) ++ { ++ } + } +- +-} ++} +\ No newline at end of file diff --git a/src/SME.SGP.Infra.Polly/RegistrarPolicies.cs b/src/SME.SGP.Infra.Polly/RegistrarPolicies.cs index 2c4ff52e89..37b4493956 100644 --- a/src/SME.SGP.Infra.Polly/RegistrarPolicies.cs +++ b/src/SME.SGP.Infra.Polly/RegistrarPolicies.cs @@ -1,8 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Polly; -using Polly.Registry; using SME.SGP.Infra; -using System; namespace SME.SGP.IoC { @@ -10,22 +9,34 @@ public static class RegistrarPolicies { public static void AddPolicies(this IServiceCollection services) { - IPolicyRegistry registry = services.AddPolicyRegistry(); - - Random jitterer = new(); - var policyFila = Policy.Handle() - .WaitAndRetryAsync(3, - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) - + TimeSpan.FromMilliseconds(jitterer.Next(0, 30))); - - registry.Add(PoliticaPolly.PublicaFila, policyFila); + var policyRegistry = services.AddPolicyRegistry(); + var policy = Policy.Handle() + .WaitAndRetryAsync(3, WithRetryAttempt); + policyRegistry.Add(PoliticaPolly.PublicaFila, policy); + policyRegistry.Add(PoliticaPolly.SGP, policy); + } - var policySgp = Policy.Handle() - .WaitAndRetryAsync(3, - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) - + TimeSpan.FromMilliseconds(jitterer.Next(0, 30))); + //nao sei se jitter pra esse caso do polly precisaria ser considerado + //pela politica de execucao exponencial o tempo a cada tentativa. + //Eu sugeriria escala linear ou logaritmica e nao exponencial para o usuario + //nao ter a sensacao que o sistema esta demorando muito pra responder + private static TimeSpan WithRetryAttempt(int retryAttempt) + { + var jitter = ConcurrentRandom.Next(0, 30); + var exponencialValue = Math.Pow(2, retryAttempt); + return TimeSpan.FromSeconds(exponencialValue) + TimeSpan.FromMilliseconds(jitter); + } + } - registry.Add(PoliticaPolly.SGP, policySgp); + //random no .net5 não é thread safe e pode retornar varios calculos com zero para Next, + //o ideal seria uma instancia por thread no minimo. no .net6 tem o Random.Shared + public static class ConcurrentRandom + { + [ThreadStatic] private static Random? _random; + private static Random Instance => _random ??= new Random(); + public static int Next(int minValue, int maxValue) + { + return Instance.Next(minValue, maxValue); } } } diff --git a/src/SME.SGP.Infra.Telemetria/IServicoTelemetria.cs b/src/SME.SGP.Infra.Telemetria/IServicoTelemetria.cs index 15404f4fed..7b9b7a660b 100644 --- a/src/SME.SGP.Infra.Telemetria/IServicoTelemetria.cs +++ b/src/SME.SGP.Infra.Telemetria/IServicoTelemetria.cs @@ -6,11 +6,21 @@ namespace SME.SGP.Infra { public interface IServicoTelemetria { - ITransaction Iniciar(string nome, string tipo); - void Finalizar(ITransaction transacao); - Task RegistrarComRetornoAsync(Func> acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = ""); - dynamic RegistrarComRetorno(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = ""); + ITransaction? Iniciar(string nome, string tipo); + void Finalizar(ITransaction? transacao); + + //nesse caso nao entendi direito o porque do uso da palavra chave dynamic aqui, sendo que o tipo dinamico já é indicado no metodo + //a keyword dynamic nao vai conseguir fazer checagens de tipo em tempo de compilacao + //dynamic tambem vai usar mais ciclos de cpu do que tipo estaticos passados + //se nao for o caso de realmente usar dynamic no metodo eu trocaria para o Tipo T do metodo + Task RegistrarComRetornoAsync(Func> acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = ""); + + //Caso de assinatura que evita alocacao dos delegates + Task RegistrarComRetornoAsync(T1 t1,T2 t2,T3 t3,Func> acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = ""); + + + T RegistrarComRetorno(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = ""); void Registrar(Action acao, string acaoNome, string telemetriaNome, string telemetriaValor); Task RegistrarAsync(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = ""); } diff --git a/src/SME.SGP.Infra.Telemetria/ServicoTelemetria.cs b/src/SME.SGP.Infra.Telemetria/ServicoTelemetria.cs index 77336c32da..544ec867c5 100644 --- a/src/SME.SGP.Infra.Telemetria/ServicoTelemetria.cs +++ b/src/SME.SGP.Infra.Telemetria/ServicoTelemetria.cs @@ -20,51 +20,19 @@ public ServicoTelemetria(TelemetryClient insightsClient, IOptions RegistrarComRetornoAsync(Func> acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = "") + public Task RegistrarComRetornoAsync(Func> acao, string acaoNome, string telemetriaNome, + string telemetriaValor, string parametros = "") { - DateTime inicioOperacao = default; - Stopwatch temporizador = default; - - dynamic result = default; - - if (telemetriaOptions.ApplicationInsights) - { - inicioOperacao = DateTime.UtcNow; - temporizador = Stopwatch.StartNew(); - } - - if (telemetriaOptions.Apm) - { - var transactionElk = Agent.Tracer.CurrentTransaction; - - await transactionElk.CaptureSpan(telemetriaNome, acaoNome, async (span) => - { - span.SetLabel(telemetriaNome, telemetriaValor); - span.SetLabel("Parametros", parametros); - result = (await acao()) as dynamic; - }); - } - else - { - result = await acao() as dynamic; - } - - if (telemetriaOptions.ApplicationInsights) - { - temporizador.Stop(); - - insightsClient?.TrackDependency(acaoNome, telemetriaNome, telemetriaValor, inicioOperacao, temporizador.Elapsed, true); - } - - return result; + return RegistrarComRetornoAsync(acao(), acaoNome, telemetriaNome, telemetriaValor, parametros); } - public dynamic RegistrarComRetorno(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = "") + private async Task RegistrarComRetornoAsync(Task acao, string acaoNome, string telemetriaNome, + string telemetriaValor, string parametros = "") { DateTime inicioOperacao = default; Stopwatch temporizador = default; - dynamic result = default; + T result = default; if (telemetriaOptions.ApplicationInsights) { @@ -76,32 +44,51 @@ public dynamic RegistrarComRetorno(Func acao, string acaoNome, string { var transactionElk = Agent.Tracer.CurrentTransaction; - transactionElk.CaptureSpan(telemetriaNome, acaoNome, (span) => + await transactionElk.CaptureSpan(telemetriaNome, acaoNome, async (span) => { span.SetLabel(telemetriaNome, telemetriaValor); span.SetLabel("Parametros", parametros); - result = acao(); + result = await acao; }); } else { - result = acao(); + result = await acao; } if (telemetriaOptions.ApplicationInsights) { temporizador.Stop(); - insightsClient?.TrackDependency(acaoNome, telemetriaNome, telemetriaValor, inicioOperacao, temporizador.Elapsed, true); + insightsClient?.TrackDependency(acaoNome, telemetriaNome, telemetriaValor, inicioOperacao, + temporizador.Elapsed, true); } return result; } + public Task RegistrarComRetornoAsync(T1 t1, T2 t2, T3 t3, Func> acao, + string acaoNome, string telemetriaNome, + string telemetriaValor, string parametros = "") + { + return RegistrarComRetornoAsync(acao(t1, t2, t3), acaoNome, telemetriaNome, telemetriaValor, parametros); + } + + public T RegistrarComRetorno(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, + string parametros = "") + { + //A implemementacao principal esta no metodo de async e aqui so repete tudo que esta no async so que executando a funcao sincronamente + //compensaria chamar o metodo async aqui bloqueando a execucao do resultado para nao duplicar codigo + return RegistrarComRetornoAsync(() => Task.FromResult(acao()), acaoNome, telemetriaNome, telemetriaValor, + parametros).GetAwaiter().GetResult(); + } + public void Registrar(Action acao, string acaoNome, string telemetriaNome, string telemetriaValor) { + //Mesmo caso aqui toda implementacao esta no metodo de async + //compensaria chamar o metodo async aqui bloqueando a execucao do resultado para nao duplicar codigo DateTime inicioOperacao = default; - Stopwatch temporizador = default; + Stopwatch temporizador = default; if (telemetriaOptions.ApplicationInsights) { @@ -127,20 +114,15 @@ public void Registrar(Action acao, string acaoNome, string telemetriaNome, strin if (telemetriaOptions.ApplicationInsights) { temporizador.Stop(); - insightsClient?.TrackDependency(acaoNome, telemetriaNome, telemetriaValor, inicioOperacao, temporizador.Elapsed, true); - } + insightsClient?.TrackDependency(acaoNome, telemetriaNome, telemetriaValor, inicioOperacao, + temporizador.Elapsed, true); + } } - public async Task RegistrarAsync(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = "") + public async Task RegistrarAsync(Func acao, string acaoNome, string telemetriaNome, + string telemetriaValor, string parametros = "") { - DateTime inicioOperacao = default; - Stopwatch temporizador = default; - - if (telemetriaOptions.ApplicationInsights) - { - inicioOperacao = DateTime.UtcNow; - temporizador = Stopwatch.StartNew(); - } + var valueStopwatch = ValueStopwatch.StartNew(); if (telemetriaOptions.Apm) { @@ -163,22 +145,54 @@ await transactionElk.CaptureSpan(telemetriaNome, acaoNome, async (span) => if (telemetriaOptions.ApplicationInsights) { - temporizador.Stop(); - insightsClient?.TrackDependency(acaoNome, telemetriaNome, telemetriaValor, inicioOperacao, temporizador.Elapsed, true); - } + insightsClient?.TrackDependency(acaoNome, telemetriaNome, telemetriaValor, + valueStopwatch.StartedAt, valueStopwatch.Elapsed, true); + } } - public ITransaction Iniciar(string nome, string tipo) + public ITransaction? Iniciar(string nome, string tipo) { return telemetriaOptions.Apm ? Agent.Tracer.StartTransaction(nome, tipo) : null; } - public void Finalizar(ITransaction transacao) + public void Finalizar(ITransaction? transacao) { if (telemetriaOptions.Apm) - transacao.End(); + transacao?.End(); + } + + //Se quiser evitar alocacao de stop watch em toda telemetria e nao precisar nada muito avancado de stop watch + //da pra criar algo do tipo acessivel a partes do projeto + public readonly struct ValueStopwatch + { + private static readonly double Ticks = (double) TimeSpan.TicksPerSecond / (double) Stopwatch.Frequency; + + private readonly long _startTimestamp; + + private readonly DateTime _startDateTime; + + private ValueStopwatch(long startTimestamp, DateTime startDateTime) + { + _startDateTime = startDateTime; + _startTimestamp = startTimestamp; + } + + public static ValueStopwatch StartNew() => new(GetTimestamp(), DateTime.UtcNow); + + private static long GetTimestamp() => Stopwatch.GetTimestamp(); + + private static TimeSpan GetElapsedTime(long startTimestamp, long endTimestamp) + { + var delta = endTimestamp - startTimestamp; + var ticks = (long) (Ticks * delta); + return new TimeSpan(ticks); + } + + public DateTime StartedAt => _startDateTime; + + public TimeSpan Elapsed => GetElapsedTime(_startTimestamp, GetTimestamp()); } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Infra/Dtos/UsuarioAutenticacaoRetornoDto.cs b/src/SME.SGP.Infra/Dtos/UsuarioAutenticacaoRetornoDto.cs index 3bb8ccf1cf..710bfa4f16 100644 --- a/src/SME.SGP.Infra/Dtos/UsuarioAutenticacaoRetornoDto.cs +++ b/src/SME.SGP.Infra/Dtos/UsuarioAutenticacaoRetornoDto.cs @@ -2,13 +2,8 @@ namespace SME.SGP.Infra { - public class UsuarioAutenticacaoRetornoDto + public struct UsuarioAutenticacaoRetornoDto { - public UsuarioAutenticacaoRetornoDto() - { - Autenticado = false; - ModificarSenha = false; - } public bool Autenticado { get; set; } public bool ModificarSenha { get; set; } diff --git a/src/SME.SGP.Infra/Interfaces/ISgpContext.cs b/src/SME.SGP.Infra/Interfaces/ISgpContext.cs index 74e2b51728..df3a3477f1 100644 --- a/src/SME.SGP.Infra/Interfaces/ISgpContext.cs +++ b/src/SME.SGP.Infra/Interfaces/ISgpContext.cs @@ -1,18 +1,21 @@  using System; using System.Data; +using System.Data.Common; +using System.Threading.Tasks; namespace SME.SGP.Infra { - public interface ISgpContext : IDbConnection + public interface ISgpContext : IDbConnection, IAsyncDisposable { IDbConnection Conexao { get; } - string UsuarioLogado { get; } string PerfilUsuario { get; } string UsuarioLogadoNomeCompleto { get; } string UsuarioLogadoRF { get; } string Administrador { get; } - void AbrirConexao(); - void FecharConexao(); + + Task OpenAsync(); + Task CloseAsync(); + Task BeginTransactionAsync(); } } \ No newline at end of file diff --git a/src/SME.SGP.Infra/SME.SGP.Infra.csproj b/src/SME.SGP.Infra/SME.SGP.Infra.csproj index 800caa3969..09c0aeffac 100644 --- a/src/SME.SGP.Infra/SME.SGP.Infra.csproj +++ b/src/SME.SGP.Infra/SME.SGP.Infra.csproj @@ -2,6 +2,7 @@ net5.0 + false diff --git a/src/SME.SGP.Infra/Utilitarios/UtilTasks.cs b/src/SME.SGP.Infra/Utilitarios/UtilTasks.cs new file mode 100644 index 0000000000..2e88cf9537 --- /dev/null +++ b/src/SME.SGP.Infra/Utilitarios/UtilTasks.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +//o ideal é ter algo um pouquinho melhor do que o default da plataforma que vai acabar lancando apenas uma excecao de tasks executando +//pode ou criar como method extensions ou encapsular em alguma classe estatica mesmo como essa +namespace SME.SGP.Infra.Utilitarios +{ + public static class UtilTasks + { + public static async Task WhenAll(params Task[] tasks) + { + var allTasks = Task.WhenAll(tasks); + try + { + await allTasks; + return; + } + catch + { + //Just ignore because if one task fails, all will fail with single exception message even + //another task fails too + } + throw allTasks.Exception ?? throw new Exception("Unreachable code"); + } + } +} \ No newline at end of file diff --git a/src/SME.SGP.IoC/Extensions/RegistrarHttpClients.cs b/src/SME.SGP.IoC/Extensions/RegistrarHttpClients.cs index 0e99a64ae4..4487f62a91 100644 --- a/src/SME.SGP.IoC/Extensions/RegistrarHttpClients.cs +++ b/src/SME.SGP.IoC/Extensions/RegistrarHttpClients.cs @@ -12,6 +12,12 @@ namespace SME.SGP.IoC { internal static class RegistrarHttpClients { + //eu daria uma revisada em algumas coisas em relacao a criacao dos clientes http + //tem casos que usam abstracoes injetando por exemplo ServicoEOL e tem casos chamando o cliente com httpClientFactory.CreateClient("servicoEOL") + //o ideal é encapsular sempre dentro de classe especifica -> ServicoEOL + //outra coisa é aumentar o tempo de lifetime de clientes que usam handlers especificos (caso a caso) que sofrem pooling padrao de 2 minutos + //unificar politicas de retry para todos clientes com retrys mais curtos (hoje esta n^3), se a chamada de api entra em lentidao a percepcao de quem usa antes de falhar + //é que o sistema está lento internal static void AdicionarHttpClients(this IServiceCollection services, IConfiguration configuration) { services.AddHttpClient(c => @@ -48,8 +54,15 @@ internal static void AdicionarHttpClients(this IServiceCollection services, ICon c.DefaultRequestHeaders.Add("x-integration-key", configuration.GetSection("AE_ChaveIntegracao").Value); }); + //typo SevicoGithub services.AddHttpClient(c => { + //A versao poderia estar embedada estaticamente no build do projeto + //Depender do github para pegar a versao do projeto mesmo que cacheando + //acaba dependendo de um sistema externo sem muita necessidade ao meu ver + //alem do que o fallback para se der algum problema é retornar uma string vazia + //duvida, se uma tag é publicada e um container sobe nesse meio tempo + //ele vai pegar a versao da tag gerada que ainda nem foi feito deploy novos ? c.BaseAddress = new Uri(configuration.GetSection("UrlApiGithub").Value); c.DefaultRequestHeaders.Add("Accept", "application/json"); }); @@ -62,6 +75,7 @@ internal static void AdicionarHttpClients(this IServiceCollection services, ICon var basicAuth = $"{configuration.GetValue("ConfiguracaoJasper:Username")}:{configuration.GetValue("ConfiguracaoJasper:Password")}".EncodeTo64(); var jasperUrl = configuration.GetValue("ConfiguracaoJasper:Hostname"); + //typo ISevicoJasper,SevicoJasper services.AddHttpClient(c => { c.BaseAddress = new Uri(jasperUrl); diff --git a/src/SME.SGP.IoC/RegistrarDependencias.cs b/src/SME.SGP.IoC/RegistrarDependencias.cs index dc73e1dc64..171fcec4d5 100644 --- a/src/SME.SGP.IoC/RegistrarDependencias.cs +++ b/src/SME.SGP.IoC/RegistrarDependencias.cs @@ -87,6 +87,12 @@ public virtual void RegistrarParaWorkers(IServiceCollection services, IConfigura services.AddHttpContextAccessor(); services.AdicionarMediatr(); services.AdicionarValidadoresFluentValidation(); + //caches em memoria por instancia podem levar a estados inconsistentes entre nós dependendo de como o balanceamento é feito + //e dependendo da politica de cache + //o ideal é migrar pra um sistema de cache compartilhado como Cluster de Redis por exemplo + //alem do que o cache em memoria da microsoft apesar de dizerem que é thread safe, tem problemas de concorrência + //basta testar multiplas threads com api de Parallel e um contador por exemplo tentando incrementar valores pegando do cache em threads distintas + //era esperado que a primeira thread ao escrever todas as outras lessem o mesmo valor porém isso não acontece. aparentemente a implementação de cache nao funciona de maneira atomica e deterministica, que é desejavel services.AddMemoryCache(); RegistrarHttpClients(services, configuration); diff --git a/src/SME.SGP.IoC/RegistrarDependencias.cs.rej b/src/SME.SGP.IoC/RegistrarDependencias.cs.rej new file mode 100644 index 0000000000..0e9a8a2a74 --- /dev/null +++ b/src/SME.SGP.IoC/RegistrarDependencias.cs.rej @@ -0,0 +1,21 @@ +diff a/src/SME.SGP.IoC/RegistrarDependencias.cs b/src/SME.SGP.IoC/RegistrarDependencias.cs (rejected hunks) +@@ -39,10 +39,18 @@ using SME.SGP.Infra.Contexto; + using SME.SGP.Infra.Interfaces; + using SME.SGP.Infra.Utilitarios; + using System; ++using SME.SGP.Aplicacao.Commands.FilaRabbit; + + namespace SME.SGP.IoC + { +- public class RegistrarDependencias //Raphael. Tirei o static para facilitar o teste ++ //evitar comunicacao escrevendo comentario em codigo, ideal é sempre comunicar por ticket ++ //comentario em pr, atividade etc. ++ ++ //essa classe realmente está gigantesca nao seria melhor segregar por interface esses registros de dependencia por contextos ++ //em classes menores e aqui ser um ponto de acumulacao de dependencias ++ //alem do que no teste de integracao seria facilmente trocada por um mock, stub, fake, os blocos nao desejaveis de registros como foi feito no teste de integracao. ++ ++ public class RegistrarDependencias + { + public virtual void Registrar(IServiceCollection services, IConfiguration configuration) + { diff --git a/src/SME.SGP.IoC/SME.SGP.IoC.csproj b/src/SME.SGP.IoC/SME.SGP.IoC.csproj index 20a7a7cf5c..916b9e70fa 100644 --- a/src/SME.SGP.IoC/SME.SGP.IoC.csproj +++ b/src/SME.SGP.IoC/SME.SGP.IoC.csproj @@ -2,6 +2,7 @@ net5.0 + false diff --git a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacao.cs b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacao.cs index 369ccf2ade..3c879aac51 100644 --- a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacao.cs +++ b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacao.cs @@ -19,12 +19,12 @@ public EventoNotificacao(IServicoTelemetria servicoTelemetria, string nomeEvento this.nomeEvento = nomeEvento ?? throw new ArgumentNullException(nameof(nomeEvento)); } - public Task Enviar(IHubCallerClients clients, T mensagem) + public Task EnviarAsync(IHubCallerClients clients, T mensagem) { var transacao = servicoTelemetria.Iniciar($"EventoNotificacao.{nomeEvento}", "Hub"); try { - servicoTelemetria.RegistrarAsync(() => Disparar(clients, mensagem), "Hub", "EventoNotificacao", nomeEvento, JsonConvert.SerializeObject(mensagem)); + servicoTelemetria.RegistrarAsync(() => DispararAsync(clients, mensagem), "Hub", "EventoNotificacao", nomeEvento, JsonConvert.SerializeObject(mensagem)); } finally { @@ -33,7 +33,7 @@ public Task Enviar(IHubCallerClients clients, T mensagem) return Task.CompletedTask; } - protected virtual Task Disparar(IHubCallerClients clients,T mensagem) + protected virtual Task DispararAsync(IHubCallerClients clients,T mensagem) => throw new NotImplementedException("Disparo do evento de notificação não implementado"); } } diff --git a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoCriada.cs b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoCriada.cs index d51a9362f1..2c6b5c5a5a 100644 --- a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoCriada.cs +++ b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoCriada.cs @@ -7,12 +7,16 @@ namespace SME.SGP.Notificacoes.Hub { public class EventoNotificacaoCriada : EventoNotificacao, IEventoNotificacaoCriada { - public EventoNotificacaoCriada(IServicoTelemetria servicoTelemetria) + public EventoNotificacaoCriada(IServicoTelemetria servicoTelemetria) : base(servicoTelemetria, "Criada") { } - protected override Task Disparar(IHubCallerClients clients, MensagemCriacaoNotificacaoDto mensagem) - => clients.Usuario(mensagem.UsuarioRf)?.SendAsync("NotificacaoCriada", mensagem.Codigo, mensagem.Data, mensagem.Titulo, mensagem.Id); + protected override async Task DispararAsync(IHubCallerClients clients, MensagemCriacaoNotificacaoDto mensagem) + { + var iClientProxy = await clients.UsuarioAsync(mensagem.UsuarioRf); + await iClientProxy.SendAsync("NotificacaoCriada", mensagem.Codigo, mensagem.Data, + mensagem.Titulo, mensagem.Id); + } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoExcluida.cs b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoExcluida.cs index c3af4ba10e..2c5602ce5d 100644 --- a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoExcluida.cs +++ b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoExcluida.cs @@ -5,14 +5,18 @@ namespace SME.SGP.Notificacoes.Hub { - public class EventoNotificacaoExcluida : EventoNotificacao, IEventoNotificacaoExcluida + public class EventoNotificacaoExcluida : EventoNotificacao, + IEventoNotificacaoExcluida { - public EventoNotificacaoExcluida(IServicoTelemetria servicoTelemetria) + public EventoNotificacaoExcluida(IServicoTelemetria servicoTelemetria) : base(servicoTelemetria, "Excluida") { } - protected override Task Disparar(IHubCallerClients clients, MensagemExclusaoNotificacaoDto mensagem) - => clients.Usuario(mensagem.UsuarioRf).SendAsync("NotificacaoExcluida", mensagem.Codigo, mensagem.Status, mensagem.AnoAnterior); + protected override async Task DispararAsync(IHubCallerClients clients, MensagemExclusaoNotificacaoDto mensagem) + { + var iClientProxy = await clients.UsuarioAsync(mensagem.UsuarioRf); + await iClientProxy.SendAsync("NotificacaoExcluida", mensagem.Codigo, mensagem.Status, mensagem.AnoAnterior); + } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoLida.cs b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoLida.cs index f5779cf9f3..558ca3f1b3 100644 --- a/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoLida.cs +++ b/src/SME.SGP.Notificacoes.Hub/Eventos/EventoNotificacaoLida.cs @@ -12,7 +12,10 @@ public EventoNotificacaoLida(IServicoTelemetria servicoTelemetria) { } - protected override Task Disparar(IHubCallerClients clients, MensagemLeituraNotificacaoDto mensagem) - => clients.Usuario(mensagem.UsuarioRf).SendAsync("NotificacaoLida", mensagem.Codigo, mensagem.AnoAnterior); + protected override async Task DispararAsync(IHubCallerClients clients, MensagemLeituraNotificacaoDto mensagem) + { + var iClientProxy = await clients.UsuarioAsync(mensagem.UsuarioRf); + await iClientProxy.SendAsync("NotificacaoLida", mensagem.Codigo, mensagem.AnoAnterior); + } } -} +} \ No newline at end of file diff --git a/src/SME.SGP.Notificacoes.Hub/Eventos/Interface/IEventoNotificacao.cs b/src/SME.SGP.Notificacoes.Hub/Eventos/Interface/IEventoNotificacao.cs index 26bfc5cb4a..e9e4f495da 100644 --- a/src/SME.SGP.Notificacoes.Hub/Eventos/Interface/IEventoNotificacao.cs +++ b/src/SME.SGP.Notificacoes.Hub/Eventos/Interface/IEventoNotificacao.cs @@ -7,6 +7,6 @@ namespace SME.SGP.Notificacoes.Hub public interface IEventoNotificacao where TMensagem : MensagemNotificacaoDto { - Task Enviar(IHubCallerClients clients, TMensagem mensagem); + Task EnviarAsync(IHubCallerClients clients, TMensagem mensagem); } } diff --git a/src/SME.SGP.Notificacoes.Hub/Extencoes/EventoNotificacaoExtensions.cs b/src/SME.SGP.Notificacoes.Hub/Extencoes/EventoNotificacaoExtensions.cs index ebd29ab041..1aa274b51b 100644 --- a/src/SME.SGP.Notificacoes.Hub/Extencoes/EventoNotificacaoExtensions.cs +++ b/src/SME.SGP.Notificacoes.Hub/Extencoes/EventoNotificacaoExtensions.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.SignalR; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; namespace SME.SGP.Notificacoes.Hub { @@ -9,7 +10,10 @@ public static class EventoNotificacaoExtensions public static void Inicializa(IRepositorioUsuario repositorioUsuarioObj) => repositorioUsuario = repositorioUsuarioObj; - public static IClientProxy Usuario(this IHubCallerClients clients, string usuarioRf) - => clients.Client(repositorioUsuario.Obter(usuarioRf).Result); + public static async Task UsuarioAsync(this IHubCallerClients clients, string usuarioRf) + { + var usuario = await repositorioUsuario.Obter(usuarioRf); + return clients.Client(usuario); + } } } diff --git a/src/SME.SGP.Notificacoes.Hub/NotificacaoHub.cs b/src/SME.SGP.Notificacoes.Hub/NotificacaoHub.cs index 84dcc2a6cd..b14771a61e 100644 --- a/src/SME.SGP.Notificacoes.Hub/NotificacaoHub.cs +++ b/src/SME.SGP.Notificacoes.Hub/NotificacaoHub.cs @@ -60,13 +60,13 @@ public async Task SendMessage(string user, string message) } public Task Criada(MensagemCriacaoNotificacaoDto mensagem) - => eventoCriada.Enviar(Clients, mensagem); + => eventoCriada.EnviarAsync(Clients, mensagem); public Task Lida(MensagemLeituraNotificacaoDto mensagem) - => eventoLida.Enviar(Clients, mensagem); + => eventoLida.EnviarAsync(Clients, mensagem); public Task Excluida(MensagemExclusaoNotificacaoDto mensagem) - => eventoExcluida.Enviar(Clients, mensagem); + => eventoExcluida.EnviarAsync(Clients, mensagem); [Authorize("Token")] public object TokenProtected() diff --git a/src/SME.SGP.Worker.Rabbbit/Program.cs.rej b/src/SME.SGP.Worker.Rabbbit/Program.cs.rej new file mode 100644 index 0000000000..e26577ef36 --- /dev/null +++ b/src/SME.SGP.Worker.Rabbbit/Program.cs.rej @@ -0,0 +1,32 @@ +diff a/src/SME.SGP.Worker.Rabbbit/Program.cs b/src/SME.SGP.Worker.Rabbbit/Program.cs (rejected hunks) +@@ -2,9 +2,11 @@ + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.Hosting; + ++//Tem typo nessa solution Rabbbit com 3 b + namespace SME.SGP.Worker.Rabbbit + { +- public class Program { ++ public class Program ++ { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); +@@ -12,14 +14,11 @@ namespace SME.SGP.Worker.Rabbbit + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) +- .ConfigureAppConfiguration((hostingContext, config) => ++ .ConfigureAppConfiguration( config => + { + config.AddEnvironmentVariables(); + config.AddUserSecrets(); + }) +- .ConfigureWebHostDefaults(webBuilder => +- { +- webBuilder.UseStartup(); +- }); ++ .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } + } +\ No newline at end of file diff --git a/src/SME.SGP.Worker.Rabbbit/appsettings.json b/src/SME.SGP.Worker.Rabbbit/appsettings.json index def9159a7d..f2052a4588 100644 --- a/src/SME.SGP.Worker.Rabbbit/appsettings.json +++ b/src/SME.SGP.Worker.Rabbbit/appsettings.json @@ -4,5 +4,40 @@ "Default": "Warning" } }, + "ConnectionStrings": { + "SGP_Postgres": "Host=localhost;Port=5433;Database=sgp_db;Username=postgres;Password=postgres;Timeout=30;Pooling=True;Maximum Pool Size=20;Application Name=SGP_DB_RABBIT_WORKER", + "SGP_PostgresConsultas": "Host=localhost;Port=5433;Database=sgp_db;Username=postgres;Password=postgres;Timeout=30;Pooling=True;Maximum Pool Size=20;Application Name=SGP_DB_CONSULTA_RABBIT_WORKER", + "SGP_Redis": "" + }, + "ElasticApm": { + "ServerUrl": "http://localhost:8080/apm/" + }, + "Telemetria" : { + "ApplicationInsights": false, + "Apm": false + }, + "ConsumoFilas": { + "Padrao": true, + "Institucional": true, + "Pendencias": true, + "Aula": true, + "Frequencia": true, + "FechamentoConselho ": true + }, + "ConfiguracaoRabbit" : { + "Port" : 5673, + "HostName": "localhost", + "Password": "rabbitmq", + "UserName": "rabbitmq", + "Virtualhost": "dev" + }, + "JwtTokenSettings": { + "Audience": "ClientApp", + "ExpiresInMinutes": "3600", + "Issuer": "IPT", + "IssuerSigningKey": "f0d9ai0f908dsamufmud89saum0fud0sa89uf0d9s8af098dsa" + }, + "UrlApiEOL": "http://localhost:8080/eol/", + "UrlApiAE": "http://localhost:8080/ae/", "AllowedHosts": "*" } diff --git a/teste/SME.SGP.Aplicacao.Teste/CasosDeUso/EncaminhamentoAee/ObterEncaminhamentoPorIdUseCaseTeste.cs b/teste/SME.SGP.Aplicacao.Teste/CasosDeUso/EncaminhamentoAee/ObterEncaminhamentoPorIdUseCaseTeste.cs index 933ed24b53..8487442aea 100644 --- a/teste/SME.SGP.Aplicacao.Teste/CasosDeUso/EncaminhamentoAee/ObterEncaminhamentoPorIdUseCaseTeste.cs +++ b/teste/SME.SGP.Aplicacao.Teste/CasosDeUso/EncaminhamentoAee/ObterEncaminhamentoPorIdUseCaseTeste.cs @@ -155,6 +155,7 @@ public async Task Nao_Pode_Editar_Encaminhamento_CP() [Fact] public async Task Pode_Editar_Encaminhamento_Professor() { + //esses testes falham com NPE por falta de Ue na turma mediator.Setup(a => a.Send(It.IsAny(), It.IsAny())) .ReturnsAsync(new EncaminhamentoAEE() { diff --git a/teste/SME.SGP.Aplicacao.Teste/SME.SGP.Aplicacao.Teste.csproj b/teste/SME.SGP.Aplicacao.Teste/SME.SGP.Aplicacao.Teste.csproj index 63f7408ca6..328741c395 100644 --- a/teste/SME.SGP.Aplicacao.Teste/SME.SGP.Aplicacao.Teste.csproj +++ b/teste/SME.SGP.Aplicacao.Teste/SME.SGP.Aplicacao.Teste.csproj @@ -2,7 +2,7 @@ net5.0 - + true false diff --git a/teste/SME.SGP.Aplicacao.Teste/Servicos/ServicoAutenticacaoTeste.cs b/teste/SME.SGP.Aplicacao.Teste/Servicos/ServicoAutenticacaoTeste.cs index caeb254236..d50acbca3b 100644 --- a/teste/SME.SGP.Aplicacao.Teste/Servicos/ServicoAutenticacaoTeste.cs +++ b/teste/SME.SGP.Aplicacao.Teste/Servicos/ServicoAutenticacaoTeste.cs @@ -23,7 +23,7 @@ public ServicoAutenticacaoTeste() public async Task DeveAlterarSenhaComSucesso() { servicoEol.Setup(c => c.Autenticar(It.IsAny(), It.IsAny())) - .Returns(Task.FromResult(new AutenticacaoApiEolDto + .Returns(Task.FromResult(new AutenticacaoApiEolDto { CodigoRf = "123", Status = AutenticacaoStatusEol.Ok @@ -46,7 +46,7 @@ public async Task DeveAlterarSenhaComSucesso() public async Task NaoDeveAlterarSenhaComSenhaAnteriorReutilizada() { servicoEol.Setup(c => c.Autenticar(It.IsAny(), It.IsAny())) - .Returns(Task.FromResult(new AutenticacaoApiEolDto + .Returns(Task.FromResult(new AutenticacaoApiEolDto { CodigoRf = "123", Status = AutenticacaoStatusEol.Ok, @@ -71,7 +71,7 @@ public async Task NaoDeveAlterarSenhaComSenhaAnteriorReutilizada() public async Task NaoDeveAlterarSenhaComSenhaAtualIncorreta() { servicoEol.Setup(c => c.Autenticar(It.IsAny(), It.IsAny())) - .Returns(Task.FromResult(new AutenticacaoApiEolDto + .Returns(Task.FromResult(new AutenticacaoApiEolDto { CodigoRf = "123", Status = AutenticacaoStatusEol.SenhaPadrao, diff --git a/teste/SME.SGP.Dominio.Servicos.Teste/SME.SGP.Dominio.Servicos.Teste.csproj b/teste/SME.SGP.Dominio.Servicos.Teste/SME.SGP.Dominio.Servicos.Teste.csproj index a9d728b092..f940e15cdb 100644 --- a/teste/SME.SGP.Dominio.Servicos.Teste/SME.SGP.Dominio.Servicos.Teste.csproj +++ b/teste/SME.SGP.Dominio.Servicos.Teste/SME.SGP.Dominio.Servicos.Teste.csproj @@ -2,7 +2,7 @@ net5.0 - + true false diff --git a/teste/SME.SGP.Dominio.Teste/SME.SGP.Dominio.Teste.csproj b/teste/SME.SGP.Dominio.Teste/SME.SGP.Dominio.Teste.csproj index 62b40d2cb9..b6474f95cb 100644 --- a/teste/SME.SGP.Dominio.Teste/SME.SGP.Dominio.Teste.csproj +++ b/teste/SME.SGP.Dominio.Teste/SME.SGP.Dominio.Teste.csproj @@ -2,7 +2,7 @@ net5.0 - + true false diff --git a/teste/SME.SGP.TesteIntegracao/SME.SGP.TesteIntegracao.csproj b/teste/SME.SGP.TesteIntegracao/SME.SGP.TesteIntegracao.csproj index 0fa0b95c3d..6747f6d400 100644 --- a/teste/SME.SGP.TesteIntegracao/SME.SGP.TesteIntegracao.csproj +++ b/teste/SME.SGP.TesteIntegracao/SME.SGP.TesteIntegracao.csproj @@ -4,6 +4,7 @@ net5.0 false false + true @@ -27,8 +28,8 @@ - - + + diff --git a/teste/SME.SGP.TesteIntegracao/ServicosFakes/ServicoEOLFake.cs b/teste/SME.SGP.TesteIntegracao/ServicosFakes/ServicoEOLFake.cs index cc741b2b50..f7e38fa3c4 100644 --- a/teste/SME.SGP.TesteIntegracao/ServicosFakes/ServicoEOLFake.cs +++ b/teste/SME.SGP.TesteIntegracao/ServicosFakes/ServicoEOLFake.cs @@ -77,7 +77,7 @@ public Task AtribuirPerfil(string codigoRf, Guid perfil) throw new NotImplementedException(); } - public Task Autenticar(string login, string senha) + public Task Autenticar(string login, string senha) { throw new NotImplementedException(); } diff --git a/teste/SME.SGP.TesteIntegracao/ServicosFakes/TelemetriaFake.cs b/teste/SME.SGP.TesteIntegracao/ServicosFakes/TelemetriaFake.cs index e90cdc66e7..1a22b93519 100644 --- a/teste/SME.SGP.TesteIntegracao/ServicosFakes/TelemetriaFake.cs +++ b/teste/SME.SGP.TesteIntegracao/ServicosFakes/TelemetriaFake.cs @@ -12,7 +12,14 @@ public void Registrar(Action acao, string acaoNome, string telemetriaNome, strin acao(); } - public dynamic RegistrarComRetorno(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = "") + + public Task RegistrarComRetornoAsync(T1 t1, T2 t2, T3 t3, Func> acao, string acaoNome, string telemetriaNome, + string telemetriaValor, string parametros = "") + { + return acao(t1, t2, t3); + } + + public T RegistrarComRetorno(Func acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = "") { return acao(); } @@ -22,15 +29,15 @@ public Task RegistrarAsync(Func acao, string acaoNome, string telemetriaNo return acao(); } - public Task RegistrarComRetornoAsync(Func> acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = "") + public Task RegistrarComRetornoAsync(Func> acao, string acaoNome, string telemetriaNome, string telemetriaValor, string parametros = "") { return acao(); } - public ITransaction Iniciar(string nome, string tipo) + public ITransaction? Iniciar(string nome, string tipo) => null; - public void Finalizar(ITransaction transacao) + public void Finalizar(ITransaction? transacao) { } } diff --git a/teste/SME.SGP.TesteIntegracao/Setup/ConstrutorDeTabelas.cs b/teste/SME.SGP.TesteIntegracao/Setup/ConstrutorDeTabelas.cs index 552ac86825..fa0ba4f798 100644 --- a/teste/SME.SGP.TesteIntegracao/Setup/ConstrutorDeTabelas.cs +++ b/teste/SME.SGP.TesteIntegracao/Setup/ConstrutorDeTabelas.cs @@ -11,6 +11,7 @@ namespace SME.SGP.TesteIntegracao.Setup { public class ConstrutorDeTabelas { + //typo => Construir public void Contruir(NpgsqlConnection connection) { MontaBaseDados(connection); diff --git a/teste/SME.SGP.TesteIntegracao/Setup/InMemoryDatabase.cs b/teste/SME.SGP.TesteIntegracao/Setup/InMemoryDatabase.cs index 48a928fa26..c65db05482 100644 --- a/teste/SME.SGP.TesteIntegracao/Setup/InMemoryDatabase.cs +++ b/teste/SME.SGP.TesteIntegracao/Setup/InMemoryDatabase.cs @@ -11,6 +11,12 @@ namespace SME.SGP.TesteIntegracao.Setup { + //mesmo localmente e em memoria a execucao de testes de integracao estao extremamente lentos (pelo menos no meu pc) + //o ideal para os teste de integracao nesse caso era subir apenas um runner de postgres buildar o schema da base apenas uma vez + //e cada caso de testes trabalhar apenas com abertura de transacao e rollback no final para jogar todos os dados foras + + //fazendo profile a maior parte do tempo de execucao de cada teste de integracao fica em subir o runner gerar a base e limpar toda vez + //eu avaliaria outra estrategia de execucao de testes de integracao pois em pouco tempo essa estrategia nao escala e vai demorar cada vez mais conforme a suite de testes vao crescendo public class InMemoryDatabase : IDisposable { public NpgsqlConnection Conexao; @@ -19,6 +25,7 @@ public class InMemoryDatabase : IDisposable public InMemoryDatabase() { _postgresRunner = PostgresRunner.Start(); + AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); CriarConexaoEAbrir(); new ConstrutorDeTabelas().Contruir(Conexao); }