From f4b12b5d4d06ef963d1a4ce4ce4918e738a33bc8 Mon Sep 17 00:00:00 2001 From: kterva Date: Wed, 28 Feb 2024 15:50:15 -0300 Subject: [PATCH 01/15] =?UTF-8?q?se=20actualiza=20archivo=20de=20traducci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- translations/es_AR.mo | Bin 0 -> 9980 bytes translations/es_AR.po | 598 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 598 insertions(+) create mode 100644 translations/es_AR.mo create mode 100644 translations/es_AR.po diff --git a/translations/es_AR.mo b/translations/es_AR.mo new file mode 100644 index 0000000000000000000000000000000000000000..aeb86e6f99f874665c053307b194cb10266faf47 GIT binary patch literal 9980 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 ?)" +msgstr "un carácter especial (! @ # $ % & * < > ?)" + +#: components/password-strongness/texts.php:10 +msgid "um número" +msgstr "un número" + +#: views/auth/confirm-email.php:25 +msgid "Entrar na minha conta" +msgstr "Entrar a mi cuenta" + +#: views/panel/multiple-local-auth--my-account.php:19 +#: views/panel/multiple-local-auth--my-account.php:53 +msgid "Guardar alteraçoes" +msgstr "Guardar cambios" + +#: views/panel/multiple-local-auth--my-account.php:20 +msgid "Trocar e-mail" +msgstr "Cambiar contraseña" + +#: views/panel/multiple-local-auth--my-account.php:24 +msgid "Email" +msgstr "E-mail" + +#: views/panel/multiple-local-auth--my-account.php:30 +msgid "Trocar Senha" +msgstr "Cambiar contraseña" + +#: views/panel/multiple-local-auth--my-account.php:40 +msgid "Nova senha" +msgstr "Nueva contraseña" + +#: views/panel/multiple-local-auth--my-account.php:48 +msgid "Confirmar nova senha" +msgstr "Confirmar nueva contraseña" + +#: views/panel/multiple-local-auth--my-account.php:65 +msgid "Vincular conta com" +msgstr "Vincular cuenta con" + +#~ msgid "Email validado com sucesso" +#~ msgstr "Email validado con éxito" + +#~ msgid "Senha alterada com sucesso. Agora você pode fazer login" +#~ msgstr "Contraseña cambiada con éxito! Usted puede ingresar ahora" + +#~ msgid "Por favor, informe seu nome" +#~ msgstr "Por favor, ingrese su nombre" + +#~ msgid "Este endereço de email já está em uso" +#~ msgstr "Esta dirección de email ya está en uso" + +#~ msgid "Email alterado com sucesso" +#~ msgstr "Email cambiado con éxito" + +#~ msgid "Informe um email válido" +#~ msgstr "Ingrese un email válido" + +#~ msgid "Email e senha alterados com sucecsso" +#~ msgstr "Email y contraseña cambiados con éxito" + +#~ msgid "Senha alterada com sucesso" +#~ msgstr "Contraseña cambiada con éxito" + +#~ msgid "Email ou token inválidos" +#~ msgstr "Email o token incorrectos" + +#~ msgid "Senha alterada com sucesso! Você pode fazer login agora" +#~ msgstr "Contraseña cambiada con éxito! Ahora puede ingresar" + +#~ msgid "" +#~ "Sucesso: Um e-mail foi enviado com instruções para recuperação da senha." +#~ msgstr "" +#~ "Un mensaje de correo electrónico fue enviado con instrucciones para " +#~ "recuperar la contraseña." + +#~ msgid "CPF ou senha incorreta" +#~ msgstr "CI o contraseña incorrectas" + +#~ msgid "Sucesso: Um e-mail lhe foi enviado com detalhes sobre a plataforma " +#~ msgstr "" +#~ "Éxito: se le envió un correo electrónico con detalles sobre la plataforma " + +#~ msgid "Informação" +#~ msgstr "Información" + +#~ msgid "Clique aqui para entrar no sistema" +#~ msgstr "Haga clic aquí para ingresar al sistema" + +#~ msgid "Se você já possui uma conta no " +#~ msgstr "Si ya tiene una cuenta en " + +#~ msgid "esqueci a senha" +#~ msgstr "olvidé mi contraseña" + +#~ msgid "Ou conecte usando sua conta em" +#~ msgstr "O conéctese usando su cuenta en" + +#~ msgid "Ainda não possui uma conta?" +#~ msgstr "¿Aún no tienes una cuenta?" + +#~ msgid "Crie uma conta agora" +#~ msgstr "Cree una cuenta ahora" + +#~ msgid "Para recuperar sua senha, informe o e-mail utilizado no cadastro." +#~ msgstr "" +#~ "Para recuperar su contraseña, informe el e-mail utilizado en su registro." + +#~ msgid "Se ainda não possui conta no " +#~ msgstr "Si no tiene una cuenta en " + +#~ msgid "Criar Conta" +#~ msgstr "Crear cuenta" + +#~ msgid "Recuperar" +#~ msgstr "Recuperar" + +#~ msgid "" +#~ "Alguém solicitou a recuperação da senha utilizada em %s por este email.\n" +#~ "\n" +#~ "Para recuperá-la, acesse o link: %s. /n/n Se você não pediu a recuperação " +#~ "desta senha, apenas ignore esta mensagem." +#~ msgstr "" +#~ "Alguien solicitó la recuperación de contraseña utilizada en %s por este " +#~ "email.\n" +#~ "\n" +#~ "Para recuperarla, haga clic en el link: %s./n/n Si usted no pidió la " +#~ "recuperación de esta contraseña, ignore este mensaje." + +#~ msgid "Registrar-se" +#~ msgstr "Registrarse" + +#~ msgid "Redes Sociais" +#~ msgstr "Redes Sociales" + +#~ msgid "Utilize sua conta em outros serviços para autenticar-se" +#~ msgstr "Utilice su cuenta en otros servicios para autenticarse" + +#~ msgid "Clique para marcar/desmarcar este" +#~ msgstr "Haga clic para marcar/desmarcar este" + +#~ msgid "Este" +#~ msgstr "Este" + +#~ msgid "Para relacionar o selo ao" +#~ msgstr "Para relacionar el sello al" + +#~ msgid "teste pt" +#~ msgstr "teste es" From c192a2359073a8fcd23b0c703ebcb692595e94b1 Mon Sep 17 00:00:00 2001 From: Welington De Lima Olegario Date: Thu, 26 Dec 2024 15:31:49 -0300 Subject: [PATCH 02/15] =?UTF-8?q?faz=20valida=C3=A7=C3=A3o=20de=20obrigato?= =?UTF-8?q?riedade=20de=20cpf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Provider.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Provider.php b/Provider.php index a252964..957575e 100644 --- a/Provider.php +++ b/Provider.php @@ -39,6 +39,8 @@ function __construct ($config) { 'loginOnRegister' => env('AUTH_LOGIN_ON_REGISTER', false), 'enableLoginByCPF' => env('AUTH_LOGIN_BY_CPF', true), + 'requeridCpf' => env('AUTH_REQUIRED_CPF', true), + 'passwordMustHaveCapitalLetters' => env('AUTH_PASS_CAPITAL_LETTERS', true), 'passwordMustHaveLowercaseLetters' => env('AUTH_PASS_LOWERCASE_LETTERS', true), 'passwordMustHaveSpecialCharacters' => env('AUTH_PASS_SPECIAL_CHARS', true), @@ -549,8 +551,10 @@ function validateRegisterFields() { // validate cpf if(empty($cpf) || !$this->validateCPF($cpf)) { - array_push($errors['user']['cpf'], i::__('Por favor, informe um cpf válido.', 'multipleLocal')); - $hasErrors = true; + if($this->config['requeridCpf']){ + array_push($errors['user']['cpf'], i::__('Por favor, informe um cpf válido.', 'multipleLocal')); + $hasErrors = true; + } } $foundAgent = []; From e93e821d2766c7f17ba6da2910d603ed93ed7080 Mon Sep 17 00:00:00 2001 From: Rafa Chaves Date: Thu, 26 Dec 2024 22:10:37 -0300 Subject: [PATCH 03/15] =?UTF-8?q?corrige=20valida=C3=A7=C3=A3o=20de=20cpf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Provider.php | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/Provider.php b/Provider.php index 957575e..40ba15c 100644 --- a/Provider.php +++ b/Provider.php @@ -39,7 +39,7 @@ function __construct ($config) { 'loginOnRegister' => env('AUTH_LOGIN_ON_REGISTER', false), 'enableLoginByCPF' => env('AUTH_LOGIN_BY_CPF', true), - 'requeridCpf' => env('AUTH_REQUIRED_CPF', true), + 'requireCpf' => env('AUTH_REQUIRED_CPF', true), 'passwordMustHaveCapitalLetters' => env('AUTH_PASS_CAPITAL_LETTERS', true), 'passwordMustHaveLowercaseLetters' => env('AUTH_PASS_LOWERCASE_LETTERS', true), @@ -550,31 +550,32 @@ function validateRegisterFields() { if($config['enableLoginByCPF']) { // validate cpf - if(empty($cpf) || !$this->validateCPF($cpf)) { - if($this->config['requeridCpf']){ - array_push($errors['user']['cpf'], i::__('Por favor, informe um cpf válido.', 'multipleLocal')); - $hasErrors = true; - } + if($config['requireCpf'] && !$this->validateCPF($cpf)) { + array_push($errors['user']['cpf'], i::__('Por favor, informe um cpf válido.', 'multipleLocal')); + $hasErrors = true; } - $foundAgent = []; - $metadataFieldCpf = $this->getMetadataFieldCpfFromConfig(); - $_cpf = implode("','", [$cpf, preg_replace('/[^0-9]/i', '', $cpf)]); - $foundAgent = $conn->fetchAll("SELECT * FROM agent_meta WHERE key IN ('{$metadataFieldCpf}', 'cpf') AND value IN ('{$_cpf}')"); - - // creates an array with agents with status == 1, because the user can have, for example, 3 agents, but 2 have status == 0 - $existAgent = []; - if($foundAgent){ - foreach ($foundAgent as $agentMeta) { - if($agentMeta->owner->status >= 0) { - $existAgent[] = $agentMeta; + if($this->validateCPF($cpf)) { + $foundAgent = []; + $metadataFieldCpf = $this->getMetadataFieldCpfFromConfig(); + + $_cpf = implode("','", [$cpf, preg_replace('/[^0-9]/i', '', $cpf)]); + $foundAgent = $conn->fetchAll("SELECT * FROM agent_meta WHERE key IN ('{$metadataFieldCpf}', 'cpf') AND value IN ('{$_cpf}')"); + + // creates an array with agents with status == 1, because the user can have, for example, 3 agents, but 2 have status == 0 + $existAgent = []; + if($foundAgent){ + foreach ($foundAgent as $agentMeta) { + if($agentMeta->owner->status >= 0) { + $existAgent[] = $agentMeta; + } } } - } - if(count($existAgent) > 0) { - array_push($errors['user']['cpf'], i::__('Este CPF já esta em uso. Tente recuperar a sua senha.', 'multipleLocal')); - $hasErrors = true; + if(count($existAgent) > 0) { + array_push($errors['user']['cpf'], i::__('Este CPF já esta em uso. Tente recuperar a sua senha.', 'multipleLocal')); + $hasErrors = true; + } } } From 92e2ce5e8801178f5c948244ade23367f757491d Mon Sep 17 00:00:00 2001 From: erleibiazzio Date: Fri, 3 Jan 2025 09:20:12 -0300 Subject: [PATCH 04/15] =?UTF-8?q?Faz=20com=20que=20os=20cadastros=20criado?= =?UTF-8?q?s=20apartir=20da=20nova=20vers=C3=A3o=20do=20Mapas=20seja=20sem?= =?UTF-8?q?pre=20criado=20como=20Publicado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Provider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Provider.php b/Provider.php index 40ba15c..e668e95 100644 --- a/Provider.php +++ b/Provider.php @@ -65,7 +65,7 @@ function __construct ($config) { 'urlImageToUseInEmails' => env('AUTH_EMAIL_IMAGE'), 'urlTermsOfUse' => env('LINK_TERMOS', $app->createUrl('auth', 'termos-e-condicoes')), - 'statusCreateAgent' => env('STATUS_CREATE_AGENT', Agent::STATUS_DRAFT), + 'statusCreateAgent' => env('STATUS_CREATE_AGENT', Agent::STATUS_ENABLED), 'strategies' => [ 'Facebook' => [ 'visible' => env('AUTH_FACEBOOK_CLIENT_ID', false), From 7dc4137c8877b07bcb5e7957e064e0649c1fbb7c Mon Sep 17 00:00:00 2001 From: kterva Date: Mon, 7 Apr 2025 19:45:57 -0300 Subject: [PATCH 05/15] =?UTF-8?q?actualizaci=C3=B3n=20archivo=20espa=C3=B1?= =?UTF-8?q?ol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- translations/es_ES.mo | Bin 4010 -> 9584 bytes translations/es_ES.po | 576 +++++++++++++++++++++++++++++++++--------- 2 files changed, 452 insertions(+), 124 deletions(-) mode change 100644 => 100755 translations/es_ES.mo mode change 100644 => 100755 translations/es_ES.po diff --git a/translations/es_ES.mo b/translations/es_ES.mo old mode 100644 new mode 100755 index 4172e6ce4c0f00ddde5f53bf67f90f966f8f18cc..4e280680d8a67df62b03232c26fa55e22e1f663d GIT binary patch literal 9584 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 G%lselJY>@V literal 4010 zcmai$O^h5z8HPKM0NH>;%#TSRPzF0VkRI=@6UWTThh;O49CpddyK8ZQRk^2jww#`- zp}KpqBZR~OBy!0K1PG8EBqEbUfGos;14u(oTyld8KR3dOOAa6o@O;%hGi~okX{qO# z?yj!-{_1=CuSf6xZo=^>=f^nvcO}UReDxjtaD4xrN%C3v1NaB{Iy?qnxI0PS17Ct4 zgs;H+;qT$Q;2ZEB_$T-f{0lq*{|!F`ALikM@C=mk8}KsRh97{hz*F#d@F;wr2d;bI92k(7%lDrolgDjDp zfMWM&;5pcXvfekKy!QfJhd+e!-anwk?=2|fA0Rkq;WO};#PpkRnd@bYd;=QzFg(ko zJW95q*!g8B@wpB$EqSrw_n^e<$M6*V4U{csF4rK6s6%( z+q|=|u*tNOm&Z5KTtB9CW{ScnuX5|2>+)7dopz_4+A`|EXXBqMCrgY>-_BW>$(yyA zXk?r&lpQ!9SW%t~jVtuP3_HncQJYxQ)8Xy!gYk{r z_I;7`WJE}MA$X;|GVZ`)ZHz2=oJ6%wNk_?OiF?ehE^GUIp>%&}oh{;Gp->oJ*wS>8 zUh&n+WLEK%x@g>usdIfIHGY{iH+fW7$2TOt@;g+O_$vczgUz*(4ZcdAu5{>QU+p}v zQ%M)yo)1H#s$pYx<6E*37nK<3AxnDmrUOj zYRhL<+k&Tqn1PTMCfSmWSpQCnNlyz!>Ld=B`{=m39CygbPqdZ9dc1eZ_nGhsG4H7j__6N@Lywk4AJ~u-$}NEr(dYrlbxa(-w4(# zYPb&XWL0W-CpHM;P8MUjrGk7#nq+^5152Sai|MK~uCz=nQ5t_ojac3mB%7U0T}>Wi zZDX94-V+;+R`oVWHiN%vvNFBcPcNHLSns-OqsmJ=%8gpb>Rhc><^ICvv)k!fFuG(! z`jjqBS1m6tJ((^prAy0dak+cuY`S=6agl-PC39e9re@s2I%Sq_2knZSeHOZkJ8n?X zchYU6hpp=_w(s_~7B((!^k()fbru)sKH_bEJFb06_d}zs@5t? z8!Sy<`p(GqS#z!pQIlGR&}OD$WoogyN-L(I+U6oz(!H(AY~Q%Kid7lfWozP=aJBDF zBQ^5c3WT*i^qVAK17hoByI4@IBE;Sj^@` z!*Z5l6!YW^4W!Iww>9jT#;K^eXc^xp5*J6$yF=FKSABAXuvyywv-yGTk8h%EZHGj& zs4t6c(;BI@^g3lxi<_G(ZsS{1af`v5dWNu38}eS*+$sm9@ssdwyK4?jv_K05VuuYYJ1n%*njn%oYGnH^)6O ?)" +msgstr "un carácter especial (! @ # $ % & * < > ?)" + +#: components/password-strongness/texts.php:10 +msgid "um número" +msgstr "un número" + +#: views/auth/confirm-email.php:25 +msgid "Entrar na minha conta" +msgstr "Entrar a mi cuenta" + +#~ msgid "Guardar alteraçoes" +#~ msgstr "Guardar cambios" + +#~ msgid "Trocar e-mail" +#~ msgstr "Cambiar e-mail" + +#~ msgid "Email" +#~ msgstr "E-mail" + +#~ msgid "Trocar Senha" +#~ msgstr "Cambiar contraseña" + +#~ msgid "Nova senha" +#~ msgstr "Nueva contraseña" + +#~ msgid "Confirmar nova senha" +#~ msgstr "Confirme su nueva contraseña" + +#~ msgid "Vincular conta com" +#~ msgstr "Vincular cuenta con" + +#~ msgid "Email alterado com sucesso" +#~ msgstr "Email cambiado con éxito" + +#~ msgid "Informe um email válido" +#~ msgstr "Ingrese un email válido" + +#~ msgid "Email e senha alterados com sucecsso" +#~ msgstr "Email y contraseña cambiados con éxito" + +#~ msgid "Senha alterada com sucesso! Você pode fazer login agora" +#~ msgstr "Contraseña cambiada con éxito! Ahora puede ingresar" + +#~ msgid "" +#~ "Alguém solicitou a recuperação da senha utilizada em %s por este email.\n" +#~ "\n" +#~ "Para recuperá-la, acesse o link: %s. /n/n Se você não pediu a recuperação " +#~ "desta senha, apenas ignore esta mensagem." +#~ msgstr "" +#~ "Alguien solicitó la recuperación de contraseña utilizada en %s por este " +#~ "email.\n" +#~ "\n" +#~ "Para recuperarla, haga clic en el link: %s./n/n Si usted no pidió la " +#~ "recuperación de esta contraseña, ignore este mensaje." + +#~ msgid "" +#~ "Sucesso: Um e-mail foi enviado com instruções para recuperação da senha." +#~ msgstr "" +#~ "Un mensaje de correo electrónico fue enviado con instrucciones para " +#~ "recuperar la contraseña." + +#~ msgid "Para recuperar sua senha, informe o e-mail utilizado no cadastro." +#~ msgstr "" +#~ "Para recuperar su contraseña, informe el e-mail utilizado en su registro." + +#~ msgid "Registrar-se" +#~ msgstr "Registrarse" + +#~ msgid "Redes Sociais" +#~ msgstr "Redes Sociales" -#: views/panel/my-account.php:29 -msgid "Nova senha" -msgstr "Nueva contraseña" +#~ msgid "Utilize sua conta em outros serviços para autenticar-se" +#~ msgstr "Utilice su cuenta en otros servicios para autenticarse" -#: views/panel/my-account.php:32 -msgid "Confirmar nova senha" -msgstr "Confirmar nueva contraseña" +#~ msgid "Recuperar" +#~ msgstr "Recuperar" #~ msgid "Clique para marcar/desmarcar este" #~ msgstr "Haga clic para marcar/desmarcar este" From 96a6622b85bd317909e1714dd12ff55483b38bdf Mon Sep 17 00:00:00 2001 From: erleibiazzio Date: Mon, 18 Aug 2025 15:35:41 -0300 Subject: [PATCH 06/15] =?UTF-8?q?Implementa=20transaction=20no=20momento?= =?UTF-8?q?=20da=20cria=C3=A7=C3=A3o=20de=20usuario=20para=20evitar=20que?= =?UTF-8?q?=20fique=20sem=20agentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Provider.php | 164 +++++++++++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 71 deletions(-) diff --git a/Provider.php b/Provider.php index e668e95..b45c04f 100644 --- a/Provider.php +++ b/Provider.php @@ -1,11 +1,12 @@ getBaseUrl(); + if(!$user) { + $error['user']['createUser'] = i::__('Não foi possível criar o usuário. Fale com o administrador', 'multipleLocal'); + + return [ + 'success' => false, + 'errors' => $error + ]; + } + //ATENÇÃO !! Se for necessario "padronizar" os emails com header/footers, é necessario adapatar o 'mustache', e criar uma mini estrutura de pasta de emails em 'MultipleLocalAuth\views' $mustache = new \Mustache_Engine(); $site_name = $app->siteName; @@ -1429,8 +1439,9 @@ function authenticateUser(Entities\User $user) { $this->_setAuthenticatedUser($user); $_SESSION['multipleLocalUserId'] = $user->id; } - - protected function _createUser($response) { + + protected function _createUser($response) + { $app = App::i(); $app->disableAccessControl(); @@ -1438,89 +1449,100 @@ protected function _createUser($response) { $config = $this->_config; $user = null; - if($provider_class = $response['auth']['provider']."Strategy"){ - if(method_exists($provider_class, "newAccountCheck")){ - if($user = $provider_class::newAccountCheck($response)){ + if ($provider_class = $response['auth']['provider'] . "Strategy") { + if (method_exists($provider_class, "newAccountCheck")) { + if ($user = $provider_class::newAccountCheck($response)) { $agent = $user->profile; } } } - if(!$user){ - // cria o usuário - $user = new Entities\User; - $user->authProvider = $response['auth']['provider']; - $user->authUid = $response['auth']['uid']; - $user->email = $response['auth']['info']['email']; + if (!$user) { + try { + $app->em->beginTransaction(); + // cria o usuário + $user = new Entities\User; + $user->authProvider = $response['auth']['provider']; + $user->authUid = $response['auth']['uid']; + $user->email = $response['auth']['info']['email']; + + $app->em->persist($user); + + // cria um agente do tipo user profile para o usuário criado acima + $agent = new Entities\Agent($user); + + if (isset($response['auth']['info']['name'])) { + $agent->name = $response['auth']['info']['name']; + } elseif (isset($response['auth']['info']['first_name']) && isset($response['auth']['info']['last_name'])) { + $agent->name = $response['auth']['info']['first_name'] . ' ' . $response['auth']['info']['last_name']; + } elseif (isset($response['auth']['agentData']['name'])) { + $agent->name = $response['auth']['agentData']['name']; + } else { + $agent->name = ''; + } - $app->em->persist($user); - - // cria um agente do tipo user profile para o usuário criado acima - $agent = new Entities\Agent($user); + if (isset($response['auth']['info']['phone_number'])) { + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $agent->$metadataFieldPhone = $response['auth']['info']['phone_number']; + } - if(isset($response['auth']['info']['name'])){ - $agent->name = $response['auth']['info']['name']; - } - elseif(isset($response['auth']['info']['first_name']) && isset($response['auth']['info']['last_name'])){ - $agent->name = $response['auth']['info']['first_name'] . ' ' . $response['auth']['info']['last_name']; - } - elseif(isset($response['auth']['agentData']['name'])){ - $agent->name = $response['auth']['agentData']['name']; - } - else{ - $agent->name = ''; - } - - if(isset($response['auth']['info']['phone_number'])){ - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $agent->$metadataFieldPhone = $response['auth']['info']['phone_number']; - } + if (isset($response['auth']['agentData']['shortDescription'])) { + $agent->shortDescription = $response['auth']['agentData']['shortDescription']; + } - if(isset($response['auth']['agentData']['shortDescription'])){ - $agent->shortDescription = $response['auth']['agentData']['shortDescription']; - } + if (isset($response['auth']['agentData']['terms:area'])) { + $agent->terms['area'] = $response['auth']['agentData']['terms:area']; + } - if(isset($response['auth']['agentData']['terms:area'])){ - $agent->terms['area'] = $response['auth']['agentData']['terms:area']; - } + if (isset($response['auth']['info']['phone_number'])) { + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $agent->setMetadata($metadataFieldPhone, $response['auth']['info']['phone_number']); + } - if(isset($response['auth']['info']['phone_number'])){ - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $agent->setMetadata($metadataFieldPhone, $response['auth']['info']['phone_number']); - } + //cpf + $cpf = (isset($response['auth']['info']['cpf']) && $response['auth']['info']['cpf'] != "") ? $this->mask($response['auth']['info']['cpf'], '###.###.###-##') : null; + if (!empty($cpf)) { + $metadataFieldCpf = $this->getMetadataFieldCpfFromConfig(); + $agent->$metadataFieldCpf = $cpf; + } - //cpf - $cpf = (isset($response['auth']['info']['cpf']) && $response['auth']['info']['cpf'] != "") ? $this->mask($response['auth']['info']['cpf'],'###.###.###-##') : null; - if(!empty($cpf)){ - $metadataFieldCpf = $this->getMetadataFieldCpfFromConfig(); - $agent->$metadataFieldCpf = $cpf; - } + $agent->status = (int) $config['statusCreateAgent'] ?? '0'; + $agent->emailPrivado = $user->email; - $agent->status = (int) $config['statusCreateAgent'] ?? '0'; - $agent->emailPrivado = $user->email; - - $agent->save(); - $app->em->flush(); + $agent->save(); + $app->em->flush(); - $user->profile = $agent; - - $user->save(true); + if(!$agent) { + throw new Exception("Error create agent"); + } + + $user->profile = $agent; + + $user->save(true); + + $user->createPermissionsCacheForUsers([$user]); + $agent->createPermissionsCacheForUsers([$user]); + $app->em->commit(); - $user->createPermissionsCacheForUsers([$user]); - $agent->createPermissionsCacheForUsers([$user]); - } - - $app->enableAccessControl(); - $redirectUrl = $agent->status == Agent::STATUS_DRAFT ? $agent->editUrl : $this->getRedirectPath(); - $app->applyHookBoundTo($this, 'auth.createUser:redirectUrl', [&$redirectUrl]); + $app->enableAccessControl(); + $redirectUrl = $agent->status == Agent::STATUS_DRAFT ? $agent->editUrl : $this->getRedirectPath(); + $app->applyHookBoundTo($this, 'auth.createUser:redirectUrl', [&$redirectUrl]); - if ($redirectUrl) { - $this->_setRedirectPath($redirectUrl); + if ($redirectUrl) { + $this->_setRedirectPath($redirectUrl); + } + + return $user; + + } catch (\Throwable $th) { + $app->em->rollback(); + return null; + } } + - return $user; } function mask($val, $mask) { From cec3590ca94fe7c28cd4baf09f573972a94ced9b Mon Sep 17 00:00:00 2001 From: erleibiazzio Date: Mon, 18 Aug 2025 15:59:24 -0300 Subject: [PATCH 07/15] =?UTF-8?q?Faz=20melhorias=20no=20processo=20de=20cr?= =?UTF-8?q?ia=C3=A7=C3=A3o=20de=20usu=C3=A1rios=20para=20evitar=20que=20os?= =?UTF-8?q?=20mesmos=20fiquem=20sem=20agente=20relacionado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Provider.php | 147 ++++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 72 deletions(-) diff --git a/Provider.php b/Provider.php index b45c04f..b78ccfb 100644 --- a/Provider.php +++ b/Provider.php @@ -1444,6 +1444,9 @@ protected function _createUser($response) { $app = App::i(); + /** @var \MapasCulturais\Connection $conn */ + $conn = $app->em->getConnection(); + $app->disableAccessControl(); $config = $this->_config; @@ -1457,92 +1460,92 @@ protected function _createUser($response) } } - if (!$user) { - try { - $app->em->beginTransaction(); - // cria o usuário - $user = new Entities\User; - $user->authProvider = $response['auth']['provider']; - $user->authUid = $response['auth']['uid']; - $user->email = $response['auth']['info']['email']; - - $app->em->persist($user); - - // cria um agente do tipo user profile para o usuário criado acima - $agent = new Entities\Agent($user); - - if (isset($response['auth']['info']['name'])) { - $agent->name = $response['auth']['info']['name']; - } elseif (isset($response['auth']['info']['first_name']) && isset($response['auth']['info']['last_name'])) { - $agent->name = $response['auth']['info']['first_name'] . ' ' . $response['auth']['info']['last_name']; - } elseif (isset($response['auth']['agentData']['name'])) { - $agent->name = $response['auth']['agentData']['name']; - } else { - $agent->name = ''; - } + if ($user) { + return $user; + } - if (isset($response['auth']['info']['phone_number'])) { - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $agent->$metadataFieldPhone = $response['auth']['info']['phone_number']; - } + try { + $app->em->beginTransaction(); + // cria o usuário + $user = new Entities\User; + $user->authProvider = $response['auth']['provider']; + $user->authUid = $response['auth']['uid']; + $user->email = $response['auth']['info']['email']; + + $app->em->persist($user); + + // cria um agente do tipo user profile para o usuário criado acima + $agent = new Entities\Agent($user); + + if (isset($response['auth']['info']['name'])) { + $agent->name = $response['auth']['info']['name']; + } elseif (isset($response['auth']['info']['first_name']) && isset($response['auth']['info']['last_name'])) { + $agent->name = $response['auth']['info']['first_name'] . ' ' . $response['auth']['info']['last_name']; + } elseif (isset($response['auth']['agentData']['name'])) { + $agent->name = $response['auth']['agentData']['name']; + } else { + $agent->name = ''; + } - if (isset($response['auth']['agentData']['shortDescription'])) { - $agent->shortDescription = $response['auth']['agentData']['shortDescription']; - } + if (isset($response['auth']['info']['phone_number'])) { + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $agent->$metadataFieldPhone = $response['auth']['info']['phone_number']; + } - if (isset($response['auth']['agentData']['terms:area'])) { - $agent->terms['area'] = $response['auth']['agentData']['terms:area']; - } + if (isset($response['auth']['agentData']['shortDescription'])) { + $agent->shortDescription = $response['auth']['agentData']['shortDescription']; + } - if (isset($response['auth']['info']['phone_number'])) { - $metadataFieldPhone = $this->getMetadataFieldPhone(); - $agent->setMetadata($metadataFieldPhone, $response['auth']['info']['phone_number']); - } + if (isset($response['auth']['agentData']['terms:area'])) { + $agent->terms['area'] = $response['auth']['agentData']['terms:area']; + } - //cpf - $cpf = (isset($response['auth']['info']['cpf']) && $response['auth']['info']['cpf'] != "") ? $this->mask($response['auth']['info']['cpf'], '###.###.###-##') : null; - if (!empty($cpf)) { - $metadataFieldCpf = $this->getMetadataFieldCpfFromConfig(); - $agent->$metadataFieldCpf = $cpf; - } + if (isset($response['auth']['info']['phone_number'])) { + $metadataFieldPhone = $this->getMetadataFieldPhone(); + $agent->setMetadata($metadataFieldPhone, $response['auth']['info']['phone_number']); + } - $agent->status = (int) $config['statusCreateAgent'] ?? '0'; - $agent->emailPrivado = $user->email; + //cpf + $cpf = (isset($response['auth']['info']['cpf']) && $response['auth']['info']['cpf'] != "") ? $this->mask($response['auth']['info']['cpf'], '###.###.###-##') : null; + if (!empty($cpf)) { + $metadataFieldCpf = $this->getMetadataFieldCpfFromConfig(); + $agent->$metadataFieldCpf = $cpf; + } - $agent->save(); - $app->em->flush(); + $agent->status = (int) $config['statusCreateAgent'] ?? '0'; + $agent->emailPrivado = $user->email; - if(!$agent) { - throw new Exception("Error create agent"); - } - - $user->profile = $agent; - - $user->save(true); - - $user->createPermissionsCacheForUsers([$user]); - $agent->createPermissionsCacheForUsers([$user]); - $app->em->commit(); + $agent->save(true); + + $user->profile = $agent; + + $user->save(true); - $app->enableAccessControl(); - $redirectUrl = $agent->status == Agent::STATUS_DRAFT ? $agent->editUrl : $this->getRedirectPath(); - $app->applyHookBoundTo($this, 'auth.createUser:redirectUrl', [&$redirectUrl]); + if(!$conn->fetchScalar("SELECT profile_id FROM usr where id = {$user->id}")) { + throw new Exception("Error create agent"); + } + + $user->createPermissionsCacheForUsers([$user]); + $agent->createPermissionsCacheForUsers([$user]); - if ($redirectUrl) { - $this->_setRedirectPath($redirectUrl); - } + $app->em->commit(); - return $user; + $app->enableAccessControl(); + $redirectUrl = $agent->status == Agent::STATUS_DRAFT ? $agent->editUrl : $this->getRedirectPath(); + $app->applyHookBoundTo($this, 'auth.createUser:redirectUrl', [&$redirectUrl]); - } catch (\Throwable $th) { - $app->em->rollback(); - return null; + if ($redirectUrl) { + $this->_setRedirectPath($redirectUrl); } - } - + return $user; + + } catch (\Throwable $th) { + $app->em->rollback(); + return null; + } } function mask($val, $mask) { From 0dc3c180492e168ea9a75b506a49c00daa3145c3 Mon Sep 17 00:00:00 2001 From: erleibiazzio Date: Mon, 18 Aug 2025 16:03:44 -0300 Subject: [PATCH 08/15] Melhora mensagem de erro ao criar usuario --- Provider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Provider.php b/Provider.php index b78ccfb..8458410 100644 --- a/Provider.php +++ b/Provider.php @@ -1168,7 +1168,7 @@ function doRegister() { $baseUrl = $app->getBaseUrl(); if(!$user) { - $error['user']['createUser'] = i::__('Não foi possível criar o usuário. Fale com o administrador', 'multipleLocal'); + $error['user']['createUser'] = i::__('Não foi possível criar o usuário. Entre em contato com suporte', 'multipleLocal'); return [ 'success' => false, From 04dc78d52d50d197a938e08afd1df8b884daff55 Mon Sep 17 00:00:00 2001 From: Erlei Biazzio Date: Tue, 11 Nov 2025 15:11:35 -0300 Subject: [PATCH 09/15] =?UTF-8?q?Implementa=20autentica=C3=A7=C3=A3o=20com?= =?UTF-8?q?=20Decidim=20no=20ambiente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Decidim/DecidimStrategy.php | 245 ++++++++++++++++++++++++++++++++++ Plugin.php | 1 + Provider.php | 12 +- components/login/template.php | 3 + 4 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 Decidim/DecidimStrategy.php diff --git a/Decidim/DecidimStrategy.php b/Decidim/DecidimStrategy.php new file mode 100644 index 0000000..f298641 --- /dev/null +++ b/Decidim/DecidimStrategy.php @@ -0,0 +1,245 @@ + 'email'); + */ + public $defaults = ['redirect_uri' => '{complete_url_to_strategy}oauth2callback']; + + /** + * Auth request + */ + public function request(){ + $url = $this->strategy['auth_endpoint']; + $params = array( + 'client_id' => $this->strategy['client_id'], + 'client_secret' => $this->strategy['client_secret'], + 'redirect_uri' => $this->strategy['redirect_uri'], + 'response_type' => 'code', + 'scope' => $this->strategy['scope'] + ); + foreach ($this->optionals as $key){ + if (!empty($this->strategy[$key])) $params[$key] = $this->strategy[$key]; + } + + $this->clientGet($url, $params); + } + + /** + * Internal callback, after OAuth + */ + public function oauth2callback(){ + if (array_key_exists('code', $_GET) && !empty($_GET['code'])){ + $code = $_GET['code']; + $url = $this->strategy['token_endpoint']; + $params = array( + 'code' => $code, + 'client_id' => $this->strategy['client_id'], + 'client_secret' => $this->strategy['client_secret'], + 'redirect_uri' => $this->strategy['redirect_uri'], + 'grant_type' => 'authorization_code' + ); + $response = $this->serverPost($url, $params, null, $headers); + + $results = json_decode($response); + + if (!empty($results) && !empty($results->access_token)){ + + $userinfo = $this->userinfo($results->access_token); + + + $this->auth = array( + 'uid' => $userinfo['id'], + 'info' => array(), + 'credentials' => array( + 'token' => $results->access_token, + 'expires' => date('c', time() + $results->expires_in) + ), + 'raw' => $userinfo + ); + + + if (!empty($results->refresh_token)) + { + $this->auth['credentials']['refresh_token'] = $results->refresh_token; + } + + $this->mapProfile($userinfo, 'name', 'info.name'); + $this->mapProfile($userinfo, 'email', 'info.email'); + $this->mapProfile($userinfo, 'given_name', 'info.first_name'); + $this->mapProfile($userinfo, 'family_name', 'info.last_name'); + $this->mapProfile($userinfo, 'picture', 'info.image'); + + $this->callback(); + } + else{ + $error = array( + 'code' => 'access_token_error', + 'message' => 'Failed when attempting to obtain access token', + 'raw' => array( + 'response' => $response, + 'headers' => $headers + ) + ); + $this->errorCallback($error); + } + } + else{ + $error = array( + 'code' => 'oauth2callback_error', + 'raw' => $_GET + ); + + $this->errorCallback($error); + } + } + + /** + * Queries Google API for user info + * + * @param string $access_token + * @return array Parsed JSON results + */ + private function userinfo($access_token){ + $options = [ + 'http' => [ + 'header' => "Authorization: Bearer {$access_token}\r\nAccept: application/json", + 'ignore_errors' => true, + 'method' => 'GET' + ] + ]; + + // Alterado para passar os headers corretamente e manter o uso do serverGet + $userinfo = $this->serverGet($this->strategy['userinfo_endpoint'], [], $options, $responseHeaders); + // $userinfo = $this->serverGet($this->strategy['userinfo_endpoint'], array('access_token' => $access_token), null, $headers); + + if (!empty($userinfo)){ + return $this->recursiveGetObjectVars(json_decode($userinfo)); + } + else{ + $error = array( + 'code' => 'userinfo_error', + 'message' => 'Failed when attempting to query for user information', + 'raw' => array( + 'response' => $userinfo, + 'headers' => $headers + ) + ); + $this->errorCallback($error); + } + } + + /** + * Atualiza dados do usuário autenticado a partir da resposta da estratégia Decidim. + * + * @param \MapasCulturais\Entities\User $user Usuário autenticado que terá os dados atualizados. + * @param array $response Resposta completa retornada pela estratégia Decidim. + * @return void + */ + public static function verifyUpdateData($user, $response) + { + $app = App::i(); + + $userinfo = (object) $response['auth']['raw']; + + self::getFile($user->profile, $userinfo->image); + } + + /** + * Faz o download de uma imagem remota e salva como avatar para o agente informado. + * + * @param \MapasCulturais\Entities\Agent $owner Agente proprietário do avatar. + * @param string|null $url URL da imagem a ser baixada. + * @return void + */ + public static function getFile($owner, $url){ + + $curl = new Curl; + $curl->get($url); + $curl->close(); + $response = $curl->response; + + if(mb_strpos($response, 'não encontrada')){ + return; + } + + $tmp = tempnam("/tmp", ""); + $handle = fopen($tmp, "wb"); + fwrite($handle,$response); + fclose($handle); + + // Confere MIME e extensões aceitas + if (!self::checkFileType($tmp)) { + unlink($tmp); + return; + } + + $mime = mime_content_type($tmp) ?: 'application/octet-stream'; + + $extension = match ($mime) { + 'image/jpeg', 'image/jpg' => 'jpg', + 'image/png' => 'png', + 'image/gif' => 'gif', + 'image/webp' => 'webp', + default => null, + }; + + if(!$extension) { + unlink($tmp); + return; + } + + $basename = sprintf('%s.%s', md5(uniqid('', true)), $extension); + + $class_name = $owner->fileClassName; + + $file = new $class_name([ + "name" => $basename, + "type" => $mime, + "tmp_name" => $tmp, + "error" => 0, + "size" => filesize($tmp) + ]); + + $file->group = "avatar"; + $file->owner = $owner; + $file->save(true); + + if(is_file($tmp)) { + unlink($tmp); + } + } + + /** + * Verifica se um arquivo temporário corresponde a um formato de imagem suportado. + * + * @param string $filename Caminho absoluto do arquivo temporário a ser verificado. + * @return bool Retorna true se o arquivo for uma imagem suportada; caso contrário, false. + */ + public static function checkFileType($filename) + { + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mimetype = finfo_file($finfo, $filename); + if ($mimetype == 'image/jpg' || $mimetype == 'image/jpeg' || $mimetype == 'image/gif' || $mimetype == 'image/png') { + $is_image = true; + } else { + $is_image = false; + } + + return $is_image; + } + +} diff --git a/Plugin.php b/Plugin.php index 9ad2020..94e4a8d 100644 --- a/Plugin.php +++ b/Plugin.php @@ -9,6 +9,7 @@ include('LinkedIn/LinkedInStrategy.php'); include('LoginCidadao/LoginCidadaoStrategy.php'); include('GovBr/GovBrStrategy.php'); +include('Decidim/DecidimStrategy.php'); class Plugin extends \MapasCulturais\Plugin { diff --git a/Provider.php b/Provider.php index 8458410..885ef1b 100644 --- a/Provider.php +++ b/Provider.php @@ -112,6 +112,16 @@ function __construct ($config) { 'applySealId' => env('AUTH_GOV_BR_APPLY_SEAL_ID', null), 'menssagem_authenticated' => env('AUTH_GOV_BR_MENSSAGEM_AUTHENTICATED','Usuário já se autenticou pelo GovBr'), 'dic_agent_fields_update' => env('AUTH_GOV_BR_DICT_AGENT_FIELDS_UPDATE','[]') + ], + 'decidim' => [ + 'visible' => env('AUTH_DECIDIM_CLIENT_ID', false), + 'client_id' => env('AUTH_DECIDIM_CLIENT_ID', null), + 'client_secret' => env('AUTH_DECIDIM_CLIENT_SECRET', null), + 'redirect_uri' => env('AUTH_DECIDIM_REDIRECT_URI', null), + 'scope' => env('AUTH_DECIDIM_SCOPE', null), + 'auth_endpoint' => env('AUTH_DECIDIM_AUTH_ENDPOINT', null), + 'token_endpoint' => env('AUTH_DECIDIM_TOKEN_ENDPOINT', null), + 'userinfo_endpoint' => env('AUTH_DECIDIM_USERINFO_ENDPOINT', null), ] ] ]; @@ -1311,7 +1321,7 @@ protected function _validateResponse(){ // verifica se a resposta é um erro if (array_key_exists('error', $response)) { - $app->flash('auth error', 'Opauth returns error auth response'); + // $app->flash('auth error', 'Opauth returns error auth response'); } else { /** * Auth response validation diff --git a/components/login/template.php b/components/login/template.php index 1ddbe24..ddc3f4e 100644 --- a/components/login/template.php +++ b/components/login/template.php @@ -60,6 +60,9 @@ + From 4819b390514d200232c42aa041abd80e594af205 Mon Sep 17 00:00:00 2001 From: Erlei Biazzio Date: Tue, 11 Nov 2025 15:17:39 -0300 Subject: [PATCH 10/15] =?UTF-8?q?Atualiza=20Documenta=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 240 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 136 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index e910937..3a4a7db 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,149 @@ # MultipleLocalAuth -Plugin que implementa um método de autenticação local para o Mapas Culturais, em conjunto com login via redes sociais. - -## Instalação e Configuração - -Faça download ou clone do plugin e coloque a pasta MultipleLocalAuth no pasta dos plugins do Mapas Culturais. - -No arquivo de configuração do Mapas Culturais, config.php, você deve: - -1. Ativar o plugin -2. Configurar MultipleLocalAuth como seu Provider de autenticação -3. Configurar as chaves das redes sociais - -Para ativar o plugin, adicione na sua array de Plugins: -``` +Plugin de autenticação para o Mapas Culturais que combina login local (e-mail e CPF) com múltiplas estratégias sociais (Google, Facebook, LinkedIn, Twitter, Login Cidadão, Gov.br, Decidim etc.), regras de senha configuráveis e proteção contra abuso. + +## Recursos principais +- Cadastro local com fluxo multi-etapas, validação de CPF e aceite de termos LGPD. +- Login por e-mail ou CPF, com limite de tentativas e bloqueio temporário automático. +- Confirmação de conta por e-mail, recuperação de senha com token e troca de senha pelo painel. +- Integração com Google reCAPTCHA v2 (visível) para login, cadastro e recuperação. +- Autenticação social via Opauth (Google, Facebook, LinkedIn, Twitter, Login Cidadão, Gov.br, Decidim) com mapeamento automático de dados. +- Atualização opcional de avatar e metadados ao autenticar via Gov.br ou Decidim. +- Componentes Vue (`login`, `create-account`, `change-password`, `password-strongness`) prontos para a Base V2. + +## Instalação +1. Faça download/clonagem deste repositório e coloque a pasta `MultipleLocalAuth` em `protected/application/plugins/` do Mapas Culturais. +2. Garanta que o módulo `LGPD` esteja habilitado, pois o cadastro consome `LGPD::acceptTerms`. +3. Instale dependências do Mapas Culturais (este plugin não adiciona dependências externas além das que já vêm com o core/opauth). + +## Configuração +Edite `config.php` do Mapas Culturais: + +```php 'plugins' => [ // ... outros plugins 'MultipleLocalAuth' => [ 'namespace' => 'MultipleLocalAuth', ], ], -``` - -Para definir este plugin como seu método de autenticação, defina a configuraço *auth.provider*: -``` -'auth.provider' => '\MultipleLocalAuth\Provider', -``` -Finalmente, defina a configuração *auth.config* para definir as estratégias utilizadas e as chaves dos serviços: +'auth.provider' => \MultipleLocalAuth\Provider::class, -``` 'auth.config' => [ - - //SALT da senha do usuario - 'salt' => 'LT_SECURITY_SALT_SECURITY_SALT_SECURITY_SALT_SECURITY_SALT_SECU', - - 'timeout' => '24 hours', - - //url de suporte por chat para ser enviado nos emails - 'urlSupportChat' => 'https://www.google.com', - - //url de suporte por email para ser enviado nos emails - 'urlSupportEmail' => 'https://www.google.com', - - //url do site de suporte para ser enviado nos emails - 'urlSupportSite' => 'https://www.google.com', - - //url dos termos de uso para utilizar a plataforma - 'urlTermsOfUse' => 'https://www.google.com', - - //url de uma imagem para ser enviado como plano de fundo nos emails - 'urlImageToUseInEmails' => 'https://mapacultural.juazeiro.ce.gov.br/files/project/1561/file/963893/blob-3d922310b0a1eb1c16791a06023f56df.png', - - //Habilita registro e login através do CPF - 'enableLoginByCPF' => true, - - //apelido do metadata que será salvo o campo CPF - 'metadataFieldCPF' => 'documento', - - //Regra para saber se o usuario deve ou não confiar o email para poder utilizar o sistema - 'userMustConfirmEmailToUseTheSystem' => false, - - //Regra de força de senha - Ter no mínimo 1 letra maiúscula - 'passwordMustHaveCapitalLetters' => true, - - //Regra de força de senha - Ter no mínimo 1 letra minúscula - 'passwordMustHaveLowercaseLetters' => true, - - //Regra de força de senha - Ter no mínimo 1 caractere especial - 'passwordMustHaveSpecialCharacters' => true, - - //Regra de força de senha - Ter no mínimo 1 caractere numérico - 'passwordMustHaveNumbers' => true, - - //Regra de força de senha - Ter no mínimo n caracteres - 'minimumPasswordLength' => 6, - - //Configuração de GOOGLE Recaptcha - 'google-recaptcha-secret' => '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe', - 'google-recaptcha-sitekey' => '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', - - //Tempo da sessao do usuario em segundos - 'sessionTime' => 7200, - - //Limite de tentativas não sucedidas de login antes de bloquear o usuario por X minutos - 'numberloginAttemp' => '5', - - //Tempo de bloqueio do usuario em segundos, após romper limites de tentativas não sucedidas - 'timeBlockedloginAttemp' => '900', - - //Estratégias de autenticação - 'strategies' => [ - 'Facebook' => array( - 'app_id' => 'SUA_APP_ID', - 'app_secret' => 'SUA_APP_SECRET', - 'scope' => 'email' - ), - 'LinkedIn' => array( - 'api_key' => 'SUA_API_KEY', - 'secret_key' => 'SUA_SECRET_KEY', - 'redirect_uri' => URL_DO_SEU_SITE . '/autenticacao/linkedin/oauth2callback', - 'scope' => 'r_emailaddress' - ), - 'Google' => array( - 'client_id' => 'SEU_CLIENT_ID', - 'client_secret' => 'SEU_CLIENT_SECRET', - 'redirect_uri' => URL_DO_SEU_SITE . '/autenticacao/google/oauth2callback', - 'scope' => 'email' - ), - 'Twitter' => array( - 'app_id' => 'SUA_APP_ID', - 'app_secret' => 'SUA_APP_SECRET', - ), - ] + // ajuste conforme as tabelas abaixo ], ``` + +### Opções gerais +| Chave | Descrição | Padrão | Variável `.env` | +| --- | --- | --- | --- | +| `salt` | Salt usado pelo Opauth | `env('AUTH_SALT')` | `AUTH_SALT` | +| `timeout` | Tempo máximo da sessão OAuth | `24 hours` | `AUTH_TIMEOUT` | +| `loginOnRegister` | Autenticar automaticamente após cadastro | `false` | `AUTH_LOGIN_ON_REGISTER` | +| `enableLoginByCPF` | Permite login/cadastro via CPF | `true` | `AUTH_LOGIN_BY_CPF` | +| `requireCpf` | Exige CPF no cadastro | `true` | `AUTH_REQUIRED_CPF` | +| `metadataFieldCPF` | Campo de metadata que armazena CPF | `documento` | `AUTH_METADATA_FIELD_DOCUMENT` | +| `metadataFieldPhone` | Campo de metadata que armazena telefone | `telefone1` | `AUTH_METADATA_FIELD_PHONE` | +| `userMustConfirmEmailToUseTheSystem` | Exige validação por e-mail antes do uso | `false` | `AUTH_EMAIL_CONFIRMATION` | +| `sessionTime` | Duração da sessão (segundos) | `7200` | `AUTH_SESSION_TIME` | +| `statusCreateAgent` | Status default do agente criado | `Agent::STATUS_ENABLED` | `STATUS_CREATE_AGENT` | + +### Comunicação e suporte +| Chave | Uso | Padrão | Variável `.env` | +| --- | --- | --- | --- | +| `urlSupportChat` | Link incluído nos e-mails | `''` | `AUTH_SUPPORT_CHAT` | +| `urlSupportEmail` | Link de contato por e-mail | `''` | `AUTH_SUPPORT_EMAIL` | +| `urlSupportSite` | URL geral de suporte | `''` | `AUTH_SUPPORT_SITE` | +| `textSupportSite` | Texto exibido com o link | `''` | `AUTH_SUPPORT_TEXT` | +| `urlImageToUseInEmails` | Imagem de fundo para e-mails | `null` | `AUTH_EMAIL_IMAGE` | +| `urlTermsOfUse` | URL dos termos de uso | `auth/termos-e-condicoes` | `LINK_TERMOS` | + +### Regras de senha +| Chave | Descrição | Padrão | Variável `.env` | +| --- | --- | --- | --- | +| `passwordMustHaveCapitalLetters` | Exigir letra maiúscula | `true` | `AUTH_PASS_CAPITAL_LETTERS` | +| `passwordMustHaveLowercaseLetters` | Exigir letra minúscula | `true` | `AUTH_PASS_LOWERCASE_LETTERS` | +| `passwordMustHaveSpecialCharacters` | Exigir caractere especial | `true` | `AUTH_PASS_SPECIAL_CHARS` | +| `passwordMustHaveNumbers` | Exigir número | `true` | `AUTH_PASS_NUMBERS` | +| `minimumPasswordLength` | Tamanho mínimo da senha | `6` | `AUTH_PASS_LENGTH` | + +### Proteção contra abuso +| Chave | Descrição | Padrão | Variável `.env` | +| --- | --- | --- | --- | +| `numberloginAttemp` | Tentativas antes do bloqueio | `5` | `AUTH_NUMBER_ATTEMPTS` | +| `timeBlockedloginAttemp` | Tempo de bloqueio (segundos) | `900` | `AUTH_BLOCK_TIME` | + +### Google reCAPTCHA v2 +| Chave | Descrição | Padrão | +| --- | --- | --- | +| `google-recaptcha-secret` | Secret da integração | `env('GOOGLE_RECAPTCHA_SECRET')` | +| `google-recaptcha-sitekey` | Site key usada no front | `env('GOOGLE_RECAPTCHA_SITEKEY')` | + +Se ambas as chaves estiverem ausentes, o captcha é desativado. + +### Estratégias de autenticação +Cada estratégia pode receber `visible => bool` para controlar se o botão aparece na interface. + +#### Google +- `client_id`, `client_secret`, `redirect_uri`, `scope` (`email profile` por padrão). + +#### Facebook +- `app_id`, `app_secret`, `scope` (default `email`). + +#### LinkedIn +- `api_key`, `secret_key`, `redirect_uri`, `scope` (default `r_emailaddress`). + +#### Twitter +- `app_id`, `app_secret`. (Fluxo direto do Opauth). + +#### Login Cidadão +- `client_id`, `client_secret`, `auth_endpoint`, `token_endpoint`, `userinfo_endpoint`, `redirect_uri`, `scope`. + +#### Gov.br +- `client_id`, `client_secret`, `scope`, `auth_endpoint`, `token_endpoint`, `userinfo_endpoint`, `redirect_uri`. +- `state_salt`, `code_verifier`, `code_challenge`, `code_challenge_method` para PKCE. +- `applySealId` (opcional): selo aplicado ao agente autenticado. +- `dic_agent_fields_update`: mapa de campos que podem ser atualizados automaticamente (JSON, ex: `{"name": "full_name"}`). +- `menssagem_authenticated`: mensagem exibida quando o usuário já autenticou via Gov.br. + +#### Decidim +- `client_id`, `client_secret`, `auth_endpoint`, `token_endpoint`, `userinfo_endpoint`, `redirect_uri`, `scope`. +- Atualiza automaticamente avatar do agente com a imagem fornecida. + +Você pode adicionar ou remover estratégias conforme necessário; qualquer estratégia Opauth disponível no diretório do plugin pode ser configurada. + +## Fluxos e endpoints +- `GET auth.index`: renderiza o componente de login. +- `GET auth.register`: fluxo multi-etapas de cadastro. +- `GET auth.recover`: formulário para solicitar redefinição de senha. +- `GET auth.confirma-email`: valida o token enviado por e-mail e ativa a conta. +- `POST auth.validate`: validação assíncrona do primeiro passo do cadastro. +- `POST auth.register`: criação de conta (gera agente, token de verificação e envia e-mail). +- `POST auth.login`: autenticação local (com bloqueio por tentativas via metadata). +- `POST auth.recover` / `POST auth.dorecover`: solicitação e conclusão da recuperação de senha. +- `POST auth.changepassword` / `POST auth.newpassword`: alteração de senha logado ou via token. +- `POST auth.adminchangeuseremail` / `POST auth.adminchangeuserpassword`: rotinas administrativas (acessos protegidos). +- `GET auth.passwordvalidationinfos`: retorna as regras de senha atuais para o front-end. + +## Componentes que acompanham o plugin +- `components/login`: formulário de login com reCAPTCHA, recuperação de senha e botões sociais. +- `components/create-account`: esteira de cadastro com validações de senha, CPF e aceite de termos LGPD. +- `components/change-password`: formulário para troca de senha no painel. +- `components/password-strongness`: barra de força da senha, reutilizada em cadastro e redefinição. + +Todos os componentes carregam textos a partir de `components/*/texts.php`, permitindo tradução personalizada. + +## Personalização +- E-mails: templates Mustache em `views/auth/email-to-validate-account.html` e `views/auth/email-resert-password.html`. Você pode copiar/adaptar mantendo as variáveis esperadas. +- Telas: `views/auth/*.php` rendem os componentes Vue; é possível sobrescrever esses arquivos em um tema customizado. +- Estilos: CSS compilado em `assets/css/plugin-MultiplLocalAuth.css`. O SCSS-fonte está em `assets-src/sass/`. +- Traduções: arquivos `.po` em `translations/` (domínio `multipleLocal`). + +## Boas práticas +- Configure o cron/serviço de fila de e-mail do Mapas Culturais antes de habilitar a confirmação por e-mail. +- Ajuste `metadataFieldCPF`/`metadataFieldPhone` para corresponder ao schema de metadados do seu deployment. +- Revise as mensagens carregadas via `textSupportSite`, `urlSupport*` para garantir contato adequado ao usuário. +- Gere URLs de callback das estratégias sociais com HTTPS e defina-as nos painéis dos provedores. + +--- +Mantemos este documento atualizado a partir do código-fonte do plugin. Contribuições são bem-vindas! \ No newline at end of file From 1afa3542129da8e8882ff3266d3fb42f37ab0675 Mon Sep 17 00:00:00 2001 From: Erlei Biazzio Date: Tue, 11 Nov 2025 15:33:08 -0300 Subject: [PATCH 11/15] =?UTF-8?q?Ajusta=20para=20poder=20alterar=20o=20tex?= =?UTF-8?q?to=20do=20bot=C3=A3o=20do=20Decidim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Provider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Provider.php b/Provider.php index 885ef1b..2326d2d 100644 --- a/Provider.php +++ b/Provider.php @@ -122,6 +122,7 @@ function __construct ($config) { 'auth_endpoint' => env('AUTH_DECIDIM_AUTH_ENDPOINT', null), 'token_endpoint' => env('AUTH_DECIDIM_TOKEN_ENDPOINT', null), 'userinfo_endpoint' => env('AUTH_DECIDIM_USERINFO_ENDPOINT', null), + 'button_text' => env('AUTH_DECIDIM_BUTTON_TEXT', 'Entrar com Decidim'), ] ] ]; From fddd14fc49c27a0f49ced8a6bc0f7f53b3a15ff0 Mon Sep 17 00:00:00 2001 From: Erlei Biazzio Date: Tue, 11 Nov 2025 15:48:26 -0300 Subject: [PATCH 12/15] =?UTF-8?q?Ajusta=20template=20para=20mostrar=20corr?= =?UTF-8?q?etamente=20o=20texto=20do=20bot=C3=A3o=20Decidim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/login/template.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/login/template.php b/components/login/template.php index ddc3f4e..b1d6f80 100644 --- a/components/login/template.php +++ b/components/login/template.php @@ -61,7 +61,8 @@ From e67cdca27bddadc2b21039e06a8bc7594b681e61 Mon Sep 17 00:00:00 2001 From: israelmelo Date: Fri, 28 Nov 2025 17:04:33 -0300 Subject: [PATCH 13/15] Adiciona flush no salvamento do user --- Provider.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Provider.php b/Provider.php index 2326d2d..33fc07e 100644 --- a/Provider.php +++ b/Provider.php @@ -1221,7 +1221,8 @@ function doRegister() { $user->{self::$tokenVerifyAccountMetadata} = $token; $user->{self::$accountIsActiveMetadata} = '0'; $app->modules['LGPD']->acceptTerms($app->request->post('slugs'), $user); - $user->save(); + $user->save(true); + $app->enableAccessControl(); From 050ff3d63d94e9446e2b7007764274ada7a980e3 Mon Sep 17 00:00:00 2001 From: erleibiazzio Date: Tue, 6 Jan 2026 09:47:57 -0300 Subject: [PATCH 14/15] =?UTF-8?q?Ajusta=20plugin=20para=20que=20solicite?= =?UTF-8?q?=20as=20taxonomias=20obrigat=C3=B3rias=20no=20momento=20da=20cr?= =?UTF-8?q?ia=C3=A7=C3=A3o=20da=20conta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/create-account/script.js | 11 +++++++++++ components/create-account/template.php | 9 ++++++++- components/create-account/texts.php | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/components/create-account/script.js b/components/create-account/script.js index bc83102..a7e4d8c 100644 --- a/components/create-account/script.js +++ b/components/create-account/script.js @@ -300,6 +300,17 @@ app.component('create-account', { if (this.agent.terms.area.length == 0) { errors.agent.push(__('Área de atuação obrigatória', 'create-account')); } + + // Validação de campos obrigatórios das taxonomias + Object.keys($TAXONOMIES).forEach(taxonomy => { + const t = $TAXONOMIES[taxonomy]; + if (t.required && t.entities.includes('MapasCulturais\\Entities\\Agent')) { + if(this.agent.terms[taxonomy].length == 0) { + errors.agent.push(`${t.description} ${__('required', 'create-account')}`); + } + } + }); + if (errors.agent.length > 0) { this.throwErrors(errors); return false; diff --git a/components/create-account/template.php b/components/create-account/template.php index a776a64..3f125fa 100644 --- a/components/create-account/template.php +++ b/components/create-account/template.php @@ -15,6 +15,8 @@ mc-stepper password-strongness '); + +$taxonomies = $app->getRegisteredTaxonomies("MapasCulturais\Entities\Agent"); ?>