├── cache └── .gitkeep ├── app ├── src │ ├── Persistence │ │ └── .gitkeep │ ├── Model │ │ ├── Instancia.php │ │ ├── Jornada.php │ │ ├── Desafio.php │ │ ├── Trilha.php │ │ ├── Usuario.php │ │ ├── IDAO.php │ │ ├── UsuarioOldDAO.php │ │ ├── DesafioDAO.php │ │ ├── TrilhaDAO.php │ │ ├── JornadaDAO.php │ │ ├── UsuarioOld.php │ │ ├── UsuarioDAO.php │ │ └── DAO.php │ ├── Lib │ │ └── PLib.php │ ├── Command │ │ ├── Command.php │ │ └── MauticImportar.php │ ├── Middleware │ │ └── AuthMiddleware.php │ ├── View │ │ ├── 404.twig │ │ ├── desafio │ │ │ └── home.twig │ │ ├── admin │ │ │ ├── usuarioOld │ │ │ │ ├── lista.twig │ │ │ │ └── form.twig │ │ │ ├── usuario │ │ │ │ ├── lista.twig │ │ │ │ └── form.twig │ │ │ ├── desafio │ │ │ │ ├── lista.twig │ │ │ │ └── form.twig │ │ │ ├── jornada │ │ │ │ ├── lista.twig │ │ │ │ └── form.twig │ │ │ ├── trilha │ │ │ │ ├── lista.twig │ │ │ │ └── form.twig │ │ │ ├── sistema │ │ │ │ └── index.twig │ │ │ └── layout.twig │ │ └── site │ │ │ ├── layout.twig │ │ │ └── home │ │ │ └── home.twig │ └── Controller │ │ ├── SistemaController.php │ │ ├── SiteController.php │ │ ├── TesteController.php │ │ ├── AdminController.php │ │ ├── UsuarioController.php │ │ ├── UsuarioOldController.php │ │ ├── DesafioController.php │ │ ├── JornadaController.php │ │ ├── CronController.php │ │ └── TrilhaController.php ├── settings.template.php ├── routes.php └── dependencies.php ├── public ├── js │ └── site.js ├── .htaccess ├── favicon │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── apple-touch-icon.png │ ├── android-chrome-144x144.png │ ├── browserconfig.xml │ ├── site.webmanifest │ └── safari-pinned-tab.svg ├── images │ ├── logo-home.jpg │ ├── question.jpg │ ├── edtech-guia.png │ ├── apoiamos │ │ ├── code.png │ │ ├── scratch.png │ │ ├── codegirl.png │ │ ├── djangogirls.png │ │ ├── freecodecamp.jpg │ │ ├── girlswhocode.png │ │ ├── hackerspaces.png │ │ ├── khanacademy.jpg │ │ ├── programaria.png │ │ ├── technovation.png │ │ ├── womenwhocode.png │ │ ├── hackerspacemga.jpg │ │ ├── logo-programae.png │ │ ├── womentechmakers.jpg │ │ ├── eupossoprogramar.jpg │ │ ├── womenintechnology.png │ │ └── mulheresnacomputacao.jpg │ ├── bg-educadores.jpg │ ├── broken_robot.jpg │ ├── google-tools.png │ ├── soraia-avatar.jpg │ ├── soraia-badges.jpg │ ├── certificado-khan.jpg │ ├── certificado-codeorg.jpg │ ├── google-ferramentas.png │ ├── atualizacao-professor.jpg │ ├── logo-horizontal-200w.png │ ├── certificado-code-academy.jpg │ └── certificado-duolingo.svg ├── favicon_package_v0.16.zip ├── css │ ├── site.css │ └── admin.css ├── mautic_test_contact.php ├── validate.php ├── mautic_test.php ├── index.php └── mautic_get_token.php ├── docs ├── ModeloBanco.mwb └── ModeloBanco.mwb.bak ├── docker.md ├── .gitignore ├── composer.json ├── ISSUE_TEMPLATE.md ├── CONTRIBUTING.md ├── migrations └── 2018-07-01.sql └── readme.md /cache/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/Persistence/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/js/site.js: -------------------------------------------------------------------------------- 1 | console.log("site.js carregado!"); -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteRule ^ index.php [QSA,L] -------------------------------------------------------------------------------- /docs/ModeloBanco.mwb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/docs/ModeloBanco.mwb -------------------------------------------------------------------------------- /docs/ModeloBanco.mwb.bak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/docs/ModeloBanco.mwb.bak -------------------------------------------------------------------------------- /public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/favicon/favicon.ico -------------------------------------------------------------------------------- /public/images/logo-home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/logo-home.jpg -------------------------------------------------------------------------------- /public/images/question.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/question.jpg -------------------------------------------------------------------------------- /public/images/edtech-guia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/edtech-guia.png -------------------------------------------------------------------------------- /public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon_package_v0.16.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/favicon_package_v0.16.zip -------------------------------------------------------------------------------- /public/images/apoiamos/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/code.png -------------------------------------------------------------------------------- /public/images/bg-educadores.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/bg-educadores.jpg -------------------------------------------------------------------------------- /public/images/broken_robot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/broken_robot.jpg -------------------------------------------------------------------------------- /public/images/google-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/google-tools.png -------------------------------------------------------------------------------- /public/images/soraia-avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/soraia-avatar.jpg -------------------------------------------------------------------------------- /public/images/soraia-badges.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/soraia-badges.jpg -------------------------------------------------------------------------------- /public/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /public/images/apoiamos/scratch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/scratch.png -------------------------------------------------------------------------------- /public/images/certificado-khan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/certificado-khan.jpg -------------------------------------------------------------------------------- /public/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /public/images/apoiamos/codegirl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/codegirl.png -------------------------------------------------------------------------------- /public/images/certificado-codeorg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/certificado-codeorg.jpg -------------------------------------------------------------------------------- /public/images/google-ferramentas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/google-ferramentas.png -------------------------------------------------------------------------------- /docker.md: -------------------------------------------------------------------------------- 1 | WIP - Work in Progress 2 | 3 | docker exec -it mine-apache-php7 /bin/bash -c "cd /var/www/desafio/; php ./public/index.php MauticImportar" -------------------------------------------------------------------------------- /public/images/apoiamos/djangogirls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/djangogirls.png -------------------------------------------------------------------------------- /public/images/apoiamos/freecodecamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/freecodecamp.jpg -------------------------------------------------------------------------------- /public/images/apoiamos/girlswhocode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/girlswhocode.png -------------------------------------------------------------------------------- /public/images/apoiamos/hackerspaces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/hackerspaces.png -------------------------------------------------------------------------------- /public/images/apoiamos/khanacademy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/khanacademy.jpg -------------------------------------------------------------------------------- /public/images/apoiamos/programaria.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/programaria.png -------------------------------------------------------------------------------- /public/images/apoiamos/technovation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/technovation.png -------------------------------------------------------------------------------- /public/images/apoiamos/womenwhocode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/womenwhocode.png -------------------------------------------------------------------------------- /public/images/atualizacao-professor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/atualizacao-professor.jpg -------------------------------------------------------------------------------- /public/images/logo-horizontal-200w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/logo-horizontal-200w.png -------------------------------------------------------------------------------- /public/favicon/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/favicon/android-chrome-144x144.png -------------------------------------------------------------------------------- /public/images/apoiamos/hackerspacemga.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/hackerspacemga.jpg -------------------------------------------------------------------------------- /public/images/apoiamos/logo-programae.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/logo-programae.png -------------------------------------------------------------------------------- /public/images/apoiamos/womentechmakers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/womentechmakers.jpg -------------------------------------------------------------------------------- /public/images/certificado-code-academy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/certificado-code-academy.jpg -------------------------------------------------------------------------------- /public/images/apoiamos/eupossoprogramar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/eupossoprogramar.jpg -------------------------------------------------------------------------------- /public/images/apoiamos/womenintechnology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/womenintechnology.png -------------------------------------------------------------------------------- /public/images/apoiamos/mulheresnacomputacao.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DesafioDoCodigo/desafio-do-codigo/HEAD/public/images/apoiamos/mulheresnacomputacao.jpg -------------------------------------------------------------------------------- /app/src/Model/Instancia.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/Lib/PLib.php: -------------------------------------------------------------------------------- 1 | container = $container; 16 | } 17 | 18 | public function __invoke( Request $request, Response $response, callable $next) { 19 | 20 | if(!$login) 21 | return $response->withRedirect($this->container->get('router')->pathFor('login')); 22 | 23 | 24 | return $next($request, $response); 25 | 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/View/404.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Desafio... 404! 5 | 6 | 8 | 9 | 10 |
11 |

Página não encontrada

12 |

13 | Este endereço não chega a lugar nenhum...
14 | ...acho que devemos considerar isso um grande problema. 15 |

16 | 17 | 18 |
-------------------------------------------------------------------------------- /app/src/View/desafio/home.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Desafio do Código 5 | 6 | 8 | 9 | 10 |

Home do Desafio do Código

11 | Logar quando não autenticado. 12 |

13 | 14 |

Testes de template

15 |

Nome do usuário

16 | {{ nome }} 17 |

18 |

Sexo

19 | {{ user.sexo }} 20 |

21 | 22 | 23 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Para criar uma issue, informe as três informações abaixo, e apague este parágrafo aqui. Marque um X onde estiver [ ] para marcar como verdadeiro. 2 | 3 | ## O que deseja criar 4 | ! Deixe apenas um ítem 5 | - Report de bug 6 | - Implementar novo código 7 | - Solicitação de novo recurso 8 | - Melhoria significativa 9 | - Discussão 10 | 11 | 12 | ## Resultado esperado 13 | Diga o que espera que aconteça... 14 | 15 | ## Como isso é hoje? 16 | Explique se já existe algo disso, como funciona (ou não) e porque não está bom. 17 | 18 | ## Detalhes do que deve ser feito 19 | Diga o que fazer (detalhando o máximo possível), se preferir já inclua no formato de tarefas. 20 | 21 | ## Estimativa 22 | Estimadas X horas - PP/P/M/G 23 | -------------------------------------------------------------------------------- /app/src/Model/Jornada.php: -------------------------------------------------------------------------------- 1 | getWhere("id_jornada=" . $this->id); 31 | 32 | return $trilhas; 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/View/admin/usuarioOld/lista.twig: -------------------------------------------------------------------------------- 1 |

Usuários Codewars

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% for registro in registros %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% endfor %} 21 | 22 |
NomeLoginAcessoRegistro
{{ registro.nome }}{{ registro.login }}{{ registro.last_login }}{{ registro.DataAdd }}
23 | 24 | Omitindo milhares de usuários da exibição. Esta rota é apenas pra saber que está tudo conectado mesmo... :)

25 | -------------------------------------------------------------------------------- /app/src/Model/Desafio.php: -------------------------------------------------------------------------------- 1 | findById($this->id_trilha); 29 | } 30 | /** 31 | * Obtem o objeto da Jornada deste desafio 32 | * @return Jornada 33 | */ 34 | public function getJornada() 35 | { 36 | return JornadaDAO::getInstance()->findById($this->getTrilha()->id_jornada); 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/View/admin/usuario/lista.twig: -------------------------------------------------------------------------------- 1 |

Usuários

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% for registro in registros %} 14 | 15 | 16 | 17 | 18 | 22 | 23 | {% endfor %} 24 | 25 |
NomeLoginTipo 
{{ registro.nome }}{{ registro.login }}{{ registro._tipo }} 19 | Editar 20 | Excluir 21 |
26 | 27 | Incluir 28 | 29 | -------------------------------------------------------------------------------- /app/src/Model/Trilha.php: -------------------------------------------------------------------------------- 1 | findById($this->id_jornada); 29 | } 30 | 31 | public function getDesafios() 32 | { 33 | // Obter DAO de Desafio 34 | /* @var $daoDesafio DesafioDAO */ 35 | $daoDesafio = DesafioDAO::getInstance(); 36 | 37 | // Obter desafios 38 | $desafios = $daoDesafio->getWhere("id_trilha=" . $this->id); 39 | 40 | return $desafios; 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/View/admin/desafio/lista.twig: -------------------------------------------------------------------------------- 1 |

{{ trilha.titulo }}

2 |

Desafios

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for registro in registros %} 15 | 16 | 17 | 18 | 19 | 23 | 24 | {% endfor %} 25 | 26 |
DesafioOrdemAtivo 
{{ registro.titulo }}{{ registro.ordem }}{{ registro.ativo ? "Sim" : "Não"}} 20 | Editar 21 | Excluir 22 |
27 | 28 | Incluir Desafio 29 | 30 | -------------------------------------------------------------------------------- /app/src/View/admin/jornada/lista.twig: -------------------------------------------------------------------------------- 1 |

Jornadas

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% for registro in registros %} 13 | 14 | 15 | 16 | 19 | 23 | 24 | {% endfor %} 25 | 26 |
JornadaAtiva 
{{ registro.titulo }}{{ registro.ativa ? "Sim" }} 17 | Trilhas 18 | 20 | Editar 21 | Excluir 22 |
27 | 28 | Incluir Jornada 29 | 30 | -------------------------------------------------------------------------------- /app/src/View/admin/trilha/lista.twig: -------------------------------------------------------------------------------- 1 |

{{ jornada.titulo }}

2 |

Trilhas

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% for registro in registros %} 14 | 15 | 16 | 17 | 20 | 24 | 25 | {% endfor %} 26 | 27 |
TrilhaAtiva 
{{ registro.titulo }}{{ registro.ativa ? "Sim" }} 18 | Desafios 19 | 21 | Editar 22 | Excluir 23 |
28 | 29 | Incluir Trilha 30 | 31 | -------------------------------------------------------------------------------- /public/mautic_test_contact.php: -------------------------------------------------------------------------------- 1 | '', 18 | 'userName' => '', 19 | 'password' => '' 20 | ); 21 | 22 | // Initiate the auth object specifying to use BasicAuth 23 | $initAuth = new ApiAuth(); 24 | $auth = $initAuth->newAuth($settings, 'OAuth'); 25 | 26 | echo "

Auth

"; 27 | vd($auth); 28 | 29 | $api = new MauticApi(); 30 | $contactApi = $api->newApi('contacts', $auth, $settings['baseUrl']); 31 | 32 | $response = $contactApi->getList(null,1000,1); 33 | echo "

contactApi response

"; 34 | vd($response); 35 | $totalContacts = $response['total']; 36 | echo "

totalContacts

"; 37 | vd($totalContacts); 38 | 39 | echo "

contactApi response

"; 40 | $response = $contactApi->get(1); 41 | vd($response); 42 | 43 | echo "

contact

"; 44 | $contact = $response[$contactApi->itemName()]; 45 | vd($contact); 46 | 47 | function vd($var){ 48 | echo "
";
49 |     print_r($var);
50 |     echo "
"; 51 | } -------------------------------------------------------------------------------- /public/favicon/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 14 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/Controller/SistemaController.php: -------------------------------------------------------------------------------- 1 | container->dbOld; 21 | $userDao = UsuarioOldDAO::getInstance($conexaoOld); 22 | // Usuários 23 | $total = $userDao->getCount(); 24 | 25 | // Mautic 26 | $migrados = $userDao->countWhere("mauticId>0"); 27 | $emailInvalido = $userDao->countWhere("mauticId=-1"); 28 | $falhaMautic = $userDao->countWhere("mauticId=0"); 29 | 30 | // Construir array de dados 31 | $dados = Array(); 32 | $dados['usuarios']=['total'=>$total, 'emailInvalido'=>$emailInvalido]; 33 | $dados['mautic']=[ 34 | 'migrados'=>$migrados, 35 | "migradosPercentual"=>round(($migrados / ($total -$emailInvalido) ) * 100, 2) 36 | ]; 37 | 38 | $content = $this->fetchView("admin/sistema/index.twig", ["dados" => $dados]); 39 | return $this->renderLayout($response, $content); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /app/src/Controller/SiteController.php: -------------------------------------------------------------------------------- 1 | container = $container; 17 | } 18 | 19 | public function indexAction(Request $request, Response $response, $args) 20 | { 21 | // Renderizar lista 22 | $content = $this->fetchView("site/home/home.twig"); 23 | 24 | return $this->renderLayout($response, $content); 25 | 26 | } 27 | 28 | protected function renderLayout($response, $content = null, $data = null) 29 | { 30 | // Obter isso de uma configuração 31 | $data['siteTitle'] = "Desafio do Código"; 32 | // $data['slug'] = $this->slug; 33 | $data['content'] = $content; 34 | return $this->container->view->render($response, '/site/layout.twig', $data); 35 | } 36 | 37 | /** 38 | * Renderiza uma view e retorna o html final 39 | * @param $view 40 | * @param null $data 41 | * @return mixedR 42 | */ 43 | protected function fetchView($view, $data = null) 44 | { 45 | if (!$data) 46 | $data = array(); 47 | return $this->container->view->fetch($view, $data); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/View/admin/usuario/form.twig: -------------------------------------------------------------------------------- 1 |
{{ registro ? "Editar Usuário" : "Incluir Usuário" }}
2 |

{{ registro.titulo }}

3 | 4 | {% if error %} 5 | 8 | {% endif %} 9 | 10 |
11 |
12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 |
20 | 21 |
22 | 23 | 24 |
25 | 26 |
27 | 28 | 33 |
34 | 35 | 36 |
-------------------------------------------------------------------------------- /app/src/Model/Usuario.php: -------------------------------------------------------------------------------- 1 | calcularCampos(); 31 | } 32 | 33 | 34 | public function __set($name, $value) 35 | { 36 | echo "Setando campo não declarado ($name) na classe ".self::class; 37 | echo $name . " -> " . $value . "
"; 38 | // Validar alguns campos antes de salvar 39 | if ($name == 'email') { 40 | // Validar 41 | $value = filter_var($value, FILTER_SANITIZE_EMAIL); 42 | } 43 | 44 | $this->$value = $value; 45 | } 46 | 47 | private function calcularCampos() 48 | { 49 | // Calcular campo _tipo 50 | if ($this->tipo) { 51 | if ($this->tipo == "admin") 52 | $this->_tipo = "Administrador"; 53 | if ($this->tipo == "tutor") 54 | $this->_tipo = "Tutor"; 55 | if ($this->tipo == "usuario") 56 | $this->_tipo = "Usuário"; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/View/admin/sistema/index.twig: -------------------------------------------------------------------------------- 1 |

Sistema

2 | 3 |
4 |
5 |
6 |
7 |
Usuários Codewars
8 |
9 |
    10 |
  • 11 | Total
    12 |

    {{ dados.usuarios.total|number_format(0, ',', '.') }}

    13 |
  • 14 |
  • 15 | Emails Inválidos
    16 |

    {{ dados.usuarios.emailInvalido|number_format(0, ',', '.') }}

    17 |
  • 18 |
19 | 20 |
21 |
22 |
23 |
24 |
25 |
Mautic
26 |
27 |
    28 |
  • 29 | Contatos importados
    30 |

    {{ dados.mautic.migrados|number_format(0, ',', '.') }} 31 | {{ dados.mautic.migradosPercentual }}% 32 |

    33 | Para importar
    34 |

    {{ (dados.usuarios.total-dados.usuarios.emailInvalido-dados.mautic.migrados)|number_format(0, ',', '.') }}

    35 |
  • 36 |
37 | 38 |
39 |
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /public/validate.php: -------------------------------------------------------------------------------- 1 | disposable == true; 24 | } 25 | 26 | 27 | $valids = []; 28 | $invalids = []; 29 | 30 | $i = 0; 31 | foreach ($users as $domain) { 32 | if ($domain['count'] <= 1) 33 | break; 34 | 35 | $domain = $domain['domain']; 36 | // var_dump($domain); 37 | 38 | if (filter_var("tiago@" . $domain, FILTER_VALIDATE_EMAIL) == false) { 39 | $invalids[] = "'$domain'"; 40 | break; 41 | } 42 | 43 | // if (domain_exists($domain)) { 44 | // // echo($domain. ' - valid
'); 45 | // $valids[] = "'$domain'"; 46 | // } else { 47 | // // echo($domain. ' - invalid
'); 48 | // $invalids[] = "'$domain'"; 49 | // } 50 | 51 | if (isDisposable($domain)) { 52 | // echo "$domain disposable
"; 53 | $invalids[] = "'$domain'"; 54 | } 55 | 56 | $i++; 57 | 58 | // if ($i > 50) 59 | // break; 60 | } 61 | 62 | $invalids = join(",", $invalids); 63 | echo "update users set email_invalido_saldo=COALESCE(email_invalido_saldo,0)-1 where substring_index(email, '@', -1) in (" . $invalids . ")

"; 64 | -------------------------------------------------------------------------------- /public/mautic_test.php: -------------------------------------------------------------------------------- 1 | $settings['settings']['mautic']['baseUrl'], 17 | 'callback' => $settings['settings']['mautic']['callback'], 18 | 'clientKey' => $settings['settings']['mautic']['clientKey'], 19 | 'clientSecret' => $settings['settings']['mautic']['clientSecret'], 20 | // To be get 21 | 'accessToken' => isset($_SESSION['accessToken']) ? $_SESSION['accessToken'] : $container['settings']['mautic']['accessToken'], 22 | 'refreshToken' => isset($_SESSION['refreshToken']) ? $_SESSION['refreshToken'] : $container['settings']['mautic']['refreshToken'], 23 | 'expires' => isset($_SESSION['expires']) ? $_SESSION['expires'] : $container['settings']['mautic']['expires'], 24 | 'version' => 'OAuth2' 25 | ); 26 | 27 | try { 28 | // Initiate the auth object 29 | $initAuth = new ApiAuth(); 30 | $auth = $initAuth->newAuth($settings); 31 | $api = new MauticApi(); 32 | $contactApi = $api->newApi('contacts', $auth, $settings['baseUrl']); 33 | 34 | $response = $contactApi->getList(); 35 | echo "

Result

"; 36 | if (isset($response['total'])) { 37 | echo "MauticTest: Sucess accessing API"; 38 | } else { 39 | echo "MauticTest: Failed to access API."; 40 | echo "
";
41 |         print_r($response);
42 |     }
43 | 
44 |     echo "

Settings

"; 45 | echo "
";
46 |     var_dump($settings);
47 | 
48 | } catch (Exception $e) {
49 |     // Do Error handling
50 |     var_dump($e);
51 | }


--------------------------------------------------------------------------------
/app/src/View/admin/jornada/form.twig:
--------------------------------------------------------------------------------
 1 | 
{{ registro ? "Editar Jornada" : "Incluir Jornada" }}
2 |

{{ registro.titulo }}

3 | 4 | 5 | {% if error %} 6 | 9 | {% endif %} 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 | -------------------------------------------------------------------------------- /app/src/View/admin/usuarioOld/form.twig: -------------------------------------------------------------------------------- 1 |
{{ registro ? "Editar Jornada" : "Incluir Jornada" }}
2 |

{{ registro.titulo }}

3 | 4 | 5 | {% if error %} 6 | 9 | {% endif %} 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 | -------------------------------------------------------------------------------- /app/src/View/admin/trilha/form.twig: -------------------------------------------------------------------------------- 1 |
{{ registro ? "Ediar Trilha" : "Incluir Trilha" }}
2 |

{{ jornada.titulo }}

3 | 4 | {% if error %} 5 | 8 | {% endif %} 9 | 10 | 11 |
12 | 13 |
14 | 15 | 17 |
18 |
19 | 20 | 22 |
23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 32 | 33 |
34 | 35 | 36 |
37 | 38 | -------------------------------------------------------------------------------- /app/src/View/admin/desafio/form.twig: -------------------------------------------------------------------------------- 1 |
{{ registro ? "Ediar Desafio" : "Incluir Desafio" }}
2 |

{{ trilha.titulo }}

3 | 4 | {% if error %} 5 | 8 | {% endif %} 9 | 10 | 11 |
12 | 13 |
14 | 15 | 17 |
18 | 19 |
20 | 21 | 23 |
24 | 25 |
26 | 27 | 28 |
29 | 30 |
31 | 33 | 34 |
35 | 36 | 37 |
38 | 39 | -------------------------------------------------------------------------------- /app/src/Controller/TesteController.php: -------------------------------------------------------------------------------- 1 | container = $container; 19 | } 20 | 21 | public function indexAction(Request $request, Response $response, $args) 22 | { 23 | // Teste de conexão e DAO 24 | echo "

Conectar ao banco

"; 25 | $conexao = $this->container->db; 26 | $userDao = UsuarioOldDAO::getInstance($conexao); 27 | var_dump($conexao); 28 | 29 | $data = []; 30 | 31 | echo "

Inserir usuário

"; 32 | 33 | // Teste de insert 34 | $user = new UsuarioOld(); 35 | $user->nome = '_Tiago_'; 36 | $user->login = '_Tiago_'; 37 | $user->sexo = '_Tiago_'; 38 | $user->senha = '_Tiago_'; 39 | $user->email = '_Tiago_'; 40 | $user->ip = '_Tiago_'; 41 | $user->autoriza = true; 42 | $user->serie = '_Tiago_'; 43 | $user->cidade = '_Tiago_'; 44 | $user->escola = '_Tiago_'; 45 | $user->nasc = '_Tiago_'; 46 | $user->telefone = '_Tiago_'; 47 | $user->tipo = '_Tiago_'; 48 | $user->m_last = '_Tiago_'; 49 | $user = $userDao->insert($user, true); 50 | var_dump($user); 51 | 52 | echo "

Atualizar usuário

"; 53 | 54 | // Teste de update 55 | $user->nome = '_Tiago updated_'; 56 | $user->login = '_Tiagoupdates_'; 57 | $user->sexo = 'muito'; 58 | $user = $userDao->update($user); 59 | var_dump($user); 60 | 61 | echo "

Apgar usuário

"; 62 | echo "Por fazer"; 63 | 64 | echo "

Obter todos usuários

"; 65 | echo "Por fazer"; 66 | 67 | echo "

Obter usuários com where

"; 68 | echo "Por fazer"; 69 | 70 | return $response; 71 | } 72 | 73 | 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/settings.template.php: -------------------------------------------------------------------------------- 1 | [ 9 | // Ambiente (Só pode ser "dev", "test" ou "production") > Na sua máquina de programador, é "dev" 10 | "environment" => "dev", 11 | 12 | // Configurações do Slim 13 | 'determineRouteBeforeAppMiddleware' => false, 14 | 'displayErrorDetails' => true, 15 | 16 | // Conexão com o Banco - REQUERIDO 17 | 'db' => [ 18 | 'driver' => 'pdo_mysql', 19 | 'host' => '', 20 | 'port' => '', 21 | 'user' => '', 22 | 'pass' => '', 23 | 'dbname' => '' 24 | ], 25 | 26 | // Configurações do Twig 27 | 'view' => [ 28 | 'templatePath' => __DIR__ . '/src/View/', 29 | 'cachePath' => __DIR__ . '/../cache/' // Use false para desativar o cache de templates 30 | ], 31 | 32 | // Configurações de marketing e tracking 33 | 'tracking' => [ 34 | 'facebookPixel' => '', 35 | 'googleAnalytics' => '', 36 | 'mauticMtc' => '' 37 | ], 38 | 39 | // Configurações de integração com Mautic 40 | 'mautic' => [ 41 | 'baseUrl' => '', 42 | 'callback' => '', 43 | 'clientKey' => '', 44 | 'clientSecret' => '', 45 | 'accessToken' => '', 46 | 'refreshToken' => '', 47 | 'expires' => '', 48 | 'version' => 'OAuth2' 49 | ], 50 | 51 | 52 | // Configurações do rollbar, para logar todos os erros online 53 | 'rollbar' => [ 54 | 'access_token' => '', 55 | 'environment' => 'dev', // deve ser o mesmo do "environment" lá no alto 56 | 'run_on_dev' => false, // indica que Rollbar deverá funcionar em dev 57 | 'root' => __DIR__ 58 | ] 59 | ], 60 | ]; 61 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Sua contribuição com código será sempre muito bem vinda! Queremos que este projeto seja acessível para você pegar uma issue, codar, fazer seu pull request, e quando estiver online poder falar "fui eu quem fez"! 2 | 3 | O importante agora é separar uns minutos para ler as regras básicas de contribuição, para que tudo saia como esperado. 4 | 5 | Todos aqueles que tiverem ao menos uma issue feita, levada para produção, receberão um certificado de contribuição com o projeto, com o total de horas dedicados. Inclua em seu currículo esta experiência, temos certeza que será de grande valor! 6 | 7 | # O que fazer? 8 | 1. Veja os [projetos](https://github.com/TiagoGouvea/desafio_do_codigo/projects) nos quais pode trabalhar; 9 | 1. No projeto, visualize as issues da primeira coluna (To do), buscando uma que te interesse fazer; 10 | 1. Comentários e discussões são bem vindas também. Sinta-se a vontade comentar sempre; 11 | 1. Uma vez que levar uma issue para "Em desenvolvimento", concentre-se nela até sua conclusão; 12 | 13 | # Requisitos 14 | * Para participar programando aqui, você precisa saber PHP ou HTML/CSS e saber usar o GIT; 15 | * Para instalar bibliotecas de terceiros use o [composer](https://getcomposer.org/), que já está ativado no projeto; 16 | 17 | # Mantendo o código e repositório 18 | * Só altere os arquivos nos quais você está trabalhando naquela issue; 19 | * Realize os commits fazendo sempre referência a issue no comentário, exemplo "Atualizando documentação de contribuição #4". Assim os commits ficarão vinculados a issue e facilitará acompanhar o que foi feito; 20 | * Comente seus blocos de código para facilitar para os demais 21 | 22 | # Criando Issues 23 | Caso precise criar novas issues, você responder as perguntas propostas em [ISSUE_TEMPLATE.md](ISSUE_TEMPLATE.md), para que todos consigam entender a demanda e juntos acharmos uma prioridade. Sempre seja educado e apresente sua demanda de forma positiva, as pessoas irão se identificar (ou não) com sua issue, para que ela seja realmente feita. 24 | 25 | # Explicação do modelo (Work in Progress) 26 | 27 | Passo a passo explicando como tudo acontece. 28 | 29 | - Rota 30 | - Controller 31 | - Chama o model 32 | - Popula array 33 | - Renderiza no Twig 34 | - Template do Twig 35 | -------------------------------------------------------------------------------- /app/src/Model/IDAO.php: -------------------------------------------------------------------------------- 1 | MauticImportar::class 43 | ]; 44 | 45 | // Decorar settings com coisas a mais 46 | 47 | // Iniciar o app 48 | $app = new \Slim\App($settings); 49 | 50 | // Set up dependencies 51 | require __DIR__ . '/../app/dependencies.php'; 52 | 53 | // Register routes 54 | require __DIR__ . '/../app/routes.php'; 55 | 56 | // Run! 57 | $app->run(); 58 | 59 | 60 | // Verifica se a pasta é "gravável", se existe permissão de escrita 61 | function isWritablePath($xpath) 62 | { 63 | $isOK = false; 64 | $path = trim($xpath); 65 | if (($path != "") && is_dir($path) && is_writable($path)) { 66 | $tmpfile = "mPC_" . uniqid(mt_rand()) . '.writable'; 67 | $fullpathname = str_replace('//', '/', $path . "/" . $tmpfile); 68 | $fp = @fopen($fullpathname, "w"); 69 | if ($fp !== false) { 70 | $isOK = true; 71 | } 72 | @fclose($fp); 73 | @unlink($fullpathname); 74 | } 75 | return $isOK; 76 | } 77 | -------------------------------------------------------------------------------- /app/src/Controller/AdminController.php: -------------------------------------------------------------------------------- 1 | container = $container; 26 | } 27 | 28 | 29 | // Isso ficaria aqui mesmo? Ou crio um controler de home de admin? 30 | public function indexAction(Request $request, Response $response, $args) 31 | { 32 | return $this->renderLayout($response); 33 | } 34 | 35 | protected function renderLayout($response, $content = null, $data = null) 36 | { 37 | // Obter isso de uma configuração 38 | $data['adminTitle'] = "Desafio do Código"; 39 | $data['slug'] = $this->slug; 40 | $data['content'] = $content; 41 | return $this->container->view->render($response, '/admin/layout.twig', $data); 42 | } 43 | 44 | /** 45 | * Renderiza uma view e retorna o html final 46 | * @param $view 47 | * @param null $data 48 | * @return mixedR 49 | */ 50 | protected function fetchView($view, $data = null) 51 | { 52 | if (!$data) 53 | $data = array(); 54 | return $this->container->view->fetch($view, $data); 55 | } 56 | 57 | /** 58 | * Retorna o DAO referente ao controller que estende 59 | * Pode ser melhorado. :) 60 | * @return DAO 61 | */ 62 | protected function getDAO($conexao = null) 63 | { 64 | if (!$conexao) 65 | $conexao = $this->container->db; 66 | $className = 'App\Model\\' . ucfirst($this->slug) . "DAO"; 67 | $dao = $className::getInstance($conexao); 68 | return $dao; 69 | } 70 | 71 | 72 | /** 73 | * Redireciona a requisição para uma nota rota 74 | * @param $response 75 | * @param $routeName 76 | * @param null $routeArgssssss 77 | * @return mixed 78 | */ 79 | protected function redirect($response, $routeName, $routeArgs = []) 80 | { 81 | $uri = $this->container->router->pathFor($routeName, $routeArgs); 82 | return $response->withStatus(302)->withHeader('Location', $uri); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/View/admin/layout.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{adminTitle}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 60 |
61 | {{ content | raw }} 62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/Model/UsuarioOldDAO.php: -------------------------------------------------------------------------------- 1 | pdo = $pdo; 28 | self::$instance = $this; 29 | } 30 | 31 | 32 | /** 33 | * @param null $pdo 34 | * @return UsuarioOldDAO 35 | */ 36 | static function getInstance($pdo = null) 37 | { 38 | if (self::$instance == null) { 39 | global $pdoOld; 40 | self::$instance = new UsuarioOldDAO($pdoOld); 41 | } 42 | return self::$instance; 43 | } 44 | 45 | /** 46 | * Procura no banco de dados pelo registro e o retorna 47 | * @param $id 48 | * @return UsuarioOld 49 | */ 50 | public function findById(int $id) 51 | { 52 | return parent::_findById($id); 53 | } 54 | 55 | /** 56 | * Cria um novo registro a partir do objeto 57 | * @param \App\Model\UsuarioOld $user Objeto a ser inserido no banco 58 | * @param bool $returnInsertedObject Retornar o registro criado 59 | * @return \App\Model\UsuarioOld 60 | */ 61 | public function insert(Instancia $user, $returnInsertedObject = false) 62 | { 63 | return parent::_insert($user, $returnInsertedObject); 64 | } 65 | 66 | /** 67 | * Procura no banco de dados pelo registro e o retorna 68 | * @param \App\Model\UsuarioOld $user Objeto a ser atualizado no banco 69 | * @param bool $returnInsertedObject Retornar o registro criado 70 | * @return UsuarioOld 71 | */ 72 | public function update(Instancia $user, $returnInsertedObject = false) 73 | { 74 | return parent::_update($user, $returnInsertedObject); 75 | } 76 | 77 | /** 78 | * Procura no banco de dados pelos registros sob as condições e retorna os objetos 79 | * @param $where 80 | * @param $order 81 | * @param $limit 82 | * @return \App\Model\UsuarioOld[] 83 | * @internal param \App\Model\User $user Objeto a ser atualizado no banco 84 | * @internal param bool $returnInsertedObject Retornar o registro criado 85 | */ 86 | public function getWhere(string $where, string $order = null,string $limit = null) 87 | { 88 | return parent::_getWhere($where, $order, $limit); 89 | } 90 | 91 | /** 92 | * Procura no banco de dados pelos registros sob as condições e retorna a quantidade encontrada 93 | * @param $where 94 | * @param $order 95 | * @param $limit 96 | * @return int 97 | * @internal param \App\Model\User $user Objeto a ser atualizado no banco 98 | * @internal param bool $returnInsertedObject Retornar o registro criado 99 | */ 100 | public function countWhere(string $where) 101 | { 102 | return parent::_countWhere($where); 103 | } 104 | 105 | /** 106 | * Exclui um registro do banco 107 | * @param $id 108 | * @return mixed 109 | */ 110 | function deleteById(int $id) 111 | { 112 | return parent::_deleteById($id); 113 | } 114 | 115 | /** 116 | * @todo 117 | * @param string $order 118 | */ 119 | function getAll(string $order = null, string $limit = null) 120 | { 121 | return parent::_getAll($order, $limit); 122 | } 123 | 124 | 125 | /** 126 | * Valida os atributos de uma instância, de um registro, quando necessário 127 | * @param $vars 128 | * @return mixed - deve retornar true para ser considerado válido 129 | */ 130 | function validatePostVars($vars) 131 | { 132 | return true; 133 | } 134 | } -------------------------------------------------------------------------------- /migrations/2018-07-01.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 4.8.2 3 | -- https://www.phpmyadmin.net/ 4 | -- 5 | -- Host: db 6 | -- Tempo de geração: 26/12/2018 às 13:20 7 | -- Versão do servidor: 5.7.21 8 | -- Versão do PHP: 7.2.6 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | SET AUTOCOMMIT = 0; 12 | START TRANSACTION; 13 | SET time_zone = "+00:00"; 14 | 15 | 16 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 17 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 18 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 19 | /*!40101 SET NAMES utf8mb4 */; 20 | 21 | -- 22 | -- Banco de dados: `desafio_codigo` 23 | -- 24 | 25 | -- -------------------------------------------------------- 26 | 27 | -- 28 | -- Estrutura para tabela `desafio` 29 | -- 30 | 31 | CREATE TABLE `desafio` ( 32 | `id` int(11) NOT NULL, 33 | `id_trilha` int(11) NOT NULL, 34 | `ordem` int(11) NOT NULL, 35 | `titulo` varchar(64) NOT NULL, 36 | `conteudo` text, 37 | `ativo` tinyint(4) DEFAULT NULL 38 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 39 | 40 | -- -------------------------------------------------------- 41 | 42 | -- 43 | -- Estrutura para tabela `jornada` 44 | -- 45 | 46 | CREATE TABLE `jornada` ( 47 | `id` int(11) NOT NULL, 48 | `titulo` varchar(64) NOT NULL, 49 | `resumo` text, 50 | `descricao` text, 51 | `ativa` int(11) DEFAULT '0' 52 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 53 | 54 | -- -------------------------------------------------------- 55 | 56 | -- 57 | -- Estrutura para tabela `trilha` 58 | -- 59 | 60 | CREATE TABLE `trilha` ( 61 | `id` int(11) NOT NULL, 62 | `id_jornada` int(11) NOT NULL, 63 | `titulo` varchar(64) NOT NULL, 64 | `resumo` text, 65 | `descricao` text, 66 | `ativa` int(11) DEFAULT '0' 67 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 68 | 69 | -- -------------------------------------------------------- 70 | 71 | -- 72 | -- Estrutura para tabela `usuario` 73 | -- 74 | 75 | CREATE TABLE `usuario` ( 76 | `id` int(11) NOT NULL, 77 | `login` varchar(128) NOT NULL, 78 | `nome` varchar(128) NOT NULL, 79 | `email` varchar(128) NOT NULL, 80 | `tipo` enum('admin','tutor','usuario','') NOT NULL, 81 | `data_cadastro` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 82 | `data_ultimo_acesso` timestamp NULL DEFAULT NULL 83 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 84 | 85 | -- 86 | -- Índices de tabelas apagadas 87 | -- 88 | 89 | -- 90 | -- Índices de tabela `desafio` 91 | -- 92 | ALTER TABLE `desafio` 93 | ADD PRIMARY KEY (`id`), 94 | ADD KEY `fk_desafio_trilha_idx` (`id_trilha`); 95 | 96 | -- 97 | -- Índices de tabela `jornada` 98 | -- 99 | ALTER TABLE `jornada` 100 | ADD PRIMARY KEY (`id`); 101 | 102 | -- 103 | -- Índices de tabela `trilha` 104 | -- 105 | ALTER TABLE `trilha` 106 | ADD PRIMARY KEY (`id`); 107 | 108 | -- 109 | -- Índices de tabela `usuario` 110 | -- 111 | ALTER TABLE `usuario` 112 | ADD PRIMARY KEY (`id`); 113 | 114 | -- 115 | -- AUTO_INCREMENT de tabelas apagadas 116 | -- 117 | 118 | -- 119 | -- AUTO_INCREMENT de tabela `desafio` 120 | -- 121 | ALTER TABLE `desafio` 122 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 123 | 124 | -- 125 | -- AUTO_INCREMENT de tabela `jornada` 126 | -- 127 | ALTER TABLE `jornada` 128 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 129 | 130 | -- 131 | -- AUTO_INCREMENT de tabela `trilha` 132 | -- 133 | ALTER TABLE `trilha` 134 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 135 | 136 | -- 137 | -- AUTO_INCREMENT de tabela `usuario` 138 | -- 139 | ALTER TABLE `usuario` 140 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 141 | 142 | -- 143 | -- Restrições para dumps de tabelas 144 | -- 145 | 146 | -- 147 | -- Restrições para tabelas `desafio` 148 | -- 149 | ALTER TABLE `desafio` 150 | ADD CONSTRAINT `fk_desafio_trilha` FOREIGN KEY (`id_trilha`) REFERENCES `trilha` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; 151 | COMMIT; 152 | 153 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 154 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 155 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 156 | -------------------------------------------------------------------------------- /app/src/Controller/UsuarioController.php: -------------------------------------------------------------------------------- 1 | getDAO(); 21 | 22 | // Obter usuarios 23 | $usuarios = $dao->getWhere('','id desc',10); 24 | 25 | // Renderizar lista 26 | $content = $this->fetchView("admin/usuario/lista.twig", ['registros' => $usuarios]); 27 | 28 | return $this->renderLayout($response, $content); 29 | } 30 | 31 | /** 32 | * Renderiza o formulário para inclusão 33 | * @param Request $request 34 | * @param Response $response 35 | * @param $args 36 | * @return mixed 37 | */ 38 | public function addAction(Request $request, Response $response, $args) 39 | { 40 | $content = $this->fetchView("admin/usuario/form.twig"); 41 | return $this->renderLayout($response, $content); 42 | } 43 | 44 | /** 45 | * Salva o novo registro incluido 46 | * @param Request $request 47 | * @param Response $response 48 | * @param $args 49 | * @return mixed 50 | */ 51 | public function addPostAction(Request $request, Response $response, $args) 52 | { 53 | $vars = $request->getParsedBody(); 54 | try { 55 | /* @var $dao usuarioDAO */ 56 | $dao = $this->getDao(); 57 | $dao->insertFromArray($vars); 58 | return $this->redirect($response, "usuarioIndex"); 59 | } catch (\Exception $e) { 60 | $error = $e->getMessage(); 61 | $content = $this->fetchView("admin/usuario/form.twig", ["error" => $error, "registro" => $vars]); 62 | return $this->renderLayout($response, $content); 63 | } 64 | } 65 | 66 | 67 | /** 68 | * Renderiza o formulário para edição 69 | * @param Request $request 70 | * @param Response $response 71 | * @param $args 72 | * @return mixed 73 | */ 74 | public function editAction(Request $request, Response $response, $args) 75 | { 76 | $registro = $this->getDAO()->findById($args['id']); 77 | $content = $this->fetchView("admin/usuario/form.twig", ["registro" => $registro]); 78 | return $this->renderLayout($response, $content); 79 | } 80 | 81 | 82 | /** 83 | * Salva o registro alterado 84 | * @param Request $request 85 | * @param Response $response 86 | * @param $args 87 | * @return mixed 88 | */ 89 | public function editPostAction(Request $request, Response $response, $args) 90 | { 91 | $vars = $request->getParsedBody(); 92 | try { 93 | /* @var $dao usuarioDAO */ 94 | $dao = $this->getDao(); 95 | $dao->updateFromArray($args['id'], $vars); 96 | return $this->redirect($response, "usuarioIndex"); 97 | } catch (\Exception $e) { 98 | $error = $e->getMessage(); 99 | $content = $this->fetchView("admin/usuario/form.twig", ["error" => $error, "registro" => $vars]); 100 | return $this->renderLayout($response, $content); 101 | } 102 | } 103 | 104 | 105 | /** 106 | * Exclui (tenta ao menos) um registro 107 | * @param Request $request 108 | * @param Response $response 109 | * @param $args 110 | * @return mixed 111 | */ 112 | public function deleteAction(Request $request, Response $response, $args) 113 | { 114 | $this->getDAO()->deleteById($args['id']); 115 | return $this->redirect($response, "usuarioIndex"); 116 | } 117 | 118 | /** 119 | * Retorna o DAO referente a este controller 120 | * Implementado apenas para forçar o tipo do retorno 121 | * Pode ser melhorado. :) 122 | * @return usuarioDAO 123 | */ 124 | protected function getDAO($conexao = null) 125 | { 126 | return parent::getDAO(); 127 | } 128 | 129 | 130 | } 131 | -------------------------------------------------------------------------------- /app/src/Controller/UsuarioOldController.php: -------------------------------------------------------------------------------- 1 | getDAO(); 21 | 22 | // Obter usuarios 23 | $usuarios = $dao->getWhere('','id desc',10); 24 | 25 | // Renderizar lista 26 | $content = $this->fetchView("admin/usuarioOld/lista.twig", ['registros' => $usuarios]); 27 | 28 | return $this->renderLayout($response, $content); 29 | } 30 | 31 | /** 32 | * Renderiza o formulário para inclusão 33 | * @param Request $request 34 | * @param Response $response 35 | * @param $args 36 | * @return mixed 37 | */ 38 | public function addAction(Request $request, Response $response, $args) 39 | { 40 | $content = $this->fetchView("admin/usuarioOld/form.twig"); 41 | return $this->renderLayout($response, $content); 42 | } 43 | 44 | /** 45 | * Salva o novo registro incluido 46 | * @param Request $request 47 | * @param Response $response 48 | * @param $args 49 | * @return mixed 50 | */ 51 | public function addPostAction(Request $request, Response $response, $args) 52 | { 53 | $vars = $request->getParsedBody(); 54 | try { 55 | /* @var $dao UsuarioOldDAO */ 56 | $dao = $this->getDao(); 57 | $dao->insertFromArray($vars); 58 | return $this->redirect($response, "usuarioIndex"); 59 | } catch (\Exception $e) { 60 | $error = $e->getMessage(); 61 | $content = $this->fetchView("admin/usuarioOld/form.twig", ["error" => $error, "registro" => $vars]); 62 | return $this->renderLayout($response, $content); 63 | } 64 | } 65 | 66 | 67 | /** 68 | * Renderiza o formulário para edição 69 | * @param Request $request 70 | * @param Response $response 71 | * @param $args 72 | * @return mixed 73 | */ 74 | public function editAction(Request $request, Response $response, $args) 75 | { 76 | $registro = $this->getDAO()->findById($args['id']); 77 | $content = $this->fetchView("admin/usuarioOld/form.twig", ["registro" => $registro]); 78 | return $this->renderLayout($response, $content); 79 | } 80 | 81 | 82 | /** 83 | * Salva o registro alterado 84 | * @param Request $request 85 | * @param Response $response 86 | * @param $args 87 | * @return mixed 88 | */ 89 | public function editPostAction(Request $request, Response $response, $args) 90 | { 91 | $vars = $request->getParsedBody(); 92 | try { 93 | /* @var $dao UsuarioOldDAO */ 94 | $dao = $this->getDao(); 95 | $dao->updateFromArray($args['id'], $vars); 96 | return $this->redirect($response, "usuarioIndex"); 97 | } catch (\Exception $e) { 98 | $error = $e->getMessage(); 99 | $content = $this->fetchView("admin/usuarioOld/form.twig", ["error" => $error, "registro" => $vars]); 100 | return $this->renderLayout($response, $content); 101 | } 102 | } 103 | 104 | 105 | /** 106 | * Exclui (tenta ao menos) um registro 107 | * @param Request $request 108 | * @param Response $response 109 | * @param $args 110 | * @return mixed 111 | */ 112 | public function deleteAction(Request $request, Response $response, $args) 113 | { 114 | $this->getDAO()->deleteById($args['id']); 115 | return $this->redirect($response, "usuarioIndex"); 116 | } 117 | 118 | /** 119 | * Retorna o DAO referente a este controller 120 | * Implementado apenas para forçar o tipo do retorno 121 | * Pode ser melhorado. :) 122 | * @return UsuarioOldDAO 123 | */ 124 | protected function getDAO($conexao = null) 125 | { 126 | return parent::getDAO($this->container->dbOld); 127 | } 128 | 129 | 130 | } 131 | -------------------------------------------------------------------------------- /app/src/Model/DesafioDAO.php: -------------------------------------------------------------------------------- 1 | length(4)->setName('Título')->assert($vars['titulo']), 112 | Validator::stringType()->length(100)->setName('Conteudo')->assert($vars['conteudo']) 113 | ]; 114 | 115 | if (isset($vars['ativo'])) { 116 | $validacoes[] = Validator::boolVal()->validate($vars['ativo']); 117 | } 118 | 119 | } catch (NestedValidationException $exception) { 120 | $errors = $exception->findMessages([ 121 | 'alnum' => '{{name}} deve ter apenas letras e números', 122 | 'length' => '{{name}} deve ter mais caracteres', 123 | 'noWhitespace' => '{{name}} não pode ter espaços' 124 | ]); 125 | 126 | throw new \Exception($exception->getFullMessage()); 127 | } 128 | 129 | return true; 130 | } 131 | 132 | 133 | } -------------------------------------------------------------------------------- /app/src/Model/TrilhaDAO.php: -------------------------------------------------------------------------------- 1 | length(10)->setName('Título')->assert($vars['titulo']), 112 | Validator::stringType()->length(40)->setName('Resumo')->assert($vars['resumo']), 113 | Validator::stringType()->length(200)->setName('Descrição')->assert($vars['descricao']) 114 | ]; 115 | 116 | if (isset($vars['ativa'])) { 117 | $validacoes[] = Validator::boolVal()->validate($vars['ativa']); 118 | } 119 | 120 | } catch (NestedValidationException $exception) { 121 | $errors = $exception->findMessages([ 122 | 'alnum' => '{{name}} deve ter apenas letras e números', 123 | 'length' => '{{name}} deve ter mais caracteres', 124 | 'noWhitespace' => '{{name}} não pode ter espaços' 125 | ]); 126 | 127 | throw new \Exception($exception->getFullMessage()); 128 | } 129 | 130 | return true; 131 | } 132 | 133 | 134 | } -------------------------------------------------------------------------------- /app/src/Model/JornadaDAO.php: -------------------------------------------------------------------------------- 1 | length(10)->setName('Título')->assert($vars['titulo']), 112 | Validator::stringType()->length(40)->setName('Resumo')->assert($vars['resumo']), 113 | Validator::stringType()->length(200)->setName('Descrição')->assert($vars['descricao']) 114 | ]; 115 | 116 | if (isset($vars['ativa'])) { 117 | $validacoes[] = Validator::boolVal()->validate($vars['ativa']); 118 | } 119 | 120 | } catch (NestedValidationException $exception) { 121 | $errors = $exception->findMessages([ 122 | 'alnum' => '{{name}} deve ter apenas letras e números', 123 | 'length' => '{{name}} deve ter mais caracteres', 124 | 'noWhitespace' => '{{name}} não pode ter espaços' 125 | ]); 126 | 127 | throw new \Exception($exception->getFullMessage()); 128 | } 129 | 130 | return true; 131 | } 132 | 133 | 134 | } -------------------------------------------------------------------------------- /public/mautic_get_token.php: -------------------------------------------------------------------------------- 1 | $accessToken, 38 | 'accessTokenExpires' => $accessTokenExpires 39 | ); 40 | 41 | 42 | if (isset($_SESSION['accessToken'])) { 43 | $accessTokenData['accessToken'] = $_SESSION['accessToken']; 44 | } 45 | if (isset($_GET['access_token'])) { 46 | $accessTokenData['accessToken'] = $_GET['access_token']; 47 | $_SESSION['accessToken'] = $_GET['access_token']; 48 | } 49 | 50 | if (isset($_SESSION['accessToken'])) { 51 | $accessTokenData['accessToken'] = $_SESSION['accessToken']; 52 | } 53 | if (isset($_GET['refresh_token'])) { 54 | $accessTokenData['refreshToken'] = $_GET['refresh_token']; 55 | $_SESSION['refreshToken'] = $_GET['refresh_token']; 56 | } 57 | 58 | // @todo Sanitize this URL. Make sure it starts with http/https and doesn't end with '/' 59 | $settings = array( 60 | 'baseUrl' => $baseUrl, 61 | 'clientKey' => $clientKey, 62 | 'clientSecret' => $clientSecret, 63 | 'callback' => $callback, 64 | 'version' => 'OAuth2' 65 | ); 66 | 67 | if (!empty($accessTokenData['accessToken']) && !empty($accessTokenData['accessTokenSecret'])) { 68 | $settings['accessToken'] = $accessTokenData['accessToken']; 69 | $settings['accessTokenExpires'] = $accessTokenData['accessTokenExpires']; 70 | $settings['refreshToken'] = $accessTokenData['refreshToken']; 71 | } 72 | 73 | // echo "
";
 74 | // var_dump($_SESSION['oauth']);
 75 | // var_dump($_GET);
 76 | // die();
 77 | 
 78 | $initAuth = new ApiAuth();
 79 | 
 80 | /* @var $auth Mautic\Auth\OAuth */
 81 | $auth = $initAuth->newAuth($settings);
 82 | $auth->enableDebugMode();
 83 | try {
 84 |     if ($auth->validateAccessToken()) {
 85 |         // var_dump("A");
 86 |         if ($auth->accessTokenUpdated()) {
 87 |             // var_dump("b");
 88 |             $accessTokenData = $auth->getAccessTokenData();
 89 |             echo "

accessTokenData

"; 90 | echo "
";
 91 |             var_dump($accessTokenData);
 92 |             $_SESSION['accessToken'] = $accessTokenData['access_token'];
 93 |             $_SESSION['refreshToken'] = $accessTokenData['refresh_token'];
 94 |             $_SESSION['expires'] = $accessTokenData['expires'];
 95 |             var_dump("session updated");
 96 |             echo "Check it now on mautic_test";
 97 |             // @todo Save $accessTokenData
 98 |             // @todo Display success authorization message
 99 |         } else {
100 |             var_dump("already authorized");
101 |             // @todo Display info message that this app is already authorized.
102 | 
103 |             $api = new MauticApi();
104 |             var_dump($settings['baseUrl']);
105 |             $contactApi = $api->newApi('contacts', $auth, $settings['baseUrl']);
106 |             $response = $contactApi->getList();
107 |             var_dump($response);
108 |             $totalContacts = $response['total'];
109 |             var_dump($totalContacts);
110 |         }
111 |     } else {
112 |         // @todo Display info message that the token is not valid.
113 |         var_dump("Token is not valid?");
114 |     }
115 | } catch (Exception $exception) {
116 |     echo "

Exception

"; 117 | echo "
";
118 |     var_dump($exception);
119 | }
120 | 
121 | echo "
";
122 | // var_dump($_SESSION['oauth']);


--------------------------------------------------------------------------------
/app/src/Model/UsuarioOld.php:
--------------------------------------------------------------------------------
  1 |  " . $value . "
"; 46 | // Validar alguns campos antes de salvar 47 | if ($name == 'email') { 48 | // Validar 49 | $value = filter_var($value, FILTER_SANITIZE_EMAIL); 50 | } 51 | 52 | $this->$value = $value; 53 | } 54 | 55 | /** 56 | * Retorna o usuário, porém no formato correto pra enviar para o Mautic 57 | * @todo 58 | * Campos que foram ignorados e precisam ser trabalhados 59 | * tutor, total, m_last, newsletter 60 | * 61 | * @return array 62 | */ 63 | public function getMauticObj() 64 | { 65 | // Arrow Function para formatar datas pro mautic - Recebe algo como "2018-02-13 12:13:19" e retorna "2018-02-13 12:13" (garantidamente) 66 | $formatMauticDate = function ($date) { 67 | $format = "Y-m-d H:m"; 68 | if ($date === null || $date === '0000-00-00 00:00:00') 69 | return null; 70 | else if (strpos($date, "/")) { 71 | $date = explode("/", $date); 72 | return "$date[2]-$date[1]-$date[0] 00:00:00"; 73 | } else 74 | return $date; 75 | }; 76 | 77 | $data = []; 78 | $data['firstname'] = PLib::capitalize_name($this->nome); // Separar first name do restante 79 | $data['email'] = str_replace(" ", "", trim(strtolower($this->email))); 80 | $data['login'] = $this->removeAccents(trim(strtolower($this->login))); 81 | $data['ipAddress'] = $this->ip; 82 | $data['birthday'] = $formatMauticDate($this->nasc); 83 | $data['usertype'] = $this->tipo; 84 | $data['nickname'] = $this->apelido; 85 | $data['phone'] = $this->telefone; 86 | $data['city'] = PLib::capitalize_name($this->cidade); 87 | $data['school'] = PLib::capitalize_name($this->escola); 88 | $data['schoolyear'] = $this->serie; 89 | $data['signupdate'] = $formatMauticDate($this->DataAdd); 90 | $data['lastlogindate'] = $formatMauticDate($this->last_login); 91 | $data['oldpoints'] = $this->total; 92 | 93 | // Ajustar encodings 94 | if (mb_detect_encoding($data['firstname']) != 'UTF-8') { 95 | // var_dump($data['firstname']); 96 | $data['firstname'] = mb_convert_encoding($data['firstname'], "UTF-8"); 97 | } 98 | if (mb_detect_encoding($data['login']) != 'UTF-8') { 99 | // var_dump($data['login']); 100 | $data['login'] = mb_convert_encoding($data['login'], "UTF-8"); 101 | } 102 | if (mb_detect_encoding($data['nickname']) != 'UTF-8') { 103 | // var_dump($data['login']); 104 | $data['nickname'] = mb_convert_encoding($data['nickname'], "UTF-8"); 105 | } 106 | if (mb_detect_encoding($data['school']) != 'UTF-8') { 107 | // var_dump($data['login']); 108 | $data['school'] = mb_convert_encoding($data['school'], "UTF-8"); 109 | } 110 | if (mb_detect_encoding($data['city']) != 'UTF-8') { 111 | // var_dump($data['login']); 112 | $data['city'] = mb_convert_encoding($data['city'], "UTF-8"); 113 | } 114 | 115 | return $data; 116 | } 117 | 118 | public function save() 119 | { 120 | } 121 | 122 | public function removeAccents($string) 123 | { 124 | return preg_replace(array("/(á|à|ã|â|ä)/", "/(Á|À|Ã|Â|Ä)/", "/(é|è|ê|ë)/", "/(É|È|Ê|Ë)/", "/(í|ì|î|ï)/", "/(Í|Ì|Î|Ï)/", "/(ó|ò|õ|ô|ö)/", "/(Ó|Ò|Õ|Ô|Ö)/", "/(ú|ù|û|ü)/", "/(Ú|Ù|Û|Ü)/", "/(ñ)/", "/(Ñ)/"), explode(" ", "a A e E i I o O u U n N"), $string); 125 | } 126 | } -------------------------------------------------------------------------------- /app/src/Controller/DesafioController.php: -------------------------------------------------------------------------------- 1 | getDAO(); 21 | 22 | // Obter desafios 23 | $desafios = $dao->getAll(); 24 | 25 | // Renderizar lista 26 | $content = $this->fetchView("admin/desafio/lista.twig", ['registros' => $desafios]); 27 | 28 | return $this->renderLayout($response, $content); 29 | } 30 | 31 | /** 32 | * Renderiza o formulário para inclusão 33 | * @param Request $request 34 | * @param Response $response 35 | * @param $args 36 | * @return mixed 37 | */ 38 | public function addAction(Request $request, Response $response, $args) 39 | { 40 | $daoTrilha = TrilhaDAO::getInstance($this->container->db); 41 | $trilha = $daoTrilha->findById($args['id']); 42 | $content = $this->fetchView("admin/desafio/form.twig", ['trilha' => $trilha]); 43 | return $this->renderLayout($response, $content); 44 | } 45 | 46 | /** 47 | * Salva o novo registro incluido 48 | * @param Request $request 49 | * @param Response $response 50 | * @param $args 51 | * @return mixed 52 | */ 53 | public function addPostAction(Request $request, Response $response, $args) 54 | { 55 | // O id da trilha, está na URL.. exemplo: /admin/trilha/1/desafio/incluir/ 56 | $idTrilha = $args['id']; 57 | $vars = $request->getParsedBody(); 58 | $vars['id_trilha'] = $idTrilha; 59 | try { 60 | /* @var $dao DesafioDAO */ 61 | $dao = $this->getDao(); 62 | $dao->insertFromArray($vars); 63 | return $this->redirect($response, "trilhaListDesafios", ['id' => $idTrilha]); 64 | } catch (\Exception $e) { 65 | $error = $e->getMessage(); 66 | $content = $this->fetchView("admin/desafio/form.twig", ["error" => $error, "registro" => $vars]); 67 | return $this->renderLayout($response, $content); 68 | } 69 | } 70 | 71 | 72 | /** 73 | * Renderiza o formulário para edição 74 | * @param Request $request 75 | * @param Response $response 76 | * @param $args 77 | * @return mixed 78 | */ 79 | public function editAction(Request $request, Response $response, $args) 80 | { 81 | /* @var $registrto Desafio */ 82 | $registro = $this->getDAO()->findById($args['id']); 83 | $trilha = $registro->getTrilha(); 84 | $content = $this->fetchView("admin/desafio/form.twig", ["trilha"=>$trilha, "registro" => $registro]); 85 | return $this->renderLayout($response, $content); 86 | } 87 | 88 | 89 | /** 90 | * Salva o registro alterado 91 | * @param Request $request 92 | * @param Response $response 93 | * @param $args 94 | * @return mixed 95 | */ 96 | public function editPostAction(Request $request, Response $response, $args) 97 | { 98 | $vars = $request->getParsedBody(); 99 | try { 100 | /* @var $dao DesafioDAO */ 101 | $dao = $this->getDao(); 102 | $desafio = $dao->updateFromArray($args['id'], $vars, true); 103 | return $this->redirect($response, "trilhaListDesafios", ['id' => $desafio->id_trilha]); 104 | } catch (\Exception $e) { 105 | $error = $e->getMessage(); 106 | $content = $this->fetchView("admin/desafio/form.twig", ["error" => $error, "registro" => $vars]); 107 | return $this->renderLayout($response, $content); 108 | } 109 | } 110 | 111 | 112 | /** 113 | * Exclui (tenta ao menos) um registro 114 | * @param Request $request 115 | * @param Response $response 116 | * @param $args 117 | * @return mixed 118 | */ 119 | public function deleteAction(Request $request, Response $response, $args) 120 | { 121 | $registro = $this->getDAO()->deleteById($args['id']); 122 | return $this->redirect($response, "desafioIndex"); 123 | } 124 | 125 | /** 126 | * Retorna o DAO referente a este controller 127 | * Implementado apenas para forçar o tipo do retorno 128 | * Pode ser melhorado. :) 129 | * @return DesafioDAO 130 | */ 131 | protected function getDAO($conexao = null) 132 | { 133 | return parent::getDAO(); 134 | } 135 | 136 | 137 | } 138 | -------------------------------------------------------------------------------- /app/src/Model/UsuarioDAO.php: -------------------------------------------------------------------------------- 1 | pdo = $pdo; 30 | self::$instance = $this; 31 | } 32 | 33 | static function getInstance($pdo = null) 34 | { 35 | if (self::$instance == null) { 36 | global $pdo; 37 | self::$instance = new UsuarioDAO($pdo); 38 | } 39 | return self::$instance; 40 | } 41 | 42 | /** 43 | * Procura no banco de dados pelo registro e o retorna 44 | * @param $id 45 | * @return UsuarioOld 46 | */ 47 | public function findById(int $id) 48 | { 49 | return parent::_findById($id); 50 | } 51 | 52 | /** 53 | * Cria um novo registro a partir do objeto 54 | * @param \App\Model\UsuarioOld $user Objeto a ser inserido no banco 55 | * @param bool $returnInsertedObject Retornar o registro criado 56 | * @return \App\Model\UsuarioOld 57 | */ 58 | public function insert(Instancia $user, $returnInsertedObject = false) 59 | { 60 | return parent::_insert($user, $returnInsertedObject); 61 | } 62 | 63 | /** 64 | * Procura no banco de dados pelo registro e o retorna 65 | * @param \App\Model\UsuarioOld $user Objeto a ser atualizado no banco 66 | * @param bool $returnInsertedObject Retornar o registro criado 67 | * @return UsuarioOld 68 | */ 69 | public function update(Instancia $user, $returnInsertedObject = false) 70 | { 71 | return parent::_update($user, $returnInsertedObject); 72 | } 73 | 74 | /** 75 | * Procura no banco de dados pelos registros sob as condições e retorna os objetos 76 | * @param $where 77 | * @param $order 78 | * @param $limit 79 | * @return \App\Model\UsuarioOld[] 80 | * @internal param \App\Model\User $user Objeto a ser atualizado no banco 81 | * @internal param bool $returnInsertedObject Retornar o registro criado 82 | */ 83 | public function getWhere(string $where, string $order = null,string $limit = null) 84 | { 85 | return parent::_getWhere($where, $order, $limit); 86 | } 87 | 88 | /** 89 | * Procura no banco de dados pelos registros sob as condições e retorna a quantidade encontrada 90 | * @param $where 91 | * @param $order 92 | * @param $limit 93 | * @return int 94 | * @internal param \App\Model\User $user Objeto a ser atualizado no banco 95 | * @internal param bool $returnInsertedObject Retornar o registro criado 96 | */ 97 | public function countWhere(string $where) 98 | { 99 | return parent::_countWhere($where); 100 | } 101 | 102 | /** 103 | * Exclui um registro do banco 104 | * @param $id 105 | * @return mixed 106 | */ 107 | function deleteById(int $id) 108 | { 109 | return parent::_deleteById($id); 110 | } 111 | 112 | /** 113 | * @todo 114 | * @param string $order 115 | */ 116 | function getAll(string $order = null, string $limit = null) 117 | { 118 | return parent::_getAll($order, $limit); 119 | } 120 | 121 | 122 | /** 123 | * Valida os atributos de uma instância, de um registro, quando necessário 124 | * @todo 125 | * Mover as mensagens para um único lugar, para todos os DAOS lerem de lá 126 | * @param $vars 127 | * @return mixed 128 | */ 129 | function validatePostVars($vars) 130 | { 131 | try { 132 | $validacoes = [ 133 | Validator::stringType()->length(10)->setName('Nome')->assert($vars['nome']), 134 | Validator::stringType()->length(4)->setName('Login')->assert($vars['login']), 135 | Validator::email()->setName('Email')->assert($vars['email']) 136 | ]; 137 | } catch (NestedValidationException $exception) { 138 | $errors = $exception->findMessages([ 139 | 'alnum' => '{{name}} deve ter apenas letras e números', 140 | 'length' => '{{name}} deve ter mais caracteres', 141 | 'noWhitespace' => '{{name}} não pode ter espaços', 142 | 'email' => 'O email informado não é válido' 143 | ]); 144 | 145 | throw new \Exception($exception->getFullMessage()); 146 | } 147 | 148 | return true; 149 | } 150 | } -------------------------------------------------------------------------------- /app/src/Controller/JornadaController.php: -------------------------------------------------------------------------------- 1 | getDAO(); 21 | 22 | // Obter jornadas 23 | $jornadas = $dao->getAll(); 24 | 25 | // Renderizar lista 26 | $content = $this->fetchView("admin/jornada/lista.twig", ['registros' => $jornadas]); 27 | 28 | return $this->renderLayout($response, $content); 29 | } 30 | 31 | /** 32 | * Renderiza o formulário para inclusão 33 | * @param Request $request 34 | * @param Response $response 35 | * @param $args 36 | * @return mixed 37 | */ 38 | public function addAction(Request $request, Response $response, $args) 39 | { 40 | $content = $this->fetchView("admin/jornada/form.twig"); 41 | return $this->renderLayout($response, $content); 42 | } 43 | 44 | /** 45 | * Salva o novo registro incluido 46 | * @param Request $request 47 | * @param Response $response 48 | * @param $args 49 | * @return mixed 50 | */ 51 | public function addPostAction(Request $request, Response $response, $args) 52 | { 53 | $vars = $request->getParsedBody(); 54 | try { 55 | /* @var $dao JornadaDAO */ 56 | $dao = $this->getDao(); 57 | $dao->insertFromArray($vars); 58 | return $this->redirect($response, "jornadaIndex"); 59 | } catch (\Exception $e) { 60 | $error = $e->getMessage(); 61 | $content = $this->fetchView("admin/jornada/form.twig", ["error" => $error, "registro" => $vars]); 62 | return $this->renderLayout($response, $content); 63 | } 64 | } 65 | 66 | 67 | /** 68 | * Renderiza o formulário para edição 69 | * @param Request $request 70 | * @param Response $response 71 | * @param $args 72 | * @return mixed 73 | */ 74 | public function editAction(Request $request, Response $response, $args) 75 | { 76 | $registro = $this->getDAO()->findById($args['id']); 77 | $content = $this->fetchView("admin/jornada/form.twig", ["registro" => $registro]); 78 | return $this->renderLayout($response, $content); 79 | } 80 | 81 | 82 | /** 83 | * Salva o registro alterado 84 | * @param Request $request 85 | * @param Response $response 86 | * @param $args 87 | * @return mixed 88 | */ 89 | public function editPostAction(Request $request, Response $response, $args) 90 | { 91 | $vars = $request->getParsedBody(); 92 | try { 93 | /* @var $dao JornadaDAO */ 94 | $dao = $this->getDao(); 95 | $dao->updateFromArray($args['id'], $vars); 96 | return $this->redirect($response, "jornadaIndex"); 97 | } catch (\Exception $e) { 98 | $error = $e->getMessage(); 99 | $content = $this->fetchView("admin/jornada/form.twig", ["error" => $error, "registro" => $vars]); 100 | return $this->renderLayout($response, $content); 101 | } 102 | } 103 | 104 | 105 | /** 106 | * Exclui (tenta ao menos) um registro 107 | * @param Request $request 108 | * @param Response $response 109 | * @param $args 110 | * @return mixed 111 | */ 112 | public function deleteAction(Request $request, Response $response, $args) 113 | { 114 | $this->getDAO()->deleteById($args['id']); 115 | return $this->redirect($response, "jornadaIndex"); 116 | } 117 | 118 | /** 119 | * Obtem as trilhas desta jornada 120 | * @param Request $request 121 | * @param Response $response 122 | * @param $args 123 | */ 124 | public function listTrilhas(Request $request, Response $response, $args) 125 | { 126 | // Obter Jornada atual 127 | $jornada = $this->getDAO()->findById($args['id']); 128 | 129 | // Obter trilhas da jornada 130 | $trilhas = $jornada->getTrilhas(); 131 | 132 | // Renderizar lista 133 | $content = $this->fetchView("admin/trilha/lista.twig", ['jornada' => $jornada, 'registros' => $trilhas]); 134 | 135 | return $this->renderLayout($response, $content); 136 | } 137 | 138 | /** 139 | * Retorna o DAO referente a este controller 140 | * Implementado apenas para forçar o tipo do retorno 141 | * Pode ser melhorado. :) 142 | * @return JornadaDAO 143 | */ 144 | protected function getDAO($conexao = null) 145 | { 146 | return parent::getDAO(); 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /app/routes.php: -------------------------------------------------------------------------------- 1 | get('/', '\App\Controller\SiteController:indexAction')->setName('homeSite'); 8 | 9 | // Rotas do Desafio 10 | $app->get('/desafio/', '\App\Controller\DesafioController:indexAction')->setName('homeDesafio'); 11 | 12 | // Rotas do Desafio 13 | $app->group('/admin',function (){ 14 | // Inicio 15 | $this->get('/', '\App\Controller\AdminController:indexAction')->setName('adminIndex'); 16 | 17 | // Jornadas 18 | $this->group('/jornada', function(){ 19 | $this->get('/', '\App\Controller\JornadaController:indexAction')->setName('jornadaIndex'); 20 | $this->get('/incluir', '\App\Controller\JornadaController:addAction')->setName('jornadaAdd'); 21 | $this->post('/incluir', '\App\Controller\JornadaController:addPostAction')->setName('jornadaPost'); 22 | $this->get('/editar/{id}/', '\App\Controller\JornadaController:editAction')->setName('jornadaEdit'); 23 | $this->post('/editar/{id}/', '\App\Controller\JornadaController:editPostAction')->setName('jornadaEdit'); 24 | $this->get('/excluir/{id}/', '\App\Controller\JornadaController:deleteAction')->setName('jornadaDelete'); 25 | // Trilhas em Jornada 26 | $this->get('/{id}/trilha/', '\App\Controller\JornadaController:listTrilhas')->setName('jornadaListTrilhas'); 27 | $this->get('/{id}/trilha/incluir/', '\App\Controller\TrilhaController:addAction')->setName('jornadaTrilhaIncluir'); 28 | $this->post('/{id}/trilha/incluir/', '\App\Controller\TrilhaController:addPostAction')->setName('jornadaTrilhaPost'); 29 | }); 30 | 31 | // Trilhas 32 | $this->group('/trilha', function(){ 33 | $this->get('/', '\App\Controller\TrilhaController:indexAction')->setName('trilhaIndex'); 34 | $this->get('/editar/{id}/', '\App\Controller\TrilhaController:editAction')->setName('trilhaEdit'); 35 | $this->post('/editar/{id}/', '\App\Controller\TrilhaController:editPostAction')->setName('trilhaEdit'); 36 | $this->get('/excluir/{id}/', '\App\Controller\TrilhaController:deleteAction')->setName('trilhaDelete'); 37 | 38 | // Desafios em Trilhas 39 | $this->get('/{id}/desafio/', '\App\Controller\TrilhaController:listDesafios')->setName('trilhaListDesafios'); 40 | $this->get('/{id}/desafio/incluir/', '\App\Controller\DesafioController:addAction')->setName('trilhaDesafioIncluir'); 41 | $this->post('/{id}/desafio/incluir/', '\App\Controller\DesafioController:addPostAction')->setName('trilhaDesafioPost'); 42 | }); 43 | 44 | // Desafios 45 | $this->group('/desafio', function(){ 46 | $this->get('/', '\App\Controller\DesafioController:indexAction')->setName('desafioIndex'); 47 | $this->get('/editar/{id}/', '\App\Controller\DesafioController:editAction')->setName('desafioEdit'); 48 | $this->post('/editar/{id}/', '\App\Controller\DesafioController:editPostAction')->setName('desafioEdit'); 49 | $this->get('/excluir/{id}/', '\App\Controller\DesafioController:deleteAction')->setName('desafioDelete'); 50 | }); 51 | 52 | // Usuarios 53 | $this->group('/usuario', function(){ 54 | $this->get('/', '\App\Controller\UsuarioController:indexAction')->setName('usuarioIndex'); 55 | $this->get('/incluir', '\App\Controller\UsuarioController:addAction')->setName('usuarioAdd'); 56 | $this->post('/incluir', '\App\Controller\UsuarioController:addPostAction')->setName('usuarioPost'); 57 | $this->get('/editar/{id}/', '\App\Controller\UsuarioController:editAction')->setName('usuarioEdit'); 58 | $this->post('/editar/{id}/', '\App\Controller\UsuarioController:editPostAction')->setName('usuarioEdit'); 59 | $this->get('/excluir/{id}/', '\App\Controller\UsuarioController:deleteAction')->setName('usuarioDelete'); 60 | }); 61 | 62 | // Sistema - rota de status 63 | $this->group('/sistema', function(){ 64 | $this->get('/', '\App\Controller\SistemaController:indexAction')->setName('sistemaIndex'); 65 | }); 66 | 67 | // Rotas para lidar com sistema antigo, e migrações 68 | 69 | // Usuarios codewars - sistema antigo 70 | $this->group('/usuarioOld', function(){ 71 | $this->get('/', '\App\Controller\UsuarioOldController:indexAction')->setName('usuarioOldIndex'); 72 | $this->get('/incluir', '\App\Controller\UsuarioOldController:addAction')->setName('usuarioOldAdd'); 73 | $this->post('/incluir', '\App\Controller\UsuarioOldController:addPostAction')->setName('usuarioOldPost'); 74 | $this->get('/editar/{id}/', '\App\Controller\UsuarioOldController:editAction')->setName('usuarioOldEdit'); 75 | $this->post('/editar/{id}/', '\App\Controller\UsuarioOldController:editPostAction')->setName('usuarioOldEdit'); 76 | $this->get('/excluir/{id}/', '\App\Controller\UsuarioOldController:deleteAction')->setName('usuarioOldDelete'); 77 | }); 78 | }); 79 | 80 | // Rotas de teste 81 | $app->get('/teste/', '\App\Controller\TesteController:indexAction')->setName('testeIndex'); 82 | 83 | // Rotas de teste 84 | $app->get('/cron/', '\App\Controller\CronController:indexAction')->setName('cronIndex'); 85 | $app->get('/cron/mautic/sync/', '\App\Controller\CronController:mauticSyncAction')->setName('cronMauticSync'); -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # O que é? 6 | 7 | O "[Desafio do Código](http://desafiodocodigo.com.br)" é um desafio online com um conjunto de missões que guiam você por ferramentas digitais para aprender programação, matemática e inglês. 8 | Foi criado por [Soraia Novaes](http://professoragoogle.com.br/) para auxiliar crianças de 10 a 108 anos a aprender estas habilidades tão necessárias no mundo atual. 9 | 10 | # Organização dos Desafios 11 | 12 | Na versão antiga o usuário acessava a plataforma e logo via os desafios, que eram fixos. Para esta nova versão temos os Desafios organizados em Trilhas, e Trilhas em Jornadas. 13 | 14 | Exemplo, uma Jornada poderia ser "Programação para crianças", onde teriam várias trilhas, tais como "Começando pelo Sketch Jr", "O segundo grande passo, o Sketch", "Outras forma de programar com blocos". E em cada uma destas trilhas teriam os desafios que seriam efetivamente onde a pessoa aprenderia. 15 | 16 | O Desafio do Código pode atender diversos públicos, bastando apenas criamos jornadas, trilhas e desafios para isso. 17 | 18 | ## Uma jornada 19 | 20 | Uma jornada é algo durador e transformador. Podemos imaginar uma jornada "Programação com PHP", que fará uma pessoa aprender tudo que for necessário sobre o PHP. Dentro desta jornada existirão várias trilhas que subdividem o conteúdo em partes menores. 21 | 22 | ## Uma trilha 23 | 24 | Na jornada do PHP, algumas trilhas poderiam ser "Lidando com o servidor local", "O básico do PHP"... e outras tantas trilhas. 25 | 26 | ## Um desafio 27 | 28 | Um desafio é basicamente algo que a pessoa precisará aprender, realizar, e ser avaliada por isso. Poderia exisitir uma trilha "Utilizando o Git" onde um dos desafios fosse "Realizando um commit e push". Neste desafio seria explicado detalhadamente como é feito um commit e como dar o push pro repositório, por fim haveria um teste ou questionário simples para validar que a pessoa aprendeu mesmo. 29 | 30 | Ao concluir um desafio e realizar a avaliação, ela ganha pontos e avança na plataforma, e confirma que está aprendendo cada vez mais! 31 | 32 | # Contribuindo 33 | 34 | Precisamos de pessoas para manter o Desafio do Código. Ficaremos muitos felizes em ver você contribuindo conosco! Se esse é seu desejo dê uma lida em "[Como Contribuir](CONTRIBUTING.md)". 35 | 36 | # Este repositório 37 | 38 | É o repositório único do projeto no qual estamos trabalhando em uma **nova versão** com um padrão **mais limpo e moderno de código** a partir da iniciativa de [Tiago Gouvêa](http://www.tiagogouvea.com.br). 39 | 40 | O código antigo foi implementado em PHP por alguns voluntários e está na branch [desafioAntigo](/https://github.com/TiagoGouvea/desafio_do_codigo/tree/desafioAntigo). 41 | 42 | Tudo por aqui está (e deverá continuar) em português, incluíndo comentários em códigos, para permitir que mais pessoas contribuam com o projeto. 43 | 44 | ## Componentes e estrutura do projeto 45 | 46 | Optamos por usar frameworks mais simples, para que jovens e estudantes possam trabalhar bem com o projeto. Estamos usando: 47 | 48 | * PHP 7 - Para que tudo funcione como esperado 49 | * [Composer](https://getcomposer.org) - Gerenciador de dependências 50 | * [Slim Framework](https://www.slimframework.com/) - É quem carrega a base do projeto, define as rotas e lida com as requisições 51 | * [Twig](https://twig.symfony.com) - É o responsável por renderizar as views, mesclar os dados fornecidos pelo PHP com o HTML 52 | * [Bootstrap](https://getbootstrap.com/) - Para manter as views fáceis de serem construídas e sempre responsivas 53 | 54 | Algumas bibliotecas extras para ajudar no trabalho: 55 | * [Respect\Validation](https://github.com/Respect/Validation) - Para validar dados de formulários 56 | * [Rollbar](https://rollbar.com/) - Para logar todos os erros online, tanto no backend quanto no frontend 57 | 58 | A estrutura de pastas do projeto segue o padrão do Slim, com poucas modificações: 59 | 60 | ``` 61 | / 62 | |--- app/ 63 | | |--- src/ 64 | | | |--- Controller 65 | | | |--- Model 66 | | | |--- Middleware 67 | | | |--- Persistence 68 | | | |--- View/ 69 | | |--- dependencies.php 70 | | |--- routes.php 71 | | |--- settings.php 72 | |--- public/ 73 | | |--- css/ 74 | | |--- js/ 75 | | |--- index.php 76 | ``` 77 | 78 | Certamente em 99% do tempo você estará trabalhando nos arquivos das pastas **Controller**, **Model**, **View** e **public**. 79 | 80 | ## Rodando o projeto novo em desenvolvimento 81 | 82 | 1. Baixe o código do repositório usando seu git; 83 | 1. Acesse a pasta do projeto e execute ``php composer.phar install`` para instalar as dependências (ou ``composer install``); 84 | 1. Dê seu navegado, acesse seu localhost, algo como ``http://localhost/desafio_do_codigo/public/``. Você verá as instruções para concluir sua configuração; 85 | 1. Crie um arquivo settings.php em /app/, usando como base o settings.template.php 86 | 87 | * Será necessário ter permissão de escrita na pasta /cache/. Se você usa Mac ou Linux precisará dar esta permissão pelo terminal. 88 | 89 | Outra forma de rodar o projeto pode ser executando diretamente na pasta raiz do projeto: 90 | 91 | ``` 92 | php -d display_errors=on -S localhost:8000 -t public 93 | ``` 94 | 95 | Tudo pronto para programar! :D 96 | 97 | 98 | -------------------------------------------------------------------------------- /app/src/Controller/CronController.php: -------------------------------------------------------------------------------- 1 | container = $container; 20 | } 21 | 22 | public function indexAction(Request $request, Response $response, $args) 23 | { 24 | var_dump("cron index"); 25 | return $response; 26 | } 27 | 28 | /** 29 | * WIP 30 | * Rodar novamente para levar os novos campos (citados no modelo 31 | * de usuario em getMauticObj) e para lidar com usuário com mauticId=0 (falhas) 32 | * @param Request $request 33 | * @param Response $response 34 | * @param $args 35 | */ 36 | public function mauticSyncAction(Request $request, Response $response, $args) 37 | { 38 | $baseUrl = $this->container['settings']['mautic']['baseUrl']; 39 | $auth = $this->container->mauticAuth; 40 | 41 | $api = new MauticApi(); 42 | $contactApi = $api->newApi('contacts', $auth, $baseUrl); 43 | 44 | // var_dump($mauticApi); 45 | 46 | // Ok! Sincronizar 47 | 48 | echo ""; 53 | flush(); 54 | ob_flush(); 55 | 56 | echo "
";
 57 |         echo "The time is " . date("h:i:sa") . PHP_EOL . PHP_EOL;
 58 | 
 59 |         // Obter conexão
 60 | 
 61 |         $conexao = $this->container->dbOld;
 62 |         $userDao = UsuarioOldDAO::getInstance($conexao);
 63 | 
 64 |         // Obter últimos X registros não sincronizados
 65 |         $limit = 5;
 66 |         echo "Limite para obtenção: " . $limit . PHP_EOL;
 67 |         $users = $userDao->getWhere("mauticId is null", "id desc", $limit);
 68 | 
 69 |         echo "Usuários para sincronizar agora: " . count($users) . PHP_EOL;
 70 |         echo "The time is " . date("h:i:sa") . PHP_EOL . PHP_EOL;
 71 | //        var_dump($users);
 72 | 
 73 | //        $fields = $contactApi->getFieldList();
 74 | //        var_dump($fields);
 75 |         // Certificar campos necessários - login
 76 | //
 77 | //// Create the contact
 78 | //        $response = $contactApi->create($data);
 79 | //        $contact = $response[$contactApi->itemName()];
 80 | 
 81 |         echo "Sincronização:" . PHP_EOL . PHP_EOL;
 82 | 
 83 |         $emailInvalido = 0;
 84 | 
 85 |         foreach ($users as $user) {
 86 |             // Ignorar usuários sem email ou com email inválido
 87 |             if (filter_var($user->email, FILTER_VALIDATE_EMAIL) == false) {
 88 |                 $emailInvalido++;
 89 |                 echo "  Email inválido: " . $user->email . PHP_EOL;
 90 |                 // Atualizar usuários com mauticId -1 para saber que não devem ser enviados ao mautic
 91 |                 $user->mauticId = -1;
 92 |                 $userDao->update($user);
 93 |                 continue;
 94 |             }
 95 | 
 96 |             // Obter contato como objeto
 97 |             $contact = $user->getMauticObj();
 98 |             // var_dump($contact);
 99 | 
100 |             // Enviar ao mautic
101 |             $response = $contactApi->create($contact);
102 |             // var_dump($response['contact']['fields']['all']);
103 | //            var_dump($response['contact']);
104 | 
105 |             // Salvar id remoto, localmente
106 |             if (isset($response['contact']) && $response['contact']['id']) {
107 |                 echo "  Contato Id: " . $response['contact']['id'] . " - " . $response['contact']['fields']['all']['firstname'] . " - " . $response['contact']['fields']['all']['email'] . PHP_EOL;
108 |                 $user->mauticId = $response['contact']['id'];
109 |                 $userDao->update($user);
110 |             } else {
111 |                 echo "  FALHA ao criar contato no mautic" . PHP_EOL;
112 |                 if (isset($response['error'])) {
113 |                     echo "    " . $response['error']['message'] . PHP_EOL;
114 |                 } else {
115 |                     var_dump($response);
116 |                 }
117 |                 var_dump($response);
118 |                 // var_dump($user);
119 |                 // Atualizar usuários com mauticId 0 para saber que devem ser corrigidos futuramente...
120 |                 $user->mauticId = 0;
121 |                 $userDao->update($user);
122 |             }
123 |             flush();
124 |             ob_flush();
125 |         }
126 | 
127 |         echo PHP_EOL . "Fim da sincronização" . PHP_EOL;
128 |         echo "The time is " . date("h:i:sa") . PHP_EOL . PHP_EOL;
129 |         flush();
130 |         ob_flush();
131 | 
132 |         $todos = $userDao->getCount();
133 |         echo "Usuários totais: " . $todos . PHP_EOL;
134 | 
135 |         $migrarAinda = $userDao->countWhere("mauticId is null");
136 |         echo "Usuários para migrar ainda: " . $migrarAinda . PHP_EOL;
137 | 
138 |         $migrados = $userDao->countWhere("mauticId is not null");
139 |         echo "Usuários migrados: " . $migrados . " (" . round(($migrados / $todos) * 100, 2) . "%)" . PHP_EOL;
140 | 
141 |         echo "
"; 142 | 143 | 144 | // Bora continuar 145 | echo ""; 146 | flush(); 147 | ob_flush(); 148 | } 149 | 150 | 151 | } 152 | -------------------------------------------------------------------------------- /app/src/Controller/TrilhaController.php: -------------------------------------------------------------------------------- 1 | getDAO(); 22 | 23 | // Obter trilhas 24 | $trilhas = $dao->getAll(); 25 | 26 | // Renderizar lista 27 | $content = $this->fetchView("admin/trilha/lista.twig", ['registros' => $trilhas]); 28 | 29 | return $this->renderLayout($response, $content); 30 | } 31 | 32 | /** 33 | * Renderiza o formulário para inclusão 34 | * @param Request $request 35 | * @param Response $response 36 | * @param $args 37 | * @return mixed 38 | */ 39 | public function addAction(Request $request, Response $response, $args) 40 | { 41 | $daoJornada = JornadaDAO::getInstance($this->container->db); 42 | $jornada = $daoJornada->findById($args['id']); 43 | $content = $this->fetchView("admin/trilha/form.twig", ['jornada' => $jornada]); 44 | return $this->renderLayout($response, $content); 45 | } 46 | 47 | /** 48 | * Salva o novo registro incluido 49 | * @param Request $request 50 | * @param Response $response 51 | * @param $args 52 | * @return mixed 53 | */ 54 | public function addPostAction(Request $request, Response $response, $args) 55 | { 56 | // O id da jornada, está na URL.. exemplo: /admin/jornada/1/trilha/incluir/ 57 | $idJornada = $args['id']; 58 | $vars = $request->getParsedBody(); 59 | $vars['id_jornada'] = $idJornada; 60 | try { 61 | /* @var $dao TrilhaDAO */ 62 | $dao = $this->getDao(); 63 | $dao->insertFromArray($vars); 64 | return $this->redirect($response, "jornadaListTrilhas", ['id' => $idJornada]); 65 | } catch (\Exception $e) { 66 | $error = $e->getMessage(); 67 | $content = $this->fetchView("admin/trilha/form.twig", ["error" => $error, "registro" => $vars]); 68 | return $this->renderLayout($response, $content); 69 | } 70 | } 71 | 72 | 73 | /** 74 | * Renderiza o formulário para edição 75 | * @param Request $request 76 | * @param Response $response 77 | * @param $args 78 | * @return mixed 79 | */ 80 | public function editAction(Request $request, Response $response, $args) 81 | { 82 | /* @var $registrto Trilha */ 83 | $registro = $this->getDAO()->findById($args['id']); 84 | $jornada = $registro->getJornada(); 85 | $content = $this->fetchView("admin/trilha/form.twig", ["jornada"=>$jornada, "registro" => $registro]); 86 | return $this->renderLayout($response, $content); 87 | } 88 | 89 | 90 | /** 91 | * Salva o registro alterado 92 | * @param Request $request 93 | * @param Response $response 94 | * @param $args 95 | * @return mixed 96 | */ 97 | public function editPostAction(Request $request, Response $response, $args) 98 | { 99 | $vars = $request->getParsedBody(); 100 | try { 101 | /* @var $dao TrilhaDAO */ 102 | $dao = $this->getDao(); 103 | $trilha = $dao->updateFromArray($args['id'], $vars, true); 104 | return $this->redirect($response, "jornadaListTrilhas", ['id' => $trilha->id_jornada]); 105 | } catch (\Exception $e) { 106 | $error = $e->getMessage(); 107 | $content = $this->fetchView("admin/trilha/form.twig", ["error" => $error, "registro" => $vars]); 108 | return $this->renderLayout($response, $content); 109 | } 110 | } 111 | 112 | 113 | /** 114 | * Exclui (tenta ao menos) um registro 115 | * @param Request $request 116 | * @param Response $response 117 | * @param $args 118 | * @return mixed 119 | */ 120 | public function deleteAction(Request $request, Response $response, $args) 121 | { 122 | $registro = $this->getDAO()->deleteById($args['id']); 123 | return $this->redirect($response, "trilhaIndex"); 124 | } 125 | 126 | /** 127 | * Obtem os desafios desta trilha 128 | * @param Request $request 129 | * @param Response $response 130 | * @param $args 131 | */ 132 | public function listDesafios(Request $request, Response $response, $args) 133 | { 134 | // Obter Trilha atual 135 | $trilha = $this->getDAO()->findById($args['id']); 136 | 137 | // Obter Desafios das Trilha 138 | $desafios = $trilha->getDesafios(); 139 | 140 | // Renderizar lista 141 | $content = $this->fetchView( 142 | "admin/desafio/lista.twig", 143 | [ 144 | 'trilha' => $trilha, 145 | 'registros' => $desafios 146 | ] 147 | ); 148 | 149 | return $this->renderLayout($response, $content); 150 | } 151 | 152 | /** 153 | * Retorna o DAO referente a este controller 154 | * Implementado apenas para forçar o tipo do retorno 155 | * Pode ser melhorado. :) 156 | * @return TrilhaDAO 157 | */ 158 | protected function getDAO($conexao = null) 159 | { 160 | return parent::getDAO(); 161 | } 162 | 163 | 164 | } 165 | -------------------------------------------------------------------------------- /public/images/certificado-duolingo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | 11 | 12 | 15 | 21 | 22 | 25 | 27 | 28 | 40 | 43 | 46 | 47 | 49 | 51 | 52 | 53 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/dependencies.php: -------------------------------------------------------------------------------- 1 | getContainer(); 8 | 9 | // view > Twig 10 | $container['view'] = function ($container) { 11 | $view = new \Slim\Views\Twig($container['settings']['view']['templatePath'], [ 12 | 'cache' => $container['settings']['view']['cachePath'] 13 | ]); 14 | 15 | // Instantiate and add Slim specific extension 16 | $basePath = rtrim(str_ireplace('index.php', '', $container['request']->getUri()->getBasePath()), '/'); 17 | $view->addExtension(new \Slim\Views\TwigExtension($container['router'], $basePath)); 18 | 19 | return $view; 20 | }; 21 | 22 | // view > Twig 23 | $container['model'] = function ($container) { 24 | echo "model"; 25 | return true; 26 | }; 27 | 28 | // mauticAuth -> retorna instância de autenticação do Mautic 29 | $container['mauticAuth'] = function ($container) { 30 | // Facilitar visualização das configurações 31 | $baseUrl = $container['settings']['mautic']['baseUrl']; 32 | $clientKey = $container['settings']['mautic']['clientKey']; 33 | $clientSecret = $container['settings']['mautic']['clientSecret']; 34 | $callback = $container['settings']['mautic']['callback']; 35 | $accessToken = isset($_SESSION['accessToken']) ? $_SESSION['accessToken'] : $container['settings']['mautic']['accessToken']; 36 | $refreshToken = isset($_SESSION['refreshToken']) ? $_SESSION['refreshToken'] : $container['settings']['mautic']['refreshToken']; 37 | $expires = isset($_SESSION['expires']) ? $_SESSION['expires'] : $container['settings']['mautic']['expires']; 38 | 39 | // Validar parâmetros 40 | $settings = array( 41 | 'baseUrl' => $baseUrl, 42 | 'clientKey' => $clientKey, 43 | 'clientSecret' => $clientSecret, 44 | 'callback' => $callback, 45 | 'version' => 'OAuth2', 46 | 'accessToken' => $accessToken, 47 | 'refreshToken' => $refreshToken, 48 | 'accessTokenExpires' => $expires 49 | ); 50 | 51 | /* @var $auth Mautic\Auth\OAuth */ 52 | $initAuth = new ApiAuth(); 53 | $auth = $initAuth->newAuth($settings); 54 | $auth->enableDebugMode(); 55 | 56 | try { 57 | if ($auth->validateAccessToken(false)) { 58 | // var_dump("validateAccessToken"); 59 | if ($auth->accessTokenUpdated()) { 60 | // var_dump("accessTokenUpdated"); 61 | $accessTokenData = $auth->getAccessTokenData(); 62 | var_dump("accessTokenUpdated"); 63 | var_dump($accessTokenData); 64 | // @todo Save $accessTokenData 65 | // @todo Display success authorization message 66 | Rollbar::info("AccessTokenUpdated"); 67 | $_SESSION['accessToken'] = $accessTokenData['access_token']; 68 | $_SESSION['refreshToken'] = $accessTokenData['refresh_token']; 69 | $_SESSION['expires'] = $accessTokenData['expires']; 70 | var_dump("session updated"); 71 | } else { 72 | var_dump("already authorized"); 73 | // @todo Display info message that this app is already authorized. 74 | } 75 | } else { 76 | // @todo Display info message that the token is not valid. 77 | var_dump("token is not valid"); 78 | } 79 | } catch (Exception $exception) { 80 | Rollbar::critical('mauticAuth fail', $exception); 81 | echo "

Exception on dependeces mauticAuth

"; 82 | echo "
";
 83 |         var_dump($exception);
 84 |         echo "
"; 85 | die(); 86 | } 87 | 88 | return $auth; 89 | }; 90 | 91 | //Not Found 92 | $container['notFoundHandler'] = function ($container) { 93 | return function ($request, $response) use ($container) { 94 | return $container->get('view')->render($response, '404.twig')->withStatus(404); 95 | }; 96 | }; 97 | 98 | //Database Connection 99 | $pdo = null; 100 | $container['db'] = function ($container) use ($pdo) { 101 | if ($pdo) { 102 | return $pdo; 103 | } 104 | 105 | // Facilitar visualização das configurações 106 | $host = $container['settings']['db']['host']; 107 | $port = $container['settings']['db']['port']; 108 | $dbname = $container['settings']['db']['dbname']; 109 | $user = $container['settings']['db']['user']; 110 | $pass = $container['settings']['db']['pass']; 111 | 112 | // Validar o mínimo 113 | if ($host == null || $dbname == null || $user == null) { 114 | throw new Exception("Os parametros de conexão com o banco de dados não foram definidos em settings.php na chave 'db'"); 115 | } 116 | 117 | // Tentar conexão 118 | try { 119 | $conexao = new PDO("mysql:host=$host;port=$port;dbname=$dbname", $user, $pass); 120 | $conexao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 121 | $conexao->exec("SET CHARACTER SET utf8"); 122 | 123 | // Share it over static class... 124 | global $pdo; 125 | $pdo = $conexao; 126 | } catch (PDOException $e) { 127 | var_dump($e); 128 | die("Erro de banco de dados"); 129 | throw $e; 130 | } 131 | 132 | return $conexao; 133 | }; 134 | 135 | $container['dbOld'] = function ($container) use ($pdo) { 136 | if ($pdo) { 137 | return $pdo; 138 | } 139 | 140 | // Facilitar visualização das configurações 141 | $host = $container['settings']['dbOld']['host']; 142 | $port = $container['settings']['dbOld']['port']; 143 | $dbname = $container['settings']['dbOld']['dbname']; 144 | $user = $container['settings']['dbOld']['user']; 145 | $pass = $container['settings']['dbOld']['pass']; 146 | 147 | // Validar o mínimo 148 | if ($host == null || $dbname == null || $user == null) { 149 | throw new Exception("Os parametros de conexão com o banco de dados não foram definidos em settings.php na chave 'dbOld'"); 150 | } 151 | 152 | // Tentar conexão 153 | try { 154 | $conexao = new PDO("mysql:host=$host;port=$port;dbname=$dbname", $user, $pass); 155 | $conexao->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 156 | $conexao->exec("SET CHARACTER SET utf8"); 157 | 158 | // Share it over static class... 159 | global $pdoOld; 160 | $pdoOld = $conexao; 161 | } catch (PDOException $e) { 162 | throw $e; 163 | die("Erro de banco de dados - doOld"); 164 | } 165 | 166 | return $conexao; 167 | }; 168 | 169 | // Iniciar Rollbar (https://rollbar.com 170 | if ($container['settings']['rollbar'] && ($container['settings']['environment'] !== 'dev' || (isset($container['settings']['rollbar']['run_on_dev'])))) 171 | Rollbar::init($container['settings']['rollbar']); 172 | 173 | $container['errorHandler'] = function ($container) { 174 | return function ($request, $response, $exception) use ($container) { 175 | 176 | if ($container['settings']['environment'] !== 'dev') { 177 | Rollbar::error($exception); 178 | echo "Algo muito errado aconteceu aqui dentro do servidor. É um problema mesmo, alguém terá que resolver. É você que resolve? Ou ainda está aprendendo?"; 179 | // var_dump($exception); 180 | // echo $e->getMessage(); 181 | die(); 182 | } else { 183 | var_dump($exception); 184 | echo $exception->getMessage(); 185 | die("errorHandler"); 186 | } 187 | 188 | // var_dump("errorHandler"); 189 | // var_dump($exception); 190 | // return $c['response']->withStatus(500) 191 | // ->withHeader('Content-Type', 'text/html') 192 | // ->write('Something went wrong!'); 193 | }; 194 | }; 195 | $container['phpErrorHandler'] = function ($container) { 196 | return function ($request, $response, $exception) use ($container) { 197 | 198 | if ($container['settings']['environment'] !== 'dev') { 199 | Rollbar::error($exception); 200 | echo "Algo muito errado aconteceu aqui dentro do servidor. É um problema mesmo, alguém terá que resolver. É você que resolve? Ou ainda está aprendendo?"; 201 | die(); 202 | } else { 203 | var_dump($exception); 204 | echo $exception->getMessage(); 205 | die("phpErrorHandler"); 206 | } 207 | 208 | return $container['response']->withStatus(500) 209 | ->withHeader('Content-Type', 'text/html') 210 | ->write('Something went wrong!'); 211 | }; 212 | }; 213 | 214 | // Adicionar Middleware para executar comandos no CLI 215 | $app->add(\adrianfalleiro\SlimCLIRunner::class); -------------------------------------------------------------------------------- /app/src/View/site/layout.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ siteTitle }} 5 | 6 | 7 | 8 | 9 | 10 | 12 | 15 | 18 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 100 |
101 | {{ content | raw }} 102 |
103 | 104 | 105 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /app/src/Command/MauticImportar.php: -------------------------------------------------------------------------------- 1 | get('redis'); 45 | $this->container = $container; 46 | 47 | // Obter conexão bom banco e API 48 | $conexao = $this->container->dbOld; 49 | $this->userDao = UsuarioOldDAO::getInstance($conexao); 50 | 51 | /** @var AuthInterface $auth */ 52 | $auth = $this->container->mauticAuth; 53 | $api = new MauticApi(); 54 | $this->contactApi = $api->newApi('contacts', $auth, $this->container['settings']['mautic']['baseUrl']); 55 | } 56 | 57 | /** 58 | * SampleTask command 59 | * 60 | * @param array $args 61 | * @return void 62 | */ 63 | public function command($args) 64 | { 65 | // Access items in container 66 | $settings = $this->container->get('settings'); 67 | 68 | $this->log("Limite para obtenção: " . $this->limit); 69 | 70 | $this->importar(); 71 | $this->atualizarEmailsInvalidos(); 72 | $this->atualizarContatos(); 73 | 74 | return true; 75 | } 76 | 77 | private function importar() 78 | { 79 | // Obter últimos X registros não sincronizados 80 | $this->log("============ Importar ============="); 81 | 82 | $users = $this->userDao->getWhere("mauticId is null", "id asc", $this->limit); 83 | 84 | $this->log("Usuários para sincronizar agora: " . count($users)); 85 | $this->log("The time is " . date("h:i:sa")); 86 | 87 | foreach ($users as $user) { 88 | $user->email = str_replace(" ", "", strtolower(trim($user->email))); 89 | // Ignorar usuários sem email ou com email inválido 90 | if (filter_var($user->email, FILTER_VALIDATE_EMAIL) == false) { 91 | $this->log(" Email inválido: " . $user->email); 92 | // Atualizar usuários com mauticId -1 para saber que não devem ser enviados ao mautic 93 | $user->mauticId = -1; 94 | $this->userDao->update($user); 95 | continue; 96 | } 97 | 98 | // Obter contato como objeto 99 | $contact = $user->getMauticObj(); 100 | // var_dump($contact); 101 | 102 | // Enviar ao mautic 103 | $response = $this->contactApi->create($contact); 104 | 105 | // var_dump($response['contact']['fields']['all']); 106 | // var_dump($response['contact']); 107 | 108 | // Salvar id remoto, localmente 109 | if (isset($response['contact']) && $response['contact']['id']) { 110 | $this->log(" Contato Id: " . $response['contact']['id'] . " - " . $response['contact']['fields']['all']['firstname'] . " - " . $response['contact']['fields']['all']['email']); 111 | $user->mauticId = $response['contact']['id']; 112 | $this->userDao->update($user); 113 | } else { 114 | 115 | $this->log(" FALHA ao criar contato no mautic"); 116 | $this->log(" $user->login (" . mb_detect_encoding($user->login) . ") - $user->nome (" . mb_detect_encoding($user->nome) . ")"); 117 | $code = null; 118 | if (isset($response['error'])) { 119 | // $this->log($response); 120 | $this->log(" Code: " . $response['error']['code']); 121 | $this->log(" Message: " . $response['error']['message']); 122 | $code = $response['error']['code']; 123 | } else { 124 | $this->log($response); 125 | } 126 | // die(); 127 | Rollbar::error("Importar Mautic - Code " . $code, ['response' => $response, 'contact' => $contact]); 128 | // Atualizar usuários com mauticId 0 para saber que devem ser corrigidos futuramente... 129 | $user->mauticId = 0; 130 | $this->userDao->update($user); 131 | } 132 | } 133 | 134 | $this->log("Fim da sincronização"); 135 | $this->log("The time is " . date("h:i:sa")); 136 | 137 | $todos = $this->userDao->getCount(); 138 | $this->log("Usuários totais: " . $todos); 139 | 140 | $migrarAinda = $this->userDao->countWhere("mauticId is null"); 141 | $this->log("Usuários para migrar ainda: " . $migrarAinda); 142 | 143 | $migrados = $this->userDao->countWhere("mauticId is not null"); 144 | $this->log("Usuários migrados: " . $migrados . " (" . round(($migrados / $todos) * 100, 2) . "%)"); 145 | } 146 | 147 | /** 148 | * Realiza a atualização dos usuários no mautic 149 | * - Atualiza pontuação 150 | * - Atualiza emails inválidos 151 | * @throws \Mautic\Exception\ContextNotFoundException 152 | */ 153 | private function atualizarEmailsInvalidos() 154 | { 155 | $this->log("============ atualizarEmailsInvalidos ============="); 156 | 157 | // mauticId -2 significa totalmente fora (DNC) 158 | // Atualizar emails inválidos para o mautic, setando DNC lá e mauticid -2 aqui 159 | $users = $this->userDao->getWhere("email_invalido is not null and mauticId is not null and mauticId<>-2 and mauticId>0", "id asc", $this->limit); 160 | $this->log("Usuários para sincronizar agora: " . count($users)); 161 | $this->log("The time is " . date("h:i:sa")); 162 | 163 | foreach ($users as $user) { 164 | // ADD DNC 165 | $response = $this->contactApi->addDnc($user->mauticId, 'email', 2, null, 'Via API'); 166 | 167 | // Salvar id remoto, localmente 168 | if (isset($response['contact']) && $response['contact']['id']) { 169 | $this->log(" Contato Id: " . $response['contact']['id'] . " - " . $user->nome); 170 | $user->mauticId = -2; 171 | $this->userDao->update($user); 172 | } else { 173 | $this->log(" FALHA com contato no mautic"); 174 | $this->log(" $user->login - $user->nome"); 175 | $code = null; 176 | if (isset($response['error'])) { 177 | // $this->log($response); 178 | $this->log(" Code: " . $response['error']['code']); 179 | $this->log(" Message: " . $response['error']['message']); 180 | $code = $response['error']['code']; 181 | } else { 182 | $this->log($response); 183 | } 184 | // die(); 185 | // Rollbar::error("Atualizar Mautic - Code " . $code, ['response' => $response, 'contact' => $contact]); 186 | die(); 187 | // Atualizar usuários com mauticId 0 para saber que devem ser corrigidos futuramente... 188 | // $user->mauticId = 0; 189 | // $this->userDao->update($user); 190 | } 191 | } 192 | 193 | $this->log("Fim da sincronização"); 194 | $this->log("The time is " . date("h:i:sa")); 195 | } 196 | 197 | /** 198 | * Realiza a atualização dos usuários no mautic 199 | * - Atualizar pontuação 200 | * - Atualiza último login 201 | * @throws \Mautic\Exception\ContextNotFoundException 202 | */ 203 | private function atualizarContatos() 204 | { 205 | // Obter últimos X registros não sincronizados 206 | $this->log("=========== atualizarContatos ============="); 207 | 208 | // Atualizar pontuação os usuários no mautic 209 | $users = $this->userDao->getWhere("coalesce(mauticId)>0 and total>0 and last_mautic_update is null", "total asc", $this->limit); 210 | $this->log("Usuários para sincronizar agora: " . count($users)); 211 | $this->log("The time is " . date("h:i:sa")); 212 | 213 | foreach ($users as $user) { 214 | 215 | // Obter contato como objeto 216 | $contact = $user->getMauticObj(); 217 | 218 | // Enviar ao mautic 219 | $response = $this->contactApi->edit($user->mauticId, $contact, false); 220 | 221 | // Salvar id remoto, localmente 222 | if (isset($response['contact']) && $response['contact']['id']) { 223 | $this->log(" Contato Id: " . $response['contact']['id'] . " - " . $user->nome . " - " . $user->email); 224 | $user->last_mautic_update = time(); 225 | $this->userDao->update($user); 226 | } else { 227 | $this->log(" FALHA com contato no mautic"); 228 | $this->log(" $user->login - $user->nome"); 229 | $code = null; 230 | if (isset($response['error'])) { 231 | // $this->log($response); 232 | $this->log(" Code: " . $response['error']['code']); 233 | $this->log(" Message: " . $response['error']['message']); 234 | $code = $response['error']['code']; 235 | } else { 236 | $this->log($response); 237 | } 238 | // die(); 239 | Rollbar::error("Atualizar Mautic - Code " . $code, ['response' => $response, 'contact' => $contact]); 240 | // die(); 241 | // Atualizar usuários com mauticId 0 para saber que devem ser corrigidos futuramente... 242 | $user->mauticId = 0; 243 | $this->userDao->update($user); 244 | } 245 | } 246 | 247 | $this->log("Fim da sincronização"); 248 | $this->log("The time is " . date("h:i:sa")); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /app/src/Model/DAO.php: -------------------------------------------------------------------------------- 1 | pdo = $pdo; 28 | } 29 | 30 | /** 31 | * Retorna o número de registros na tabela 32 | * @return Integer 33 | */ 34 | public function getCount() 35 | { 36 | $result = $this->pdo->prepare('select count(*) as count from ' . $this->tableName); 37 | $result->execute(); 38 | $result = $result->fetch(PDO::FETCH_ASSOC); 39 | return $result['count']; 40 | } 41 | 42 | /** 43 | * Procura no banco de dados por id e retorna o objeto 44 | * @param $id 45 | * @return mixed 46 | */ 47 | protected function _findById($id) 48 | { 49 | $sql = $this->pdo->prepare('select * from ' . $this->tableName . ' where id=:id'); 50 | $sql->bindValue(':id', $id, PDO::PARAM_INT); 51 | if ($sql->execute()) { 52 | return $sql->fetchObject($this->getInstanceNamespaceClassName()); 53 | } else { 54 | // Query failed. 55 | echo $sql->errorCode(); 56 | } 57 | } 58 | 59 | /** 60 | * Exclui um registro do banco 61 | * @param $id 62 | * @return mixed 63 | */ 64 | protected function _deleteById($id) 65 | { 66 | $sql = $this->pdo->prepare('delete from ' . $this->tableName . ' where id=:id'); 67 | $sql->bindValue(':id', $id, PDO::PARAM_INT); 68 | if ($sql->execute()) { 69 | return true; 70 | } else { 71 | die($sql->errorCode()); 72 | } 73 | } 74 | 75 | 76 | /** 77 | * Cria um novo registro a partir do objeto 78 | * @param $obj Objeto a ser inserido no banco 79 | * @param bool $returnInsertedObject Retornar o registro criado 80 | * @return \App\Model\UsuarioOld 81 | */ 82 | protected function _insert($obj, $returnInsertedObject = false) 83 | { 84 | try { 85 | $props = $this->getProps(); 86 | $insert = []; 87 | foreach ($props as $prop) { 88 | $insert[$prop] = ':' . $prop; 89 | } 90 | 91 | $fields = implode(',', array_keys($insert)); 92 | $values = implode(',', $insert); 93 | // var_dump($insert); var_dump($fields); var_dump($values); 94 | 95 | $sql = "INSERT INTO $this->tableName ($fields) VALUES ($values)"; 96 | // var_dump($sql); 97 | $sth = $this->pdo->prepare($sql); 98 | foreach ($insert as $field => $value) { 99 | $sth->bindValue(':' . $field, $obj->$field); 100 | } 101 | $r = $sth->execute(); 102 | 103 | if ($returnInsertedObject) { 104 | $lastID = $this->pdo->lastInsertId(); 105 | return $this->findById($lastID); 106 | } 107 | 108 | return $obj; 109 | } catch (PDOException $e) { 110 | echo $e->getMessage() . "

"; 111 | die('Database access FAILED!'); 112 | } catch (Exception $e) { 113 | echo $e->getMessage() . "

"; 114 | die('Database access FAILED!'); 115 | } 116 | 117 | } 118 | 119 | /** 120 | * Procura no banco de dados pelo registro e o retorna 121 | * @param $obj Objeto a ser atualizado no banco 122 | * @param bool $returnInsertedObject Retornar o registro criado 123 | * @return UsuarioOld 124 | */ 125 | protected function _update($obj, $returnInsertedObject = true) 126 | { 127 | try { 128 | // O objeto informado tem id? 129 | if ($obj->id == null) { 130 | throw new \Exception("O objeto passado em _update não tem id"); 131 | } 132 | $props = $this->getProps(); 133 | $fields = []; 134 | foreach ($props as $prop) { 135 | if (property_exists($obj, $prop)) 136 | $fields[$prop] = $prop . '=:' . $prop; 137 | } 138 | // var_dump($fields); 139 | $values = implode(', ', $fields); 140 | // var_dump($fields); 141 | // var_dump($values); 142 | 143 | 144 | $sql = "UPDATE $this->tableName SET $values WHERE id=$obj->id"; 145 | // var_dump($obj); 146 | // var_dump($sql); 147 | // die(); 148 | 149 | $sth = $this->pdo->prepare($sql); 150 | foreach ($fields as $field => $value) { 151 | $sth->bindValue(':' . $field, $obj->$field); 152 | } 153 | 154 | $r = $sth->execute(); 155 | // var_dump($r); 156 | 157 | if (!$r) { 158 | var_dump("r is false. Why?"); 159 | var_dump($sql); 160 | } 161 | 162 | if ($returnInsertedObject) { 163 | return $this->findById($obj->id); 164 | } 165 | 166 | return $obj; 167 | } catch (PDOException $e) { 168 | echo $e->getMessage() . "

"; 169 | die('Database access FAILED!'); 170 | } catch (Exception $e) { 171 | echo $e->getMessage() . "

"; 172 | die('Database access FAILED!'); 173 | } 174 | } 175 | 176 | /** 177 | * @todo 178 | * @param UsuarioOld $user 179 | */ 180 | public function _delete(UsuarioOld $user) 181 | { 182 | } 183 | 184 | /** 185 | * @todo 186 | * @param string $order 187 | */ 188 | public function _getAll(string $order = null, string $limit = null) 189 | { 190 | $query = 'SELECT * FROM ' . $this->tableName; 191 | if ($order) 192 | $query .= ' ORDER BY ' . $order; 193 | if ($limit) 194 | $query .= ' LIMIT ' . $limit; 195 | $sql = $this->pdo->prepare($query); 196 | if ($sql->execute()) { 197 | return $sql->fetchAll(PDO::FETCH_CLASS, $this->getInstanceNamespaceClassName()); 198 | } else { 199 | // Query failed. 200 | // Query failed. 201 | var_dump($sql->errorInfo()); 202 | var_dump($sql->errorCode()); 203 | die("Erro de sql em _getAll"); 204 | } 205 | } 206 | 207 | /** 208 | * @todo 209 | * @param string $where 210 | * @param string|null $order 211 | * @param string|null $limit 212 | * @return array 213 | */ 214 | public function _getWhere(string $where, string $order = null, int $limit = null, int $startingAt = null) 215 | { 216 | $query = 'SELECT * FROM ' . $this->tableName; 217 | if ($where) 218 | $query .= " WHERE $where"; 219 | if ($order) 220 | $query .= " ORDER BY $order"; 221 | if ($startingAt && $limit) 222 | $query .= " LIMIT $startingAt, $limit"; 223 | if ($limit) 224 | $query .= " LIMIT $limit"; 225 | $sql = $this->pdo->prepare($query); 226 | if ($sql->execute()) { 227 | return $sql->fetchAll(PDO::FETCH_CLASS, $this->getInstanceNamespaceClassName()); 228 | } else { 229 | // Query failed. 230 | var_dump($sql->errorInfo()); 231 | var_dump($sql->errorCode()); 232 | die("Erro de sql em _getWhere"); 233 | } 234 | } 235 | 236 | 237 | /** 238 | * @todo 239 | * @param string $where 240 | * @param string|null $order 241 | * @param string|null $limit 242 | * @return array 243 | */ 244 | public function _countWhere(string $where) 245 | { 246 | $query = 'SELECT count(*) as count FROM ' . $this->tableName . ' WHERE ' . $where; 247 | $sql = $this->pdo->prepare($query); 248 | if ($sql->execute()) { 249 | $count = $sql->fetch(PDO::FETCH_ASSOC); 250 | return $count['count']; 251 | } else { 252 | // Query failed. 253 | var_dump($sql->errorInfo()); 254 | var_dump($sql->errorCode()); 255 | die("Erro de sql em _countWhere"); 256 | } 257 | } 258 | 259 | /** 260 | * Retorna o nome da classe DAO com o namespace antes 261 | * Exemplo: App\Model\User 262 | * @return string 263 | */ 264 | protected function getInstanceNamespaceClassName() 265 | { 266 | return __NAMESPACE__ . '\\' . $this->instanceClassName; 267 | } 268 | 269 | /** 270 | * Retorna as props (atributos) da classe que representamos 271 | * Se a classe for User por exemplo, retornará um array com 272 | * ["id","nome","email",etc] 273 | * @return array 274 | */ 275 | private function getProps() 276 | { 277 | // Se já temos algo, devolvemos 278 | if ($this->props) return $this->props; 279 | 280 | // 281 | $reflect = new ReflectionClass($this->getInstanceNamespaceClassName()); 282 | $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE); 283 | $this->props = []; 284 | foreach ($props as $prop) { 285 | $this->props[$prop->getName()] = $prop->getName(); 286 | } 287 | 288 | // Armazenar na classe pra não precisar mais obter 289 | return $this->props; 290 | } 291 | 292 | 293 | /** 294 | * Cria um novo registro no banco a partir de um array (certamente vindo do POST) 295 | * @param $vars 296 | * @return mixed 297 | */ 298 | public function insertFromArray($vars) 299 | { 300 | // Validar dados recebidos 301 | $valid = $this->validatePostVars($vars); 302 | 303 | // Criar novo objeto 304 | $obj = $this->fromArray($vars); 305 | 306 | // Salvar 307 | $registro = $this->insert($obj); 308 | 309 | return $registro; 310 | } 311 | 312 | /** 313 | * Atualiza um novo registro no banco a partir de um array (certamente vindo do POST) 314 | * @param $vars 315 | * @return mixed 316 | */ 317 | public function updateFromArray(int $id, $vars, $returnInsertedObject = true) 318 | { 319 | // Validar dados recebidos 320 | $valid = $this->validatePostVars($vars); 321 | 322 | // Criar novo objeto 323 | $obj = $this->fromArray($vars); 324 | $obj->id = $id; 325 | 326 | 327 | // Salvar 328 | $registro = $this->_update($obj, $returnInsertedObject); 329 | 330 | return $registro; 331 | } 332 | 333 | 334 | /** 335 | * Cria um objeto do tipo da classe herdeira, a partir de um array 336 | * @param $array 337 | * @return mixed 338 | */ 339 | public function fromArray($array) 340 | { 341 | $className = $this->getInstanceNamespaceClassName(); 342 | $obj = new $className; 343 | foreach ($array as $fieldName => $fieldValue) { 344 | $obj->$fieldName = $fieldValue; 345 | } 346 | return $obj; 347 | } 348 | 349 | } -------------------------------------------------------------------------------- /app/src/View/site/home/home.twig: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | Logo Desafio do Código 7 |
8 |
9 |
10 |

Aprenda gratuitamente as habilidades necessárias 11 | para fazer jogos, animações e aplicativos.

12 |

13 | Descubra como hackear sua própria educação. 14 | Aprenda a programar. Programe para aprender. 15 |

16 |
17 | 22 |
23 |
24 |
25 | 26 | 27 |
28 |
29 |
30 |
31 |
O que é?
32 |

Desafio online com um conjunto de missões que guiam você aprender 33 | programação, matemática e inglês. Crie sua conta e comece a aprender!

34 |
35 |
36 |
37 |
38 |
39 |
40 |
Qual o objetivo?
41 |

Estimular o aprendizado das habilidades necessárias no Século XXI de 42 | forma lúdica, divertida, online e gratuita. Acessível a todos.

43 |
44 |
45 |
46 |
47 |
48 |
49 |
Quem pode participar?
50 |

Jovens de 8 a 108 anos, que estejam interessados em aprender mais, 51 | ganhar conhecimentos, ou simplesmente querem descobrir algo novo.

52 |
53 |
54 |
55 |
56 | 57 | 58 | 59 |
60 |
61 |

O que você vai conquistar com o Desafio do Código?

62 |
63 |
64 |
65 |
66 |
Certificados da Code.org
67 | Certificado da Code.org 69 |
70 |
71 |
72 |
73 |
74 |
75 |
Certificado Khan Academy
76 | Certificado Khan Academy 78 |
79 |
80 |
81 |
82 |
83 |
84 |
Proficiência em Inglês
85 | Duolingo 86 |
87 |
88 |
89 |
90 |
91 |
92 |
Linguagens de Programação
93 | Certificado da Code Academy 95 |
96 |
97 |
98 |
99 | 100 | 101 | 102 |
103 |
104 |

Pronto para encarar o Desafio?

105 |
106 |
107 | 112 |
113 |
114 | 115 | 116 | 117 |
118 | 119 |
120 |

“Poxa vida, mas não sei absolutamente nada de programação”.

121 |

Não se preocupe, nós te ensinaremos tudo passo a passo.

122 |
123 | 124 |
125 | 127 |
128 |
129 | 131 |
132 |
133 | 135 |
136 | 137 |
138 | 139 | 140 |
141 |
142 |

Está pensando em participar, mas ainda tem dúvidas?

143 |
144 |
145 |
146 |
147 |
Várias Jornadas
148 | Soaria Novaes 149 |

Você pode escolher dentre várias jornadas de conhecimento, onde 150 | seguirá por trilhas com pequenos desafios. Desta forma você aprende continuamente, de forma 151 | simples 152 | e objetiva.

153 |
154 |
155 |
156 |
157 |
Os Tutores
158 | Soaria Novaes 159 |

160 | Soraia Novaes é co-founder e tutora do CodeWars. Tradutora plena da Khan 161 | Academy, Professora certificada Google Trainer, Google Certified Innovator e autora do 162 | livro “Tecnologias para Inovação nas Escolas”.
163 | Soaria Novaes - Badges 164 |

165 |

166 | Tiago Gouvêa é co-founder e tutora do CodeWars. Tradutora plena da Khan 167 | Academy, Professora certificada Google Trainer, Google Certified Innovator e autora do 168 | livro “Tecnologias para Inovação nas Escolas”. 169 |

170 |

171 | 172 |

173 |
174 |
175 |
176 |
177 |
Peguntas Frequentes
178 | Interrogação 179 |

180 | Meu computador precisa ser potente? 181 | Não necessariamente, basta ter um navegador atualizado. 182 | Posso fazer tudo em casa? 183 | Sim, você pode fazer todos os desafios onde estiver. 184 | Preciso estar conectado sempre? 185 | Sim, utilizamos recursos online e você vai precisar de conexão com a internet para realizar os 186 | desafios. 187 | Preciso pagar alguma coisa? 188 | Não, a trilha do Desafio é gratuita. Caso você prefira, pode contar com um tutor para lhe 189 | acompanhar, contratando por hora. 190 | + Perguntas 191 |

192 |
193 |
194 |
195 |
196 | 197 | 198 |
200 |
201 |

Educadores são bem vindos!

202 |
Precisamos levar tecnologia para as salas de aulas, tornar o 203 | ensino mais interativo e contextualizado 204 | com o momento em que vivemos. 205 |
206 |
207 |
208 |
209 | Card image cap 211 |
212 |
Atualização para profesorres
213 |

Nosso programa contempla de forma abrangente a atualização dos 214 | professores, 215 | colocando-os em contato com novas ferramentas e tecnologias.

216 | Conhecer mais 217 | Card image cap 218 |
Tecnologias Google para Educação
219 |

A colaboração foi simplificada. Crie, compartilhe e edite arquivos em 220 | tempo 221 | real. Todos acompanham o conteúdo, que é armazenado automaticamente na nuvem. Use em 222 | qualquer dispositivo, tenha uma experiência consistente em qualquer computador, tablet 223 | ou 224 | telefone. Acesse seus arquivos a qualquer hora, em qualquer lugar.

225 | Conhecer mais 226 |
227 |
228 |
229 |
230 | 231 | 232 |
233 | 234 |
235 |
236 |

Programas que apoiamos

237 |
238 |
239 |
240 | Card image cap 242 |
243 |
Scratch
244 |
245 |
246 |
247 |
248 |
249 | Card image cap 251 |
252 |
Code
253 |
254 |
255 |
256 |
257 |
258 | Card image cap 260 |
261 |
Khan Academy
262 |
263 |
264 |
265 |
266 |
267 | Card image cap 269 |
270 |
Women in Technology
271 |
272 |
273 |
274 |
275 |
276 | Card image cap 278 |
279 |
Women Who Code
280 |
281 |
282 |
283 |
284 |
285 | Card image cap 287 |
288 |
Eu Posso Programar
289 |
290 |
291 |
292 |
293 |
294 | Card image cap 296 |
297 |
Women TechMakers
298 |
299 |
300 |
301 |
302 |
303 | Card image cap 305 |
306 |
FreeCodeCamp
307 |
308 |
309 |
310 |
311 |
312 | Card image cap 314 |
315 |
Girls Who Code
316 |
317 |
318 |
319 |
320 |
321 | Card image cap 323 |
324 |
Programaê
325 |
326 |
327 |
328 |
329 |
330 | Card image cap 332 |
333 |
Technovation
334 |
335 |
336 |
337 |
338 |
339 | Card image cap 341 |
342 |
Code Club Br
343 |
344 |
345 |
346 |
347 |
348 | Card image cap 350 |
351 |
Mulheres na Computação
352 |
353 |
354 |
355 |
356 |
357 | Card image cap 359 |
360 |
Django Girls
361 |
362 |
363 |
364 |
365 |
366 | Card image cap 368 |
369 | Programaria 370 |
371 |
372 |
373 |
374 |
375 | Card image cap 377 |
378 |
Code Girl
379 |
380 |
381 |
382 |
383 |
384 | 385 | 386 | 387 |
388 |
389 |

Pronto para começar agora?

390 |
391 |
392 | 397 |
398 |
--------------------------------------------------------------------------------