├── 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 |
13 | Este endereço não chega a lugar nenhum...
14 | ...acho que devemos considerar isso um grande problema.
15 |
18 | | Nome | 7 |Login | 8 |Acesso | 9 |Registro | 10 |
|---|---|---|---|
| {{ registro.nome }} | 16 |{{ registro.login }} | 17 |{{ registro.last_login }} | 18 |{{ registro.DataAdd }} | 19 |
| Nome | 7 |Login | 8 |Tipo | 9 |10 | |
|---|---|---|---|
| {{ registro.nome }} | 16 |{{ registro.login }} | 17 |{{ registro._tipo }} | 18 |19 | Editar 20 | Excluir 21 | | 22 |
| Desafio | 8 |Ordem | 9 |Ativo | 10 |11 | |
|---|---|---|---|
| {{ registro.titulo }} | 17 |{{ registro.ordem }} | 18 |{{ registro.ativo ? "Sim" : "Não"}} | 19 |20 | Editar 21 | Excluir 22 | | 23 |
| Jornada | 7 |Ativa | 8 |9 | | |
|---|---|---|---|
| {{ registro.titulo }} | 15 |{{ registro.ativa ? "Sim" }} | 16 |17 | Trilhas 18 | | 19 |20 | Editar 21 | Excluir 22 | | 23 |
| Trilha | 8 |Ativa | 9 |10 | | |
|---|---|---|---|
| {{ registro.titulo }} | 16 |{{ registro.ativa ? "Sim" }} | 17 |18 | Desafios 19 | | 20 |21 | Editar 22 | Excluir 23 | | 24 |
"; 49 | print_r($var); 50 | echo ""; 51 | } -------------------------------------------------------------------------------- /public/favicon/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 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 |
"; 41 | print_r($response); 42 | } 43 | 44 | echo "34 | 35 | -------------------------------------------------------------------------------- /app/src/View/admin/usuarioOld/form.twig: -------------------------------------------------------------------------------- 1 |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 |7 | {{ error }} 8 |9 | {% endif %} 10 | 11 | 12 |
";
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 |
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 |
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 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Certificado Khan Academy
76 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | Proficiência em Inglês
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | Linguagens de Programação
93 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
242 |
243 | Scratch
244 |
245 |
246 |
247 |
248 |
249 |
251 |
252 | Code
253 |
254 |
255 |
256 |
257 |
258 |
260 |
261 | Khan Academy
262 |
263 |
264 |
265 |
266 |
267 |
269 |
270 | Women in Technology
271 |
272 |
273 |
274 |
275 |
276 |
278 |
279 | Women Who Code
280 |
281 |
282 |
283 |
284 |
285 |
287 |
288 | Eu Posso Programar
289 |
290 |
291 |
292 |
293 |
294 |
296 |
297 | Women TechMakers
298 |
299 |
300 |
301 |
302 |
303 |
305 |
306 | FreeCodeCamp
307 |
308 |
309 |
310 |
311 |
312 |
314 |
315 | Girls Who Code
316 |
317 |
318 |
319 |
320 |
321 |
323 |
324 | Programaê
325 |
326 |
327 |
328 |
329 |
330 |
332 |
333 | Technovation
334 |
335 |
336 |
337 |
338 |
339 |
341 |
342 | Code Club Br
343 |
344 |
345 |
346 |
347 |
348 |
350 |
351 | Mulheres na Computação
352 |
353 |
354 |
355 |
356 |
357 |
359 |
360 | Django Girls
361 |
362 |
363 |
364 |
365 |
366 |
368 |
369 | Programaria
370 |
371 |
372 |
373 |
374 |
375 |
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 |
--------------------------------------------------------------------------------