Parcourir la source

Commit inicial

ElPoteito il y a 1 an
commit
a28e6b08cc
100 fichiers modifiés avec 8146 ajouts et 0 suppressions
  1. 34 0
      .gitignore
  2. 29 0
      LICENSE.md
  3. 1 0
      README.md
  4. 92 0
      Vagrantfile
  5. 31 0
      assets/AppAsset.php
  6. 27 0
      codeception.yml
  7. 24 0
      commands/BdController.php
  8. 51 0
      commands/ComandoController.php
  9. 130 0
      commands/DependenciaController.php
  10. 1343 0
      commands/EventoController.php
  11. 104 0
      commands/NotificacionController.php
  12. 231 0
      commands/UsuarioController.php
  13. 75 0
      components/FirebaseHelper.php
  14. 38 0
      components/NotificacionController.php
  15. 148 0
      components/Whatsapp.php
  16. 83 0
      composer.json
  17. 33 0
      config/__autocomplete.php
  18. 48 0
      config/console.php
  19. 13 0
      config/db.php
  20. 12 0
      config/firebase-key.json
  21. 10 0
      config/params.php
  22. 42 0
      config/test.php
  23. 6 0
      config/test_db.php
  24. 92 0
      config/web.php
  25. 128 0
      controllers/SiteController.php
  26. 9 0
      docker-compose.yml
  27. 22 0
      mail/layouts/html.php
  28. 94 0
      migrations/m220310_234138_inicio.php
  29. 59 0
      migrations/m230127_213733_tablas_eventos.php
  30. 29 0
      migrations/m230130_173821_campos_uid_tablas.php
  31. 45 0
      migrations/m230130_184544_tabla_grupos_eventos.php
  32. 56 0
      migrations/m230130_220056_redes.php
  33. 28 0
      migrations/m230131_203636_ajuste_dependencias.php
  34. 73 0
      migrations/m230213_234921_views.php
  35. 47 0
      migrations/m230420_191735_notificaciones.php
  36. 37 0
      migrations/m230427_164031_dependencia_lideres.php
  37. 24 0
      migrations/m230506_001938_notificacion_plantilla.php
  38. 24 0
      migrations/m230515_183220_ajustes_usuario.php
  39. 47 0
      migrations/m230530_233715_tabla_EventoResumen.php
  40. 27 0
      migrations/m230531_172644_eventoresumen_dependencia.php
  41. 77 0
      models/Dependencia.php
  42. 65 0
      models/DependenciaLider.php
  43. 120 0
      models/Evento.php
  44. 55 0
      models/EventoAccion.php
  45. 65 0
      models/EventoGrupo.php
  46. 59 0
      models/EventoResumen.php
  47. 68 0
      models/EventoResumenDependencia.php
  48. 104 0
      models/EventoResumenParticipante.php
  49. 94 0
      models/Grupo.php
  50. 72 0
      models/Notificacion.php
  51. 78 0
      models/NotificacionUsuario.php
  52. 61 0
      models/Red.php
  53. 75 0
      models/Resultado.php
  54. 125 0
      models/Usuario.php
  55. 65 0
      models/UsuarioDependencia.php
  56. 65 0
      models/UsuarioGrupo.php
  57. 38 0
      modules/common/Module.php
  58. 159 0
      modules/common/data/Respuesta.php
  59. 127 0
      modules/common/models/Usuario.php
  60. 33 0
      modules/common/rest/AuthController.php
  61. 83 0
      modules/common/rest/JsonController.php
  62. 19 0
      modules/common/rest/Serializer.php
  63. 17 0
      modules/common/rest/UrlRule.php
  64. 38 0
      modules/v1/Module.php
  65. 102 0
      modules/v1/controllers/ComparativaDependenciaController.php
  66. 28 0
      modules/v1/controllers/DefaultController.php
  67. 85 0
      modules/v1/controllers/DependenciaController.php
  68. 85 0
      modules/v1/controllers/EventoAccionController.php
  69. 735 0
      modules/v1/controllers/EventoController.php
  70. 116 0
      modules/v1/controllers/EventoNotificacionController.php
  71. 90 0
      modules/v1/controllers/EventoResumenController.php
  72. 85 0
      modules/v1/controllers/GrupoController.php
  73. 85 0
      modules/v1/controllers/RedController.php
  74. 346 0
      modules/v1/controllers/ReporteGlobalController.php
  75. 169 0
      modules/v1/controllers/ReporteIndividualController.php
  76. 85 0
      modules/v1/controllers/ResultadoController.php
  77. 69 0
      modules/v1/controllers/ResultadosIndividualesController.php
  78. 83 0
      modules/v1/controllers/UsuarioController.php
  79. 38 0
      modules/v1/models/Dependencia.php
  80. 30 0
      modules/v1/models/DependenciaLider.php
  81. 57 0
      modules/v1/models/Evento.php
  82. 25 0
      modules/v1/models/EventoAccion.php
  83. 32 0
      modules/v1/models/EventoGrupo.php
  84. 29 0
      modules/v1/models/EventoResumen.php
  85. 31 0
      modules/v1/models/EventoResumenDependencia.php
  86. 45 0
      modules/v1/models/EventoResumenParticipante.php
  87. 46 0
      modules/v1/models/Grupo.php
  88. 36 0
      modules/v1/models/NotificacionUsuario.php
  89. 29 0
      modules/v1/models/Notificacon.php
  90. 27 0
      modules/v1/models/Red.php
  91. 36 0
      modules/v1/models/Resultado.php
  92. 22 0
      modules/v1/models/Sesion.php
  93. 57 0
      modules/v1/models/Usuario.php
  94. 32 0
      modules/v1/models/UsuarioDependencia.php
  95. 32 0
      modules/v1/models/UsuarioGrupo.php
  96. 162 0
      requirements.php
  97. 2 0
      runtime/.gitignore
  98. 6 0
      tests/_bootstrap.php
  99. 1 0
      tests/_data/.gitkeep
  100. 0 0
      tests/_output/.gitignore

+ 34 - 0
.gitignore

@@ -0,0 +1,34 @@
+# phpstorm project files
+.idea
+.vscode
+
+# netbeans project files
+nbproject
+
+# zend studio for eclipse project files
+.buildpath
+.project
+.settings
+
+# windows thumbnail cache
+Thumbs.db
+
+# composer vendor dir
+/vendor
+
+# composer itself is not needed
+composer.phar
+
+# Mac DS_Store Files
+.DS_Store
+
+# phpunit itself is not needed
+phpunit.phar
+# local phpunit config
+/phpunit.xml
+
+tests/_output/*
+tests/_support/_generated
+
+#vagrant folder
+/.vagrant

+ 29 - 0
LICENSE.md

@@ -0,0 +1,29 @@
+Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+ * Neither the name of Yii Software LLC nor the names of its
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.

+ 1 - 0
README.md

@@ -0,0 +1 @@
+### Aquí se puede guardar detalles del proyecto

+ 92 - 0
Vagrantfile

@@ -0,0 +1,92 @@
+require 'yaml'
+require 'fileutils'
+
+required_plugins_installed = nil
+required_plugins = %w( vagrant-hostmanager vagrant-vbguest )
+required_plugins.each do |plugin|
+  unless Vagrant.has_plugin? plugin
+    system "vagrant plugin install #{plugin}"
+    required_plugins_installed = true
+  end
+end
+
+# IF plugin[s] was just installed - restart required
+if required_plugins_installed
+  # Get CLI command[s] and call again
+  system 'vagrant' + ARGV.to_s.gsub(/\[\"|\", \"|\"\]/, ' ')
+  exit
+end
+
+domains = {
+  app: 'yii2basic.test'
+}
+
+vagrantfile_dir_path = File.dirname(__FILE__)
+
+config = {
+  local: vagrantfile_dir_path + '/vagrant/config/vagrant-local.yml',
+  example: vagrantfile_dir_path + '/vagrant/config/vagrant-local.example.yml'
+}
+
+# copy config from example if local config not exists
+FileUtils.cp config[:example], config[:local] unless File.exist?(config[:local])
+# read config
+options = YAML.load_file config[:local]
+
+# check github token
+if options['github_token'].nil? || options['github_token'].to_s.length != 40
+  puts "You must place REAL GitHub token into configuration:\n/yii2-app-basic/vagrant/config/vagrant-local.yml"
+  exit
+end
+
+# vagrant configurate
+Vagrant.configure(2) do |config|
+  # select the box
+  config.vm.box = 'bento/ubuntu-18.04'
+
+  # should we ask about box updates?
+  config.vm.box_check_update = options['box_check_update']
+
+  config.vm.provider 'virtualbox' do |vb|
+    # machine cpus count
+    vb.cpus = options['cpus']
+    # machine memory size
+    vb.memory = options['memory']
+    # machine name (for VirtualBox UI)
+    vb.name = options['machine_name']
+  end
+
+  # machine name (for vagrant console)
+  config.vm.define options['machine_name']
+
+  # machine name (for guest machine console)
+  config.vm.hostname = options['machine_name']
+
+  # network settings
+  config.vm.network 'private_network', ip: options['ip']
+
+  # sync: folder 'yii2-app-advanced' (host machine) -> folder '/app' (guest machine)
+  config.vm.synced_folder './', '/app', owner: 'vagrant', group: 'vagrant'
+
+  # disable folder '/vagrant' (guest machine)
+  config.vm.synced_folder '.', '/vagrant', disabled: true
+
+  # hosts settings (host machine)
+  config.vm.provision :hostmanager
+  config.hostmanager.enabled            = true
+  config.hostmanager.manage_host        = true
+  config.hostmanager.ignore_private_ip  = false
+  config.hostmanager.include_offline    = true
+  config.hostmanager.aliases            = domains.values
+
+  # quick fix for failed guest additions installations
+  # config.vbguest.auto_update = false
+
+  # provisioners
+  config.vm.provision 'shell', path: './vagrant/provision/once-as-root.sh', args: [options['timezone'], options['ip']]
+  config.vm.provision 'shell', path: './vagrant/provision/once-as-vagrant.sh', args: [options['github_token']], privileged: false
+  config.vm.provision 'shell', path: './vagrant/provision/always-as-root.sh', run: 'always'
+
+  # post-install message (vagrant console)
+  config.vm.post_up_message = "App URL: http://#{domains[:app]}"
+end

+ 31 - 0
assets/AppAsset.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace app\assets;
+
+use yii\web\AssetBundle;
+
+/**
+ * Main application asset bundle.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class AppAsset extends AssetBundle
+{
+    public $basePath = '@webroot';
+    public $baseUrl = '@web';
+    public $css = [
+        'css/site.css',
+    ];
+    public $js = [
+    ];
+    public $depends = [
+        'yii\web\YiiAsset',
+        'yii\bootstrap4\BootstrapAsset',
+    ];
+}

+ 27 - 0
codeception.yml

@@ -0,0 +1,27 @@
+actor: Tester
+bootstrap: _bootstrap.php
+paths:
+    tests: tests
+    log: tests/_output
+    data: tests/_data
+    helpers: tests/_support
+settings:
+    memory_limit: 1024M
+    colors: true
+modules:
+    config:
+        Yii2:
+            configFile: 'config/test.php'
+
+# To enable code coverage:
+#coverage:
+#    #c3_url: http://localhost:8080/index-test.php/
+#    enabled: true
+#    #remote: true
+#    #remote_config: '../codeception.yml'
+#    whitelist:
+#        include:
+#            - models/*
+#            - controllers/*
+#            - commands/*
+#            - mail/*

+ 24 - 0
commands/BdController.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace app\commands;
+
+use yii\console\Controller;
+use yii\console\ExitCode;
+
+class BdController extends Controller {
+
+  public function actionInsertarUsuario() {
+    $usuario = new \app\models\Usuario();
+    $usuario->correo = "hquijada@edesarrollos.com";
+    $usuario->rfc = "QUGH900512";
+    $usuario->agregarClave("123456");
+    $usuario->nombre = "Hugo";
+    $usuario->apellidoPaterno = "Quijada";
+    $usuario->apellidoMaterno = "García";
+    if(!$usuario->save()) {
+      $this->stdout(json_encode($usuario->getFirstErrors()));
+    }
+    return ExitCode::OK;
+  }
+
+}

+ 51 - 0
commands/ComandoController.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace app\commands;
+
+use app\components\Whatsapp;
+use yii\console\Controller;
+
+class ComandoController extends Controller {
+
+  public function actionEnviarMensaje() {
+
+    $params = \Yii::$app->params;
+    $wab = null;
+    if(isset($params["wab"])) {
+      $wab = $params["wab"];
+    }
+
+    if($wab === null) {
+      $this->stdout("No existe la configuración\n");
+    }
+
+    $msgTo = "526621115643";
+    $template = "laud_resumen_eventos";
+    $template = "informe_de_eventos";
+
+    $eventos = "5/5 eventos";
+    $mensaje = "gracias por tu ";
+
+    try {
+      $wa = (new Whatsapp())
+        ->set_access_token($wab["access-token"])
+        ->msg_from($wab["phone-id"])
+        ->msg_to($msgTo)
+        ->template($template)
+        ->add_body_param($eventos)
+        ->add_body_param($mensaje)
+        ->send_template_message();
+      
+      if($wa === null) {
+        $this->stdout("Ocurrió un error al enviar el mensaje\n");
+        return;
+      }
+
+      $this->stdout("Proceso terminado\n");
+    } catch (\Exception $e) {
+      $this->stdout("Error al enviar el mensaje: {$e->getMessage()}\n");
+    }
+
+  }
+
+}

+ 130 - 0
commands/DependenciaController.php

@@ -0,0 +1,130 @@
+<?php
+
+namespace app\commands;
+
+use app\components\FirebaseHelper;
+use v1\models\Dependencia;
+use v1\models\DependenciaLider;
+use v1\models\Usuario;
+use yii\console\Controller;
+use yii\helpers\Json;
+
+class DependenciaController extends Controller {
+
+  public function stdoutln($cadena) {
+    return $this->stdout($cadena . "\n");
+  }
+
+  public function cambiarFecha($string) {
+    $formato = "D M d Y H:i:s P";
+    $fecha = \DateTime::createFromFormat($formato, $string);
+
+    return $fecha;
+  }
+
+  public function actionSincronizar() {
+
+    $firebase = new FirebaseHelper();
+    $firestore = $firebase->firestore();
+
+    $refUsuarios = $firestore->collection("usuarios");
+
+    $usuarios = [];
+
+    foreach ($refUsuarios->documents() as $usuario) {
+      $usuarios[$usuario->id()] = $usuario->data();
+    }
+
+    $ultimaFecha = null;
+    $limite = 100; // 1000;
+    $continuar = true;
+
+    do {
+      $this->stdout("Sincronizando ...");
+      $ref = $firestore->collection("dependencias")
+        ->where("sincronizado", "==", null)
+        ->orderBy("timestamp", "ASC")
+        ->limit($limite);
+
+      if ($ultimaFecha !== null) {
+        $ref = $ref->startAt([$ultimaFecha]);
+      }
+
+      $c = 0; # Contador de registros procesados
+      foreach ($ref->documents() as $doc) {
+        $this->stdoutln($doc->id());
+        $c++;
+        $data = $doc->data();
+        $ultimaFecha = $data["timestamp"];
+        $modelo = Dependencia::findOne(["firebaseId" => $doc->id()]);
+        if ($modelo === null) {
+          $modelo = new Dependencia();
+        }
+        try {
+          $modelo->nombre = $data["nombre"];
+          $modelo->descripcion = $data["descripcion"];
+          $modelo->estatus = $data["estatus"];
+          $modelo->firebaseId = $doc->id();
+
+          $creado = \DateTime::createFromFormat('Y-m-d\TH:i:s.u\Z', $data["timestamp"]);
+          if ($creado !== false) {
+            $modelo->creado = $creado->format(\DateTime::RFC3339_EXTENDED);
+          }
+
+          if (!$modelo->save()) {
+            $this->stdoutln('Ocurrió un error al guardar una dependencia. ' . Json::encode($modelo->getFirstErrors()));
+          }
+
+          if (isset($data["usuarios"])) {
+            foreach ($data["usuarios"] as $usuarioDependencia) {
+              $usuarioModelo = Usuario::findOne(["uid" => $usuarioDependencia["uid"]]);
+              $usuarioRef = isset($usuarios[$usuarioDependencia["uid"]])
+                ? $usuarios[$usuarioDependencia["uid"]] : null;
+  
+              if ($usuarioModelo !== null && $usuarioRef !== null) {
+                $usuarioDependencia = DependenciaLider::find()
+                  ->andWhere([
+                    "idUsuario" => $usuarioModelo->id,
+                    "idDependencia" => $modelo->id
+                  ])
+                  ->one();
+  
+                if ($usuarioDependencia === null) {
+                  $usuarioDependencia = new DependenciaLider();
+  
+                  $usuarioDependencia->idUsuario = $usuarioModelo->id;
+                  $usuarioDependencia->idDependencia = $modelo->id;
+  
+                  if (!$usuarioDependencia->save()) {
+                    $this->stdoutln('Ocurrió un error al guardar un lider de dependencia. ' . Json::encode($usuarioDependencia->getFirstErrors()));
+                  }
+                }
+              }
+            }
+          }
+
+          $hoy = new \DateTime();
+          $doc->reference()
+            ->update([
+              ["path" => "sincronizado", "value" => "OK"],
+              ["path" => "sincronizadoFecha", "value" => $hoy->format("Y-m-d H:i:s")],
+            ]);
+          $this->stdoutln("Sincronizado correcto");
+        } catch (\Exception $e) {
+          $this->stdoutln("Exception: {$e->getMessage()}\n");
+          $doc->reference()
+            ->update([
+              ["path" => "sincronizado", "value" => "ERROR"],
+              ["path" => "sincronizadoError", "value" => $e->getMessage()],
+              ["path" => "sincronizadoErrorLine", "value" => $e->getLine()],
+            ]);
+        }
+      }
+
+      # Si los registros procesados son menores al límite, terminar
+      if ($c < $limite) {
+        $continuar = false;
+      }
+    } while ($continuar);
+  }
+}

Fichier diff supprimé car celui-ci est trop grand
+ 1343 - 0
commands/EventoController.php


+ 104 - 0
commands/NotificacionController.php

@@ -0,0 +1,104 @@
+<?php
+
+namespace app\commands;
+
+use app\components\NotificacionController as Controller;
+use app\components\Whatsapp;
+use app\models\Notificacion;
+use app\models\NotificacionUsuario;
+
+class NotificacionController extends Controller {
+
+  public function actionParticipacion() {
+
+    $notificacion = $this->consultarNotificacion();
+    if ($notificacion === null) {
+      $this->stdout("No hay notificaciones pendientes\n");
+      return;
+    }
+
+    $this->stdout("Procesando notificación {$notificacion->id}\n");
+
+    $params = \Yii::$app->params;
+    $wab = null;
+    if(isset($params["wab"])) {
+      $wab = $params["wab"];
+    }
+
+    if($wab === null) {
+      $this->stdout("No existe la configuración\n");
+    }
+
+    try {
+      /** @var \app\models\Notificacion $notificacion */
+      $notificacion->estatus = Notificacion::ESTATUS_ENVIANDO;
+      $notificacion->save();
+
+      $notificacionUsuario = NotificacionUsuario::find()
+        ->andWhere(["idNotificacion" => $notificacion->id]);
+
+      foreach ($notificacionUsuario->each() as $nu) {
+        // if ($nu->telefono !== '6624473145' && $nu->telefono !== '6621564051' && $nu->telefono !== '6621115643'){
+        //   continue;
+        // }
+        $this->stdout("Enviando mensaje a ".$nu->telefono."\n");
+        /** @var \app\models\NotificacionUsuario $nu */
+        // $msgTo = "526624473145";
+        $msgTo = $nu->telefono;
+        if (strlen($nu->telefono) === 10) {
+          $msgTo = "52".$nu->telefono;
+        }
+        $template = "laud_resumen_eventos";
+        if($nu->plantilla) {
+          $template = $nu->plantilla;
+        }
+        // $template = "informe_de_eventos";
+
+        try {
+          $wa = (new Whatsapp())
+            ->set_access_token($wab["access-token"])
+            ->msg_from($wab["phone-id"])
+            ->msg_to($msgTo)
+            ->template($template);
+
+          foreach ($nu['parametros'] as $param) {
+            $wa->add_body_param($param['text'], $param['type']);
+          }
+            $resultado = $wa->send_template_message();
+          
+          if($resultado === null) {
+            $this->stdout("Ocurrió un error al enviar el mensaje\n");
+            return;
+          }
+
+          $nu->detalle = $resultado;
+          $nu->save();
+
+          // $this->stdout("Proceso terminado\n");
+        } catch (\Exception $e) {
+          $this->stdout("Error al enviar el mensaje: {$e->getMessage()}\n");
+        }
+      }
+
+      $notificacion->estatus = Notificacion::ESTATUS_TERMINADO;
+      $notificacion->save();
+    } catch(\Exception $e) {
+      $notificacion->estatus = Notificacion::ESTATUS_ERROR;
+      $notificacion->detalle = "Ocurrió un error en el servidor al generar la notificación {$e->getMessage()} {$e->getCode()}";
+      $notificacion->save();
+      $this->stdout($e->getMessage() . "\n");
+    }
+  }
+
+  public function actionFecha() {
+    $domingo = 0;
+    $fecha = strtotime('2023-05-07');
+    $dia = intval(date("w", $fecha));
+    if($dia !== $domingo) {
+      $fecha = strtotime('next Sunday');
+    }
+    
+    $siguienteDomingo = date("Y-m-d", $fecha);
+    $this->stdout("{$siguienteDomingo}\n");
+  }
+}

+ 231 - 0
commands/UsuarioController.php

@@ -0,0 +1,231 @@
+<?php
+
+namespace app\commands;
+
+use app\components\FirebaseHelper;
+use v1\models\Dependencia;
+use v1\models\Grupo;
+use v1\models\Usuario;
+use v1\models\UsuarioDependencia;
+use v1\models\UsuarioGrupo;
+use yii\console\Controller;
+use yii\db\Expression;
+use yii\helpers\Json;
+
+class UsuarioController extends Controller {
+
+  public function stdoutln($cadena) {
+    return $this->stdout($cadena . "\n");
+  }
+
+  public function cambiarFecha($string) {
+    $formato = "D M d Y H:i:s P";
+    $fecha = \DateTime::createFromFormat($formato, $string);
+
+    return $fecha;
+  }
+
+  public function actionSincronizar() {
+
+    $firebase = new FirebaseHelper();
+    $firestore = $firebase->firestore();
+
+    $ultimaFecha = null;
+    $limite = 100; // 1000;
+    $continuar = true;
+
+    do {
+      $this->stdout("Sincronizando ...");
+      $ref = $firestore->collection("usuarios")
+        ->where("sincronizado", "==", null)
+        ->orderBy("timestamp", "ASC")
+        ->limit($limite);
+
+      if ($ultimaFecha !== null) {
+        $ref = $ref->startAt([$ultimaFecha]);
+      }
+
+      $c = 0; # Contador de registros procesados
+      foreach ($ref->documents() as $doc) {
+        $this->stdoutln($doc->id());
+        $c++;
+        $data = $doc->data();
+        $ultimaFecha = $data["timestamp"];
+        $modelo = Usuario::findOne(["uid" => $doc->id()]);
+        if ($modelo === null) {
+          $modelo = new Usuario();
+        }
+        try {
+          $modelo->uid = $data["uid"];
+          $modelo->nombre = $data["nombre"];
+          if (isset($data["email"])) {
+            $modelo->email = $data["email"];
+          }
+          $modelo->telefono = $data["telefono"];
+          $modelo->facebook = $data["facebook"];
+          if (isset($data["facebookVerificado"])) {
+            $modelo->facebookVerificado = $data["facebookVerificado"];
+          }
+          $modelo->instagram = $data["instagram"];
+          if (isset($data["instagramVerificado"])) {
+            $modelo->instagramVerificado = $data["instagramVerificado"];
+          }
+          $modelo->twitter = $data["twitter"];
+          if (isset($data["twitterVerificado"])) {
+            $modelo->twitterVerificado = $data["twitterVerificado"];
+          }
+          $modelo->genero = $data["genero"];
+          $modelo->verificado = $data["verificado"];
+          if (isset($data["liderGlobal"])) {
+            $modelo->liderGlobal = $data["liderGlobal"];
+          }
+
+          if (!$modelo->save()) {
+            $this->stdoutln('Ocurrió un error al guardar un usuario. ' . Json::encode($modelo->getFirstErrors()));
+          }
+
+          $creado = \DateTime::createFromFormat('Y-m-d\TH:i:s.u\Z', $data["timestamp"]);
+          if ($creado !== false) {
+            $modelo->creado = new Expression("now()");
+          }
+
+          if ($data["estatus"] === false) {
+            $modelo->eliminado = $creado->format(\DateTime::RFC3339_EXTENDED);
+          }
+
+          if (!$modelo->save()) {
+            $this->stdoutln('Ocurrió un error al guardar un usuario. ' . Json::encode($modelo->getFirstErrors()));
+          }
+
+          if (isset($data["grupos"])) {
+            for($i = 0; $i < count($data["grupos"]); $i++){
+              
+              $modeloGrupo = Grupo::findOne(["firebaseId" => $data["grupos"][$i]]);
+
+              if (isset($modeloGrupo)) {
+                $usuarioGrupo = UsuarioGrupo::find()
+                  ->andWhere([
+                    "idUsuario" => $modelo->id,
+                    "idGrupo" => $modeloGrupo->id
+                  ])
+                  ->one();
+
+                if ($usuarioGrupo === null) {
+                  $usuarioGrupo = new UsuarioGrupo();
+
+                  $usuarioGrupo->idUsuario = $modelo->id;
+                  $usuarioGrupo->idGrupo = $modeloGrupo->id;
+
+                  if (!$usuarioGrupo->save()) {
+                    $this->stdoutln('Ocurrió un error al guardar un usuario-grupo. ' . Json::encode($usuarioGrupo->getFirstErrors()));
+                  }
+                }
+              }
+            }
+          }
+
+          if (isset($data["dependencias"])) {
+            if (is_array($data["dependencias"])) {
+              for($i = 0; $i < count($data["dependencias"]); $i++){
+                
+                $modeloDependencia = Grupo::findOne(["firebaseId" => $data["dependencias"][$i]]);
+  
+                if (isset($modeloDependencia)) {
+                  $usuarioDependencia = UsuarioDependencia::find()
+                    ->andWhere([
+                      "idUsuario" => $modelo->id,
+                      "idDependencia" => $modeloDependencia->id
+                    ])
+                    ->one();
+  
+                  if ($usuarioDependencia === null) {
+                    $usuarioDependencia = new UsuarioDependencia();
+  
+                    $usuarioDependencia->idUsuario = $modelo->id;
+                    $usuarioDependencia->idDependencia = $modeloDependencia->id;
+  
+                    if (!$usuarioDependencia->save()) {
+                      $this->stdoutln('Ocurrió un error al guardar un usuario-dependencia. ' . Json::encode($usuarioDependencia->getFirstErrors()));
+                    }
+                  }
+                }
+              }
+            } else {
+              $modeloDependencia = Dependencia::findOne(["firebaseId" => $data["dependencias"]]);
+  
+                if (isset($modeloDependencia)) {
+                  $usuarioDependencia = UsuarioDependencia::find()
+                    ->andWhere([
+                      "idUsuario" => $modelo->id,
+                      "idDependencia" => $modeloDependencia->id
+                    ])
+                    ->one();
+  
+                  if ($usuarioDependencia === null) {
+                    $usuarioDependencia = new UsuarioDependencia();
+  
+                    $usuarioDependencia->idUsuario = $modelo->id;
+                    $usuarioDependencia->idDependencia = $modeloDependencia->id;
+  
+                    if (!$usuarioDependencia->save()) {
+                      $this->stdoutln('Ocurrió un error al guardar un usuario-dependencia. ' . Json::encode($usuarioDependencia->getFirstErrors()));
+                    }
+                  }
+                }
+            }
+          }
+
+          $hoy = new \DateTime();
+          $doc->reference()
+            ->update([
+              ["path" => "sincronizado", "value" => "OK"],
+              ["path" => "sincronizadoFecha", "value" => $hoy->format("Y-m-d H:i:s")],
+            ]);
+          $this->stdoutln("Sincronizado correcto");
+        } catch (\Exception $e) {
+          $this->stdoutln("Exception: {$e->getMessage()}\n");
+          $doc->reference()
+            ->update([
+              ["path" => "sincronizado", "value" => "ERROR"],
+              ["path" => "sincronizadoError", "value" => $e->getMessage()],
+              ["path" => "sincronizadoErrorLine", "value" => $e->getLine()],
+            ]);
+        }
+      }
+
+      # Si los registros procesados son menores al límite, terminar
+      if ($c < $limite) {
+        $continuar = false;
+      }
+    } while ($continuar);
+  }
+
+  public function actionCambiarClave($uid, $clave) {
+    if(trim($uid) === "" || trim($clave) === "") {
+      return $this->stdout("Los parámetros uid y clave son obligatorios\n");
+    }
+
+    $firebase = new FirebaseHelper();
+    $auth = $firebase->authentication();
+
+    $res = $auth->changeUserPassword($uid, $clave);
+
+    $this->stdout("Proceso terminado \n");
+  }
+
+  public function actionCambiarTelefono($uid, $telefono) {
+    if(trim($uid) === "" || trim($telefono) === "") {
+      return $this->stdout("Los parámetros uid y telefono son obligatorios\n");
+    }
+
+    $firebase = new FirebaseHelper();
+    $auth = $firebase->authentication();
+
+    $telefono = trim($telefono);
+
+    $propiedades = ["phoneNumber" => "+52{$telefono}"];
+    $res = $auth->updateUser($uid, $propiedades);
+
+    $this->stdout("Proceso terminado \n");
+  }
+}

+ 75 - 0
components/FirebaseHelper.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace app\components;
+
+use Kreait\Firebase\Factory;
+use Kreait\Firebase\Messaging\CloudMessage;
+
+class FirebaseHelper {
+
+  const TIPO_PAGO = "pago";
+  const TIPO_PEDIDO = "pedido";
+  const TIPO_PROMOCION = "promocion";
+
+  private $_firebase = null;
+  private $_firestore = null;
+  private $_messaging = null;
+
+  function firebase() {
+    $params = \Yii::$app->params;
+    if($this->_firebase === null) {
+      $this->_firebase = (new Factory)
+        ->withServiceAccount($params['firebaseKey']);
+    }
+
+    return $this->_firebase;
+  }
+
+  function firestore() {
+    if($this->_firestore === null) {
+      $this->_firestore = self::firebase()
+        ->createFirestore()
+        ->database();
+    }
+
+    return $this->_firestore;
+  }
+
+  function messaging() {
+    if($this->_messaging === null) {
+      $this->_messaging = $this->firebase()
+        ->createMessaging();
+    }
+    return $this->_messaging;
+  }
+
+  public static function enviarNotificacion($idCliente, CloudMessage $notificacion) {
+    $model = new self();
+    return $model->enviar($idCliente, $notificacion);
+  }
+
+  public function enviar($idCliente, CloudMessage $notificacion) {
+    if(!$idCliente)
+      return null;
+
+    $firestore = $this->firestore();
+    $doc = $firestore->collection("clientes")
+      ->document($idCliente);
+
+    $data = $doc->snapshot()->data();
+    $tokens = $data["tokens"];
+
+    if(empty($tokens))
+      return null;
+    
+    $resultado = $this->messaging()->sendMulticast($notificacion, $tokens);
+    # Actualizar los tokens en firestore con los que si funcionaron
+    $tokenValidos = $resultado->validTokens();
+
+    $doc->update([
+      ["path" => "tokens", "value" => $tokenValidos],
+    ]);
+
+  }
+
+}

+ 38 - 0
components/NotificacionController.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace app\components;
+
+use app\models\Notificacion;
+use yii\console\Controller;
+use yii\db\Expression;
+
+class NotificacionController extends Controller {
+
+  public $debug = true;
+
+  public function stdout($texto) {
+    if ($this->debug) {
+      parent::stdout($texto);
+    }
+  }
+
+  public function consultarNotificacion() {
+
+    $query = Notificacion::find()
+      ->orderBy(["envio" => SORT_ASC]);
+
+    $enviando = (clone $query)
+      ->andWhere(["estatus" => Notificacion::ESTATUS_ENVIANDO])
+      ->one();
+    
+    if ($enviando !== null) {
+      $this->stdout("Notificación en poceso: ". $enviando->id ."\n");
+      return null;
+    }
+
+    return (clone $query)
+      ->andWhere(["<", "envio", new Expression('now()')])
+      ->andWhere(["estatus" => Notificacion::ESTATUS_NUEVO])
+      ->one();
+  }
+}

+ 148 - 0
components/Whatsapp.php

@@ -0,0 +1,148 @@
+<?php
+
+namespace app\components;
+
+use Exception;
+
+class Whatsapp {
+
+  private $_access_token = "";
+  public $base_url = "https://graph.facebook.com/%s/%s/%s";
+  public $components = [];
+  public $language_code = "es_MX";
+  public $message_product = "whatsapp";
+  public $_from = "";
+  public $_to = "";
+  public $version = "v14.0";
+  public $template_name = "";
+
+  public function __construct() {
+    $this->_access_token = "";
+    $this->_from = "";
+    $this->_to = "";
+    $this->template_name = "";
+    $this->components = [];
+  }
+
+  public function set_access_token($token) {
+    $this->_access_token = $token;
+    return $this;
+  }
+
+  public function msg_from($number = "") {
+    if (trim($number) == "") {
+      throw new Exception("From is required");
+    }
+
+    $this->_from = $number;
+    return $this;
+  }
+
+  public function msg_to($number = "") {
+    if (trim($number) == "") {
+      throw new Exception("To is required");
+    }
+
+    $this->_to = $number;
+    return $this;
+  }
+
+  public function template($name) {
+    if (trim($name) == "") {
+      // throw error
+      return;
+    }
+
+    $this->template_name = $name;
+    return $this;
+  }
+
+  public function add_component($type, $params = []) {
+    $this->components[$type] = $params;
+    return $this;
+  }
+
+  public function add_body_param($text, $type = "text") {
+    if (!isset($this->components["body"])) {
+      $this->components["body"] = [];
+    }
+
+    $dict = [
+      "type" => $type,
+      "text" => $text
+    ];
+    $this->components["body"][] = $dict;
+    return $this;
+  }
+
+  public function send_template_message() {
+    if (!$this->_to) {
+      throw new Exception("To is not defined");
+    }
+
+    if (!$this->_from) {
+      throw new Exception("From is not defined");
+    }
+
+    if (!$this->template_name) {
+      throw new Exception("Template Name is not defined");
+    }
+
+    $url = sprintf($this->base_url, $this->version, $this->_from, "messages");
+    $headers = [
+      'Authorization: Bearer ' . $this->_access_token,
+      'Content-Type: application/json'
+    ];
+
+    $components = [];
+    if (isset($this->components['header'])) {
+      $components[] = [
+        "type" => "header",
+        "parameters" => $this->components["header"]
+      ];
+    }
+
+    if (isset($this->components['body'])) {
+      $components[] = [
+        "type" => "body",
+        "parameters" => $this->components["body"]
+      ];
+    }
+
+    if (isset($this->components['footer'])) {
+      $components[] = [
+        "type" => "footer",
+        "parameters" => $this->components["footer"]
+      ];
+    }
+
+    $body = [
+      "messaging_product" => $this->message_product,
+      "to" => $this->_to,
+      "type" => "template",
+      "template" => [
+        "name" => $this->template_name,
+        "language" => [
+          "code" => $this->language_code
+        ],
+        "components" => $components
+      ]
+    ];
+
+    $ch = curl_init();
+    curl_setopt($ch, CURLOPT_URL, $url);
+    curl_setopt($ch, CURLOPT_POST, 1);
+    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
+    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+    $resultado = curl_exec($ch);
+    curl_close($ch);
+
+    try {
+      $json = json_decode($resultado);
+      return $json;
+    } catch(Exception $e) {
+      return null;
+    }
+  }
+}

+ 83 - 0
composer.json

@@ -0,0 +1,83 @@
+{
+    "name": "yiisoft/yii2-app-basic",
+    "description": "Yii 2 Basic Project Template",
+    "keywords": ["yii2", "framework", "basic", "project template"],
+    "homepage": "http://www.yiiframework.com/",
+    "type": "project",
+    "license": "BSD-3-Clause",
+    "support": {
+        "issues": "https://github.com/yiisoft/yii2/issues?state=open",
+        "forum": "http://www.yiiframework.com/forum/",
+        "wiki": "http://www.yiiframework.com/wiki/",
+        "irc": "irc://irc.freenode.net/yii",
+        "source": "https://github.com/yiisoft/yii2"
+    },
+    "minimum-stability": "stable",
+    "require": {
+        "php": ">=5.6.0",
+        "yiisoft/yii2": "~2.0.14",
+        "yiisoft/yii2-bootstrap4": "~2.0.0",
+        "yiisoft/yii2-swiftmailer": "~2.0.0 || ~2.1.0",
+        "firebase/php-jwt": "^5.4",
+        "kreait/firebase-php": "^6.2",
+        "google/cloud-firestore": "^1.27"
+    },
+    "require-dev": {
+        "yiisoft/yii2-debug": "~2.1.0",
+        "yiisoft/yii2-gii": "~2.2.0",
+        "yiisoft/yii2-faker": "~2.0.0",
+        "codeception/codeception": "^4.0",
+        "codeception/verify": "~0.5.0 || ~1.1.0",
+        "codeception/specify": "~0.4.6",
+        "symfony/browser-kit": ">=2.7 <=4.2.4",
+        "codeception/module-filesystem": "^1.0.0",
+        "codeception/module-yii2": "^1.0.0",
+        "codeception/module-asserts": "^1.0.0"
+    },
+    "config": {
+        "process-timeout": 1800,
+        "fxp-asset": {
+            "enabled": false
+        },
+        "allow-plugins": {
+            "yiisoft/yii2-composer": true
+        }
+    },
+    "scripts": {
+        "post-install-cmd": [
+            "yii\\composer\\Installer::postInstall"
+        ],
+        "post-create-project-cmd": [
+            "yii\\composer\\Installer::postCreateProject",
+            "yii\\composer\\Installer::postInstall"
+        ]
+    },
+    "extra": {
+        "yii\\composer\\Installer::postCreateProject": {
+            "setPermission": [
+                {
+                    "runtime": "0777",
+                    "web/assets": "0777",
+                    "yii": "0755"
+                }
+            ]
+        },
+        "yii\\composer\\Installer::postInstall": {
+            "generateCookieValidationKey": [
+                "config/web.php"
+            ]
+        }
+    },
+    "repositories": [
+        {
+            "type": "composer",
+            "url": "https://asset-packagist.org"
+        }
+    ],
+    "autoload": {
+        "psr-4": {
+            "common\\": "modules/common",
+            "v1\\": "modules/v1"
+        }
+    }
+}

+ 33 - 0
config/__autocomplete.php

@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * This class only exists here for IDE (PHPStorm/Netbeans/...) autocompletion.
+ * This file is never included anywhere.
+ * Adjust this file to match classes configured in your application config, to enable IDE autocompletion for custom components.
+ * Example: A property phpdoc can be added in `__Application` class as `@property \vendor\package\Rollbar|__Rollbar $rollbar` and adding a class in this file
+ * ```php
+ * // @property of \vendor\package\Rollbar goes here
+ * class __Rollbar {
+ * }
+ * ```
+ */
+class Yii {
+    /**
+     * @var \yii\web\Application|\yii\console\Application|__Application
+     */
+    public static $app;
+}
+
+/**
+ * @property yii\rbac\DbManager $authManager 
+ * @property \yii\web\User|__WebUser $user
+ * 
+ */
+class __Application {
+}
+
+/**
+ * @property app\models\User $identity
+ */
+class __WebUser {
+}

+ 48 - 0
config/console.php

@@ -0,0 +1,48 @@
+<?php
+
+$params = require __DIR__ . '/params.php';
+$db = require __DIR__ . '/db.php';
+
+$config = [
+  'id' => 'basic-console',
+  'basePath' => dirname(__DIR__),
+  'bootstrap' => ['log'],
+  'controllerNamespace' => 'app\commands',
+  'aliases' => [
+    '@bower' => '@vendor/bower-asset',
+    '@npm'   => '@vendor/npm-asset',
+    '@tests' => '@app/tests',
+  ],
+  'components' => [
+    'cache' => [
+      'class' => 'yii\caching\FileCache',
+    ],
+    'log' => [
+      'targets' => [
+        [
+          'class' => 'yii\log\FileTarget',
+          'levels' => ['error', 'warning'],
+        ],
+      ],
+    ],
+    'db' => $db,
+  ],
+  'params' => $params,
+  /*
+  'controllerMap' => [
+      'fixture' => [ // Fixture generation command line.
+          'class' => 'yii\faker\FixtureController',
+      ],
+  ],
+  */
+];
+
+if (YII_ENV_DEV) {
+  // configuration adjustments for 'dev' environment
+  $config['bootstrap'][] = 'gii';
+  $config['modules']['gii'] = [
+    'class' => 'yii\gii\Module',
+  ];
+}
+
+return $config;

+ 13 - 0
config/db.php

@@ -0,0 +1,13 @@
+<?php
+
+return [
+    'class' => 'yii\db\Connection',
+    'dsn' => 'pgsql:host=localhost;dbname=yager-local',
+    'username' => 'yager',
+    'password' => 'yager',
+    'charset' => 'utf8',
+    // Schema cache options (for production environment)
+    //'enableSchemaCache' => true,
+    //'schemaCacheDuration' => 60,
+    //'schemaCache' => 'cache',
+];

Fichier diff supprimé car celui-ci est trop grand
+ 12 - 0
config/firebase-key.json


+ 10 - 0
config/params.php

@@ -0,0 +1,10 @@
+<?php
+
+return [
+  'jwt.key' => 'XQky31fheBkkB5T4cYnD',
+  'firebaseKey' => __DIR__ . '/firebase-key.json',
+  'wab' => [ // WhatsAppBusiness
+    "access-token" => "EABRcl7XEGR8BAOuo807qQQNHMXQojPkNndwiCFWXwKZBKqgf0eUrzYTx8vkAFWBB6JUZCcdFTtwLqZAW6YtgmH43s4LHm3ztHaSx6ZCFDZC5D7cHY67L4t49GrxmyrIHRlbykZAmzYLRvXvADf5rSdBVZAZCKmXAPEFf5R1Oy3RzwwTWCiZADgJHi",
+    "phone-id" => "111886161708348",
+  ]
+];

+ 42 - 0
config/test.php

@@ -0,0 +1,42 @@
+<?php
+$params = require __DIR__ . '/params.php';
+$db = require __DIR__ . '/test_db.php';
+
+/**
+ * Application configuration shared by all test types
+ */
+return [
+    'id' => 'basic-tests',
+    'basePath' => dirname(__DIR__),
+    'aliases' => [
+        '@bower' => '@vendor/bower-asset',
+        '@npm'   => '@vendor/npm-asset',
+    ],
+    'language' => 'en-US',
+    'components' => [
+        'db' => $db,
+        'mailer' => [
+            'useFileTransport' => true,
+        ],
+        'assetManager' => [
+            'basePath' => __DIR__ . '/../web/assets',
+        ],
+        'urlManager' => [
+            'showScriptName' => true,
+        ],
+        'user' => [
+            'identityClass' => 'app\models\User',
+        ],
+        'request' => [
+            'cookieValidationKey' => 'test',
+            'enableCsrfValidation' => false,
+            // but if you absolutely need it set cookie domain to localhost
+            /*
+            'csrfCookie' => [
+                'domain' => 'localhost',
+            ],
+            */
+        ],
+    ],
+    'params' => $params,
+];

+ 6 - 0
config/test_db.php

@@ -0,0 +1,6 @@
+<?php
+$db = require __DIR__ . '/db.php';
+// test database! Important not to run tests on production or development databases
+$db['dsn'] = 'mysql:host=localhost;dbname=yii2basic_test';
+
+return $db;

+ 92 - 0
config/web.php

@@ -0,0 +1,92 @@
+<?php
+
+$params = require __DIR__ . '/params.php';
+$db = require __DIR__ . '/db.php';
+
+$config = [
+  'id' => 'basic',
+  'basePath' => dirname(__DIR__),
+  'bootstrap' => ['log'],
+  'aliases' => [
+    '@bower' => '@vendor/bower-asset',
+    '@npm'   => '@vendor/npm-asset',
+  ],
+  'components' => [
+    'request' => [
+      'cookieValidationKey' => 'MwDzyBzzBQMMA8d_tiCkX-h5oMhAg8jK',
+      'parsers' => [
+        'application/json' => 'yii\web\JsonParser',
+      ],
+    ],
+    'cache' => [
+      'class' => 'yii\caching\FileCache',
+    ],
+    'user' => [
+      'identityClass' => 'app\models\User',
+      'enableAutoLogin' => true,
+    ],
+    'errorHandler' => [
+      'errorAction' => 'site/error',
+    ],
+    'mailer' => [
+      'class' => 'yii\swiftmailer\Mailer',
+      // send all mails to a file by default. You have to set
+      // 'useFileTransport' to false and configure transport
+      // for the mailer to send real emails.
+      'useFileTransport' => true,
+    ],
+    'log' => [
+      'traceLevel' => YII_DEBUG ? 3 : 0,
+      'targets' => [
+        [
+          'class' => 'yii\log\FileTarget',
+          'levels' => ['error', 'warning'],
+        ],
+      ],
+    ],
+    'db' => $db,
+    'urlManager' => [
+      'enablePrettyUrl' => true,
+      'showScriptName' => false,
+      'rules' => [
+        [
+          'class' => 'common\rest\UrlRule',
+          'controller' => [
+            'v1/default',
+            'v1/dependencia',
+            'v1/evento',
+            'v1/grupo',
+            'v1/resultado',
+            'v1/usuario',
+            'v1/reporte-individual',
+            'v1/reporte-global',
+            'v1/evento-notificacion'
+          ],
+        ]
+      ],
+    ],
+  ],
+  'params' => $params,
+  'modules' => [
+    'v1' => ['class' => 'v1\Module'],
+  ]
+];
+
+if (YII_ENV_DEV) {
+  // configuration adjustments for 'dev' environment
+  $config['bootstrap'][] = 'debug';
+  $config['modules']['debug'] = [
+    'class' => 'yii\debug\Module',
+    // uncomment the following to add your IP if you are not connecting from localhost.
+    //'allowedIPs' => ['127.0.0.1', '::1'],
+  ];
+
+  $config['bootstrap'][] = 'gii';
+  $config['modules']['gii'] = [
+    'class' => 'yii\gii\Module',
+    // uncomment the following to add your IP if you are not connecting from localhost.
+    //'allowedIPs' => ['127.0.0.1', '::1'],
+  ];
+}
+
+return $config;

+ 128 - 0
controllers/SiteController.php

@@ -0,0 +1,128 @@
+<?php
+
+namespace app\controllers;
+
+use Yii;
+use yii\filters\AccessControl;
+use yii\web\Controller;
+use yii\web\Response;
+use yii\filters\VerbFilter;
+use app\models\LoginForm;
+use app\models\ContactForm;
+
+class SiteController extends Controller
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function behaviors()
+    {
+        return [
+            'access' => [
+                'class' => AccessControl::className(),
+                'only' => ['logout'],
+                'rules' => [
+                    [
+                        'actions' => ['logout'],
+                        'allow' => true,
+                        'roles' => ['@'],
+                    ],
+                ],
+            ],
+            'verbs' => [
+                'class' => VerbFilter::className(),
+                'actions' => [
+                    'logout' => ['post'],
+                ],
+            ],
+        ];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function actions()
+    {
+        return [
+            'error' => [
+                'class' => 'yii\web\ErrorAction',
+            ],
+            'captcha' => [
+                'class' => 'yii\captcha\CaptchaAction',
+                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
+            ],
+        ];
+    }
+
+    /**
+     * Displays homepage.
+     *
+     * @return string
+     */
+    public function actionIndex()
+    {
+        return $this->render('index');
+    }
+
+    /**
+     * Login action.
+     *
+     * @return Response|string
+     */
+    public function actionLogin()
+    {
+        if (!Yii::$app->user->isGuest) {
+            return $this->goHome();
+        }
+
+        $model = new LoginForm();
+        if ($model->load(Yii::$app->request->post()) && $model->login()) {
+            return $this->goBack();
+        }
+
+        $model->password = '';
+        return $this->render('login', [
+            'model' => $model,
+        ]);
+    }
+
+    /**
+     * Logout action.
+     *
+     * @return Response
+     */
+    public function actionLogout()
+    {
+        Yii::$app->user->logout();
+
+        return $this->goHome();
+    }
+
+    /**
+     * Displays contact page.
+     *
+     * @return Response|string
+     */
+    public function actionContact()
+    {
+        $model = new ContactForm();
+        if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
+            Yii::$app->session->setFlash('contactFormSubmitted');
+
+            return $this->refresh();
+        }
+        return $this->render('contact', [
+            'model' => $model,
+        ]);
+    }
+
+    /**
+     * Displays about page.
+     *
+     * @return string
+     */
+    public function actionAbout()
+    {
+        return $this->render('about');
+    }
+}

+ 9 - 0
docker-compose.yml

@@ -0,0 +1,9 @@
+version: '2'
+services:
+  php:
+    image: yiisoftware/yii2-php:7.4-apache
+    volumes:
+      - ~/.composer-docker/cache:/root/.composer/cache:delegated
+      - ./:/app:delegated
+    ports:
+      - '8000:80'

+ 22 - 0
mail/layouts/html.php

@@ -0,0 +1,22 @@
+<?php
+use yii\helpers\Html;
+
+/** @var \yii\web\View $this view component instance */
+/** @var \yii\mail\MessageInterface $message the message being composed */
+/** @var string $content main view render result */
+?>
+<?php $this->beginPage() ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" />
+    <title><?= Html::encode($this->title) ?></title>
+    <?php $this->head() ?>
+</head>
+<body>
+    <?php $this->beginBody() ?>
+    <?= $content ?>
+    <?php $this->endBody() ?>
+</body>
+</html>
+<?php $this->endPage() ?>

+ 94 - 0
migrations/m220310_234138_inicio.php

@@ -0,0 +1,94 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m220310_234138_inicio
+ */
+class m220310_234138_inicio extends Migration {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+
+    $this->createTable('Usuario', [
+      "id" => $this->primaryKey(),
+      "uid" => $this->string(50)->unique(),
+      "email" => $this->string(100)->notNull(),
+      "nombre" => $this->string(100)->notNull(),
+      "telefono" => $this->string(10),
+      "facebook" => $this->string(100),
+      "facebookVerificado" => $this->boolean(false),
+      "instagram" => $this->string(100),
+      "instagramVerificado" => $this->boolean(false),
+      "twitter" => $this->string(100),
+      "twitterVerificado" => $this->boolean(false),
+      "genero" => $this->string(50)->comment("H: Hombre - M: Mujer"),
+      "verificado" => $this->timestamp() . " with time zone",
+      "creado" => $this->timestamp() . " with time zone",
+      "modificado" => $this->timestamp() . " with time zone",
+      "eliminado" => $this->timestamp() . " with time zone",
+    ]);
+
+    $this->createTable('Dependencia', [
+      "id" => $this->primaryKey(),
+      "nombre" => $this->string(100)->notNull(),
+      "descripcion" => $this->text(),
+      "creado" => $this->timestamp() . " with time zone",
+      "modificado" => $this->timestamp() . " with time zone",
+      "eliminado" => $this->timestamp() . " with time zone",
+    ]);
+
+    $this->createTable('Grupo', [
+      "id" => $this->primaryKey(),
+      "nombre" => $this->string(100)->notNull(),
+      "descripcion" => $this->text(),
+      "creado" => $this->timestamp() . " with time zone",
+      "modificado" => $this->timestamp() . " with time zone",
+      "eliminado" => $this->timestamp() . " with time zone",
+    ]);
+
+    $this->createTable("UsuarioDependencia", [
+      "idUsuario" => $this->integer(),
+      "idDependencia" => $this->integer(),
+    ]);
+
+    $this->createTable("UsuarioGrupo", [
+      "idUsuario" => $this->integer(),
+      "idGrupo" => $this->integer(),
+    ]);
+
+    $this->addPrimaryKey('UsuarioGrupoPK', 'UsuarioGrupo', ['idUsuario', 'idGrupo']);
+    $this->addPrimaryKey('UsuarioDependenciaPK', 'UsuarioDependencia', ['idUsuario', 'idDependencia']);
+
+    $this->addForeignKey('UsuarioGrupoIdUsuarioFK', 'UsuarioGrupo', 'idUsuario', 'Usuario', 'id');
+    $this->addForeignKey('UsuarioGrupoIdGrupoFK', 'UsuarioGrupo', 'idGrupo', 'Grupo', 'id' );
+
+    $this->addForeignKey('UsuarioDependenciaIdUsuarioFK', 'UsuarioDependencia', 'idUsuario', 'Usuario', 'id');
+    $this->addForeignKey('UsuarioDependenciaIdDependenciaFK', 'UsuarioDependencia', 'idDependencia', 'Dependencia', 'id');
+		
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+
+    $this->dropForeignKey("UsuarioDependenciaIdDependenciaFK", "UsuarioDependencia");
+    $this->dropForeignKey("UsuarioDependenciaIdUsuarioFK", "UsuarioDependencia");
+
+    $this->dropForeignKey("UsuarioGrupoIdGrupoFK", "UsuarioGrupo");
+    $this->dropForeignKey("UsuarioGrupoIdUsuarioFK", "UsuarioGrupo");
+
+    $this->dropPrimaryKey("UsuarioDependenciaPK", "UsuarioDependencia");
+    $this->dropPrimaryKey("UsuarioGrupoPK", "UsuarioGrupo");
+    
+    $this->dropTable('UsuarioGrupo');
+    $this->dropTable('UsuarioDependencia');
+    $this->dropTable('Grupo');
+    $this->dropTable('Dependencia');
+    $this->dropTable('Usuario');
+  }
+
+}

+ 59 - 0
migrations/m230127_213733_tablas_eventos.php

@@ -0,0 +1,59 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230127_213733_tablas_eventos
+ */
+class m230127_213733_tablas_eventos extends Migration {
+	/**
+	 * {@inheritdoc}
+	 */
+	public function safeUp() {
+
+		$this->createTable('Evento', [
+      "id" => $this->primaryKey(),
+      "idGrupo" => $this->integer(),
+      "nombre" => $this->string(100)->notNull(),
+      "descripcion" => $this->string(255),
+      "fotoEvento" => $this->text(255),
+      "tag" => $this->string(50)->unique(),
+      "url" => $this->string(155)->notNull(),
+      "fechaInicio" => $this->timestamp() . " with time zone",
+      "fechaFinal" => $this->timestamp() . " with time zone",
+      "creado" => $this->timestamp() . " with time zone",
+      "modificado" => $this->timestamp() . " with time zone",
+      "eliminado" => $this->timestamp() . " with time zone",
+    ]);
+
+		$this->createTable('Resultado', [
+      "id" => $this->primaryKey(),
+      "idUsuario" => $this->integer(),
+      "idEvento" => $this->integer(),
+      "accion" => $this->string(20)->comment("ver,likes,compartir"),
+			"creado" => $this->timestamp() . " with time zone",
+      "modificado" => $this->timestamp() . " with time zone",
+      "eliminado" => $this->timestamp() . " with time zone",
+    ]);
+
+		$this->addForeignKey('EventoIdGrupoFK', 'Evento', 'idGrupo', 'Grupo', 'id');
+		$this->addForeignKey('ResultadoIdUsuarioFK', 'Resultado', 'idUsuario', 'Usuario', 'id');
+		$this->addForeignKey('ResultadoIdEventoFK', 'Resultado', 'idEvento', 'Evento', 'id');
+
+
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function safeDown() {
+
+		$this->dropForeignKey("ResultadoIdEventoFK", "Resultado");
+		$this->dropForeignKey("ResultadoIdUsuarioFK", "Resultado");
+		$this->dropForeignKey("EventoIdGrupoFK", "Evento");
+
+    $this->dropTable('Resultado');
+    $this->dropTable('Evento');
+
+	}
+}

+ 29 - 0
migrations/m230130_173821_campos_uid_tablas.php

@@ -0,0 +1,29 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230130_173821_campos_uid_tablas
+ */
+class m230130_173821_campos_uid_tablas extends Migration {
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+    $this->addColumn("Dependencia", "firebaseId", $this->string(50));
+    $this->addColumn("Evento", "firebaseId", $this->string(50));
+    $this->addColumn("Grupo", "firebaseId", $this->string(50)); 
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+    
+    $this->dropColumn("Grupo", "firebaseId");
+    $this->dropColumn("Evento", "firebaseId");
+    $this->dropColumn("Dependencia", "firebaseId");
+
+  }
+
+}

+ 45 - 0
migrations/m230130_184544_tabla_grupos_eventos.php

@@ -0,0 +1,45 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230130_184544_tabla_grupos_eventos
+ */
+class m230130_184544_tabla_grupos_eventos extends Migration {
+	/**
+	 * {@inheritdoc}
+	 */
+	public function safeUp() {
+
+		$this->createTable("EventoGrupo", [
+      "idEvento" => $this->integer(),
+      "idGrupo" => $this->integer(),
+    ]);
+		$this->addPrimaryKey('EventoGrupoPK', 'EventoGrupo', ['idEvento', 'idGrupo']);
+
+		$this->alterColumn("Evento", "nombre", $this->string(255)->notNull());
+		$this->alterColumn("Evento", "descripcion", $this->text());
+		$this->dropColumn("Evento", "idGrupo");
+
+		$this->addForeignKey('EventoGrupoIdEventoFK', 'EventoGrupo', 'idEvento', 'Evento', 'id');
+		$this->addForeignKey('EventoGrupoIdGrupoFK', 'EventoGrupo', 'idGrupo', 'Grupo', 'id');
+
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */	
+	public function safeDown() {
+
+		$this->dropForeignKey("EventoGrupoIdGrupoFK", "EventoGrupo");
+		$this->dropForeignKey("EventoGrupoIdEventoFK", "EventoGrupo");
+		
+		$this->addColumn("Evento", "idGrupo", $this->integer());
+		$this->alterColumn("Evento", "descripcion", $this->string(255));
+		$this->alterColumn("Evento", "nombre", $this->string(100)->notNull());
+
+		$this->dropPrimaryKey("EventoGrupoPK", "EventoGrupo");
+		$this->dropTable('EventoGrupo');
+	}
+
+}

+ 56 - 0
migrations/m230130_220056_redes.php

@@ -0,0 +1,56 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230130_220056_redes
+ */
+class m230130_220056_redes extends Migration {
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+
+    $this->createTable('Red', [
+      'idEvento' => $this->integer(),
+      'key' => $this->string(50),
+      'url' => $this->string(500),
+      'redSocial' => $this->string(250)
+    ]);
+
+    $this->addPrimaryKey('RedPK', 'Red', ['idEvento', 'url']);
+    $this->addForeignKey('RedEventoFK', 'Red', 'idEvento', 'Evento', 'id');
+
+    $this->addColumn('Evento', 'ciudad', $this->string(100));
+
+    $this->createTable('EventoAccion', [
+      'idEvento' => $this->integer(),
+      'accion' => $this->string(10)
+    ]);
+
+    $this->addPrimaryKey('EventoAccionPK', 'EventoAccion', ['idEvento', 'accion']);
+    $this->addForeignKey('EventoAccionEventoFK', 'EventoAccion', 'idEvento', 'Evento', 'id');
+
+    $this->alterColumn('Usuario', 'email', $this->string(100));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+
+    $this->alterColumn('Usuario', 'email', $this->string(100)->notNull());
+
+    $this->dropTable('EventoAccion');
+
+    $this->dropForeignKey('EventoAccionEventoFK', 'EventoAccion');
+    $this->dropPrimaryKey('EventoAccionPK', 'EventoAccion');
+
+    $this->dropColumn('Evento', 'ciudad');
+    
+    $this->dropForeignKey('RedEventoFK', 'Red');
+    $this->dropPrimaryKey('RedPK', 'Red');
+
+    $this->dropTable('Red');
+  }
+}

+ 28 - 0
migrations/m230131_203636_ajuste_dependencias.php

@@ -0,0 +1,28 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230131_203636_ajuste_dependencias
+ */
+class m230131_203636_ajuste_dependencias extends Migration {
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+
+    $this->addColumn('Dependencia', 'estatus', $this->boolean());
+    $this->addColumn('Evento', 'redSocial', $this->string(100));
+    $this->alterColumn('Evento', 'nombre', $this->string(500));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+    
+    $this->alterColumn('Evento', 'nombre', $this->string(255));
+    $this->dropColumn('Evento', 'redSocial');
+    $this->dropColumn('Dependencia', 'estatus');
+  }
+}

+ 73 - 0
migrations/m230213_234921_views.php

@@ -0,0 +1,73 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230213_234921_views
+ */
+class m230213_234921_views extends Migration {
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+
+    $this->execute('
+      create view public."ReporteIndividual" as
+      select
+            U.nombre,
+            U.facebook,
+            U."facebookVerificado",
+            U.twitter,
+            U."twitterVerificado",
+            U.instagram,
+            U."instagramVerificado",
+            U.id "idUsuario",
+            count(E."redSocial") filter ( where E."redSocial" = Facebook and U."facebookVerificado") as "cantidadFacebook",
+            count(E."redSocial") filter ( where E."redSocial" = Twitter and U."twitterVerificado") as "cantidadTwitter",
+            count(E."redSocial") filter ( where E."redSocial" = Instagram and U."instagramVerificado") as "cantidadInstagram",
+            --count(E.id) as "cantidadEventos",
+            count(R.accion) as "cantidadResultados"
+            --(count(E.id) - count(R.accion)) as "cantidadPendientes"
+          from "Evento" E
+          inner join "EventoGrupo" EG on E.id = EG."idEvento"
+          inner join "Grupo" G on G.id = EG."idGrupo"
+          inner join "UsuarioGrupo" UG on G.id = UG."idGrupo"
+          inner join "Usuario" U on U.id = UG."idUsuario"
+          left join "Resultado" R on E.id = R."idEvento" and R."idUsuario" = U.id
+          group by
+                  U.nombre,
+                  U.facebook,
+                  U."facebookVerificado",
+                  U.twitter,
+                  U."twitterVerificado",
+                  U.instagram,
+                  U."instagramVerificado",
+                  U.id
+      --    order by E.id
+      ;
+      ');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+    
+    $this->execute('drop view "ReporteIndividual";');
+  }
+
+  /*
+    // Use up()/down() to run migration code without a transaction.
+    public function up()
+    {
+
+    }
+
+    public function down()
+    {
+        echo "m230213_234921_views cannot be reverted.\n";
+
+        return false;
+    }
+    */
+}

+ 47 - 0
migrations/m230420_191735_notificaciones.php

@@ -0,0 +1,47 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230420_191735_notificaciones
+ */
+class m230420_191735_notificaciones extends Migration {
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+    $this->createTable('Notificacion', [
+      'id' => $this->primaryKey(),
+      'envio' => $this->timestamp().' with time zone',
+      'estatus' => $this->string(10),
+      'creado' => $this->timestamp().' with time zone',
+      'modificado' => $this->timestamp().' with time zone',
+      'detalle' => $this->json()
+    ]);
+
+    $this->createTable('NotificacionUsuario', [
+      'id' => $this->primaryKey(),
+      'idNotificacion' => $this->integer(),
+      'idUsuario' => $this->integer(),
+      'nombre' => $this->string(100),
+      'telefono' => $this->string(10),
+      'parametros' => $this->json(),
+      'detalle' => $this->json()
+    ]);
+
+    $this->addForeignKey('NotificacionUsuario_idNotificacion_FK', 'NotificacionUsuario', 'idNotificacion', 'Notificacion', 'id');
+    $this->addForeignKey('NotificacionUsuario_idUsuario_FK', 'NotificacionUsuario', 'idUsuario', 'Usuario', 'id');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+    $this->dropForeignKey('NotificacionUsuario_idUsuario_FK', 'NotificacionUsuario');
+    $this->dropForeignKey('NotificacionUsuario_idNotificacion_FK', 'NotificacionUsuario');
+
+    $this->dropTable('NotificacionUsuario');
+
+    $this->dropTable('Notificacion');
+  }
+}

+ 37 - 0
migrations/m230427_164031_dependencia_lideres.php

@@ -0,0 +1,37 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230427_164031_dependencia_lideres
+ */
+class m230427_164031_dependencia_lideres extends Migration {
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+
+    $this->createTable('DependenciaLider', [
+      "idDependencia" => $this->integer(),
+      "idUsuario" => $this->integer(),
+    ]);
+
+    $this->addPrimaryKey('DependenciaLider_PK', 'DependenciaLider', ['idDependencia', 'idUsuario']);
+
+    $this->addForeignKey('DependenciaLider_idDependencia_FK', 'DependenciaLider', 'idDependencia', 'Dependencia', 'id');
+    $this->addForeignKey('DependenciaLider_idUsuario_FK', 'DependenciaLider', 'idUsuario', 'Usuario', 'id');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+
+    $this->dropForeignKey('DependenciaLider_idDependencia_FK', 'DependenciaLider');
+    $this->dropForeignKey('DependenciaLider_idUsuario_FK', 'DependenciaLider');
+    
+    $this->dropPrimaryKey('DependenciaLider_PK', 'DependenciaLider');
+    
+    $this->dropTable('DependenciaLider');
+  }
+}

+ 24 - 0
migrations/m230506_001938_notificacion_plantilla.php

@@ -0,0 +1,24 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230506_001938_notificacion_plantilla
+ */
+class m230506_001938_notificacion_plantilla extends Migration {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+    $this->addColumn("NotificacionUsuario", "plantilla", $this->string(100));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+    $this->dropColumn("NotificacionUsuario", "plantilla");
+  }
+
+}

+ 24 - 0
migrations/m230515_183220_ajustes_usuario.php

@@ -0,0 +1,24 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230515_183220_ajustes_usuario
+ */
+class m230515_183220_ajustes_usuario extends Migration {
+  /**
+   * {@inheritdoc}
+   */
+  public function safeUp() {
+
+    $this->addColumn('Usuario', 'liderGlobal', $this->boolean());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function safeDown() {
+
+    $this->dropColumn('Usuario', 'liderGlobal');
+  }
+}

+ 47 - 0
migrations/m230530_233715_tabla_EventoResumen.php

@@ -0,0 +1,47 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230530_233715_tabla_EventoResumen
+ */
+class m230530_233715_tabla_EventoResumen extends Migration {
+	public function safeUp() {
+		$this->createTable('EventoResumen',[
+			"id"=>$this->primaryKey(),
+			"uuid"=>$this->string(50),
+			"inicio"=>$this->timestamp() . " with time zone",
+			"fin"=>$this->timestamp() . " with time zone",
+			"creado"=>$this->timestamp() . " with time zone",
+			"modificado"=>$this->timestamp() . " with time zone",
+		]);
+
+		$this->createTable('EventoResumenParticipante',[
+			"id"=>$this->primaryKey(),
+			"idEventoResumen"=>$this->integer(),
+			"idDependencia"=>$this->integer(),
+			"nombreDependencia"=>$this->string(250),
+			"idGrupo"=>$this->integer(),
+			"nombreGrupo"=>$this->string(250),
+			"idUsuario"=>$this->integer(),
+			"nombre"=>$this->string(100),
+			"totalEventos"=>$this->integer(),
+			"participacion"=>$this->string()
+		]);
+
+		$this->addForeignKey('EventoResumenPIdResumen_FK','EventoResumenParticipante','idEventoResumen','EventoResumen','id');
+		$this->addForeignKey('EventoResumenPIdDependencia_FK','EventoResumenParticipante','idDependencia','Dependencia','id');
+		$this->addForeignKey('EventoResumenPIdGrupo_FK','EventoResumenParticipante','idGrupo','Grupo','id');
+		$this->addForeignKey('EventoResumenPIdUsuario_FK','EventoResumenParticipante','idUsuario','Usuario','id');
+	}
+	public function safeDown() {
+		$this->dropForeignKey('EventoResumenPIdResumen_FK','EventoResumenParticipante');
+		$this->dropForeignKey('EventoResumenPIdDependencia_FK','EventoResumenParticipante');
+		$this->dropForeignKey('EventoResumenPIdGrupo_FK','EventoResumenParticipante');
+		$this->dropForeignKey('EventoResumenPIdUsuario_FK','EventoResumenParticipante');
+
+		$this->dropTable('EventoResumenParticipante');
+
+		$this->dropTable('EventoResumen');
+	}
+}

+ 27 - 0
migrations/m230531_172644_eventoresumen_dependencia.php

@@ -0,0 +1,27 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m230531_172644_eventoresumen_dependencia
+ */
+class m230531_172644_eventoresumen_dependencia extends Migration {
+  public function safeUp() {
+    $this->createTable('EventoResumenDependencia',[
+      "idEventoResumen"=>$this->integer(),
+      "idDependencia"=>$this->integer(),
+      "clave"=>$this->string(50)
+    ]);
+
+    $this->addForeignKey('idEventoResumenEventoResumenDependencia_FK','EventoResumenDependencia','idEventoResumen','EventoResumen','id');
+    $this->addForeignKey('idDependenciaEventoResumenDependencia_FK','EventoResumenDependencia','idDependencia','Dependencia','id');
+    $this->addPrimaryKey('EventoResumenDependencia_PK','EventoResumenDependencia',['idEventoResumen','idDependencia']);
+  }
+  public function safeDown() {
+    $this->dropForeignKey('idEventoResumenEventoResumenDependencia_FK','EventoResumenDependencia');
+    $this->dropForeignKey('idDependenciaEventoResumenDependencia_FK','EventoResumenDependencia');
+    $this->dropForeignKey('EventoResumenDependencia_PK','EventoResumenDependencia');
+
+    $this->dropTable('EventoResumenDependencia');
+  }
+}

+ 77 - 0
models/Dependencia.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "Dependencia".
+ *
+ * @property int $id
+ * @property string $nombre
+ * @property string|null $descripcion
+ * @property string|null $creado
+ * @property string|null $modificado
+ * @property string|null $eliminado
+ * @property string|null $firebaseId
+ * @property bool|null $estatus
+ *
+ * @property Usuario[] $usuarios
+ * @property UsuarioDependencia[] $usuariosDependencias
+ */
+class Dependencia extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'Dependencia';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['nombre'], 'required'],
+      [['descripcion'], 'string'],
+      [['creado', 'modificado', 'eliminado'], 'safe'],
+      [['estatus'], 'boolean'],
+      [['nombre'], 'string', 'max' => 100],
+      [['firebaseId'], 'string', 'max' => 50],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'id' => 'ID',
+      'nombre' => 'Nombre',
+      'descripcion' => 'Descripcion',
+      'creado' => 'Creado',
+      'modificado' => 'Modificado',
+      'eliminado' => 'Eliminado',
+      'firebaseId' => 'Firebase ID',
+      'estatus' => 'Estatus',
+    ];
+  }
+
+  /**
+   * Gets query for [[usuarios]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getUsuarios() {
+    return $this->hasMany(Usuario::className(), ['id' => 'idUsuario'])->viaTable('UsuarioDependencia', ['idDependencia' => 'id']);
+  }
+
+  /**
+   * Gets query for [[usuarioDependencias]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getUsuariosDependencias() {
+    return $this->hasMany(UsuarioDependencia::className(), ['idDependencia' => 'id']);
+  }
+}

+ 65 - 0
models/DependenciaLider.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "DependenciaLider".
+ *
+ * @property int $idDependencia
+ * @property int $idUsuario
+ *
+ * @property Dependencia $dependencia
+ * @property Usuario $usuario
+ */
+class DependenciaLider extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'DependenciaLider';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['idDependencia', 'idUsuario'], 'required'],
+      [['idDependencia', 'idUsuario'], 'default', 'value' => null],
+      [['idDependencia', 'idUsuario'], 'integer'],
+      [['idDependencia', 'idUsuario'], 'unique', 'targetAttribute' => ['idDependencia', 'idUsuario']],
+      [['idDependencia'], 'exist', 'skipOnError' => true, 'targetClass' => Dependencia::class, 'targetAttribute' => ['idDependencia' => 'id']],
+      [['idUsuario'], 'exist', 'skipOnError' => true, 'targetClass' => Usuario::class, 'targetAttribute' => ['idUsuario' => 'id']],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'idDependencia' => 'Id Dependencia',
+      'idUsuario' => 'Id Usuario',
+    ];
+  }
+
+  /**
+   * Gets query for [[dependencia]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getDependencia() {
+    return $this->hasOne(Dependencia::class, ['id' => 'idDependencia']);
+  }
+
+  /**
+   * Gets query for [[usuario]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getUsuario() {
+    return $this->hasOne(Usuario::class, ['id' => 'idUsuario']);
+  }
+}

+ 120 - 0
models/Evento.php

@@ -0,0 +1,120 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "Evento".
+ *
+ * @property int $id
+ * @property string $nombre
+ * @property string|null $descripcion
+ * @property string|null $fotoEvento
+ * @property string|null $tag
+ * @property string $url
+ * @property string|null $fechaInicio
+ * @property string|null $fechaFinal
+ * @property string|null $creado
+ * @property string|null $modificado
+ * @property string|null $eliminado
+ * @property string|null $firebaseId
+ * @property string|null $ciudad
+ * @property string|null $redSocial
+ *
+ * @property EventoAccion[] $eventoAccions
+ * @property EventoGrupo[] $eventoGrupos
+ * @property Grupo[] $grupos
+ * @property Red[] $reds
+ * @property Resultado[] $resultados
+ */
+class Evento extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'Evento';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['nombre', 'url'], 'required'],
+      [['descripcion', 'fotoEvento'], 'string'],
+      [['fechaInicio', 'fechaFinal', 'creado', 'modificado', 'eliminado'], 'safe'],
+      [['nombre'], 'string', 'max' => 500],
+      [['tag', 'firebaseId'], 'string', 'max' => 50],
+      [['url'], 'string', 'max' => 155],
+      [['ciudad', 'redSocial'], 'string', 'max' => 100],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'id' => 'ID',
+      'nombre' => 'Nombre',
+      'descripcion' => 'Descripcion',
+      'fotoEvento' => 'Foto Evento',
+      'tag' => 'Tag',
+      'url' => 'Url',
+      'fechaInicio' => 'Fecha Inicio',
+      'fechaFinal' => 'Fecha Final',
+      'creado' => 'Creado',
+      'modificado' => 'Modificado',
+      'eliminado' => 'Eliminado',
+      'firebaseId' => 'Firebase ID',
+      'ciudad' => 'Ciudad',
+      'redSocial' => 'Red Social',
+    ];
+  }
+
+  /**
+   * Gets query for [[eventoAcciones]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getEventoAcciones() {
+    return $this->hasMany(EventoAccion::class, ['idEvento' => 'id']);
+  }
+
+  /**
+   * Gets query for [[eventoGrupos]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getEventoGrupos() {
+    return $this->hasMany(EventoGrupo::class, ['idEvento' => 'id']);
+  }
+
+  /**
+   * Gets query for [[grupos]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getGrupos() {
+    return $this->hasMany(Grupo::class, ['id' => 'idGrupo'])->viaTable('EventoGrupo', ['idEvento' => 'id']);
+  }
+
+  /**
+   * Gets query for [[redes]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getRedes() {
+    return $this->hasMany(Red::class, ['idEvento' => 'id']);
+  }
+
+  /**
+   * Gets query for [[resultados]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getResultados() {
+    return $this->hasMany(Resultado::class, ['idEvento' => 'id']);
+  }
+}

+ 55 - 0
models/EventoAccion.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "EventoAccion".
+ *
+ * @property int $idEvento
+ * @property string $accion
+ *
+ * @property Evento $evento
+ */
+class EventoAccion extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'EventoAccion';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['idEvento', 'accion'], 'required'],
+      [['idEvento'], 'default', 'value' => null],
+      [['idEvento'], 'integer'],
+      [['accion'], 'string', 'max' => 10],
+      [['idEvento', 'accion'], 'unique', 'targetAttribute' => ['idEvento', 'accion']],
+      [['idEvento'], 'exist', 'skipOnError' => true, 'targetClass' => Evento::class, 'targetAttribute' => ['idEvento' => 'id']],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'idEvento' => 'Id Evento',
+      'accion' => 'Accion',
+    ];
+  }
+
+  /**
+   * Gets query for [[evento]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getEvento() {
+    return $this->hasOne(Evento::class, ['id' => 'idEvento']);
+  }
+}

+ 65 - 0
models/EventoGrupo.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "EventoGrupo".
+ *
+ * @property int $idEvento
+ * @property int $idGrupo
+ *
+ * @property Evento $evento
+ * @property Grupo $grupo
+ */
+class EventoGrupo extends \yii\db\ActiveRecord {
+	/**
+	 * {@inheritdoc}
+	 */
+	public static function tableName() {
+		return 'EventoGrupo';
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function rules() {
+		return [
+			[['idEvento', 'idGrupo'], 'required'],
+			[['idEvento', 'idGrupo'], 'default', 'value' => null],
+			[['idEvento', 'idGrupo'], 'integer'],
+			[['idEvento', 'idGrupo'], 'unique', 'targetAttribute' => ['idEvento', 'idGrupo']],
+			[['idEvento'], 'exist', 'skipOnError' => true, 'targetClass' => Evento::className(), 'targetAttribute' => ['idEvento' => 'id']],
+			[['idGrupo'], 'exist', 'skipOnError' => true, 'targetClass' => Grupo::className(), 'targetAttribute' => ['idGrupo' => 'id']],
+		];
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function attributeLabels() {
+		return [
+			'idEvento' => 'Id Evento',
+			'idGrupo' => 'Id Grupo',
+		];
+	}
+
+	/**
+	 * Gets query for [[evento]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getEvento() {
+		return $this->hasOne(Evento::className(), ['id' => 'idEvento']);
+	}
+
+	/**
+	 * Gets query for [[grupo]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getGrupo() {
+		return $this->hasOne(Grupo::className(), ['id' => 'idGrupo']);
+	}
+}

+ 59 - 0
models/EventoResumen.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "EventoResumen".
+ *
+ * @property int $id
+ * @property string|null $uuid
+ * @property string|null $inicio
+ * @property string|null $fin
+ * @property string|null $creado
+ * @property string|null $modificado
+ *
+ * @property EventoResumenParticipante[] $eventoResumenParticipantes
+ */
+class EventoResumen extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'EventoResumen';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['inicio', 'fin', 'creado', 'modificado'], 'safe'],
+      [['uuid'], 'string', 'max' => 50],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'id' => 'ID',
+      'uuid' => 'Uuid',
+      'inicio' => 'Inicio',
+      'fin' => 'Fin',
+      'creado' => 'Creado',
+      'modificado' => 'Modificado',
+    ];
+  }
+
+  /**
+   * Gets query for [[EventoResumenParticipantes]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getEventoResumenParticipantes() {
+    return $this->hasMany(EventoResumenParticipante::class, ['idEventoResumen' => 'id']);
+  }
+}

+ 68 - 0
models/EventoResumenDependencia.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "EventoResumenDependencia".
+ *
+ * @property int $idEventoResumen
+ * @property int $idDependencia
+ * @property string|null $clave
+ *
+ * @property Dependencia $Dependencia
+ * @property EventoResumen $EventoResumen
+ */
+class EventoResumenDependencia extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'EventoResumenDependencia';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['idEventoResumen', 'idDependencia'], 'required'],
+      [['idEventoResumen', 'idDependencia'], 'default', 'value' => null],
+      [['idEventoResumen', 'idDependencia'], 'integer'],
+      [['clave'], 'string', 'max' => 50],
+      [['idEventoResumen', 'idDependencia'], 'unique', 'targetAttribute' => ['idEventoResumen', 'idDependencia']],
+      [['idDependencia'], 'exist', 'skipOnError' => true, 'targetClass' => Dependencia::class, 'targetAttribute' => ['idDependencia' => 'id']],
+      [['idEventoResumen'], 'exist', 'skipOnError' => true, 'targetClass' => EventoResumen::class, 'targetAttribute' => ['idEventoResumen' => 'id']],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'idEventoResumen' => 'Id Evento Resumen',
+      'idDependencia' => 'Id Dependencia',
+      'clave' => 'Clave',
+    ];
+  }
+
+  /**
+   * Gets query for [[IdDependencia0]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getDependencia() {
+    return $this->hasOne(Dependencia::class, ['id' => 'idDependencia']);
+  }
+
+  /**
+   * Gets query for [[IdEventoResumen0]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getEventoResumen() {
+    return $this->hasOne(EventoResumen::class, ['id' => 'idEventoResumen']);
+  }
+}

+ 104 - 0
models/EventoResumenParticipante.php

@@ -0,0 +1,104 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "EventoResumenParticipante".
+ *
+ * @property int $id
+ * @property int|null $idEventoResumen
+ * @property int|null $idDependencia
+ * @property string|null $nombreDependencia
+ * @property int|null $idGrupo
+ * @property string|null $nombreGrupo
+ * @property int|null $idUsuario
+ * @property string|null $nombre
+ * @property int|null $totalEventos
+ * @property string|null $participacion
+ *
+ * @property Dependencia $Dependencia
+ * @property EventoResumen $EventoResumen
+ * @property Grupo $Grupo
+ * @property Usuario $Usuario
+ */
+class EventoResumenParticipante extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'EventoResumenParticipante';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['idEventoResumen', 'idDependencia', 'idGrupo', 'idUsuario', 'totalEventos'], 'default', 'value' => null],
+      [['idEventoResumen', 'idDependencia', 'idGrupo', 'idUsuario', 'totalEventos'], 'integer'],
+      [['nombreDependencia', 'nombreGrupo'], 'string', 'max' => 250],
+      [['nombre'], 'string', 'max' => 100],
+      [['participacion'], 'string', 'max' => 255],
+      [['idDependencia'], 'exist', 'skipOnError' => true, 'targetClass' => Dependencia::class, 'targetAttribute' => ['idDependencia' => 'id']],
+      [['idEventoResumen'], 'exist', 'skipOnError' => true, 'targetClass' => EventoResumen::class, 'targetAttribute' => ['idEventoResumen' => 'id']],
+      [['idGrupo'], 'exist', 'skipOnError' => true, 'targetClass' => Grupo::class, 'targetAttribute' => ['idGrupo' => 'id']],
+      [['idUsuario'], 'exist', 'skipOnError' => true, 'targetClass' => Usuario::class, 'targetAttribute' => ['idUsuario' => 'id']],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'id' => 'ID',
+      'idEventoResumen' => 'Id Evento Resumen',
+      'idDependencia' => 'Id Dependencia',
+      'nombreDependencia' => 'Nombre Dependencia',
+      'idGrupo' => 'Id Grupo',
+      'nombreGrupo' => 'Nombre Grupo',
+      'idUsuario' => 'Id Usuario',
+      'nombre' => 'Nombre',
+      'totalEventos' => 'Total Eventos',
+      'participacion' => 'Participacion',
+    ];
+  }
+
+  /**
+   * Gets query for [[Dependencia]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getDependencia() {
+    return $this->hasOne(Dependencia::class, ['id' => 'idDependencia']);
+  }
+
+  /**
+   * Gets query for [[EventoResumen]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getEventoResumen() {
+    return $this->hasOne(EventoResumen::class, ['id' => 'idEventoResumen']);
+  }
+
+  /**
+   * Gets query for [[Grupo]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getGrupo() {
+    return $this->hasOne(Grupo::class, ['id' => 'idGrupo']);
+  }
+
+  /**
+   * Gets query for [[Usuario]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getUsuario() {
+    return $this->hasOne(Usuario::class, ['id' => 'idUsuario']);
+  }
+}

+ 94 - 0
models/Grupo.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "Grupo".
+ *
+ * @property int $id
+ * @property string $nombre
+ * @property string|null $descripcion
+ * @property string|null $creado
+ * @property string|null $modificado
+ * @property string|null $eliminado
+ * @property string|null $firebaseId
+ *
+ * @property EventoGrupo[] $eventoGrupos
+ * @property Evento[] $eventos
+ * @property Usuario[] $usuarios
+ * @property UsuarioGrupo[] $usuariosGrupos
+ */
+class Grupo extends \yii\db\ActiveRecord {
+	/**
+	 * {@inheritdoc}
+	 */
+	public static function tableName() {
+		return 'Grupo';
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function rules() {
+		return [
+			[['nombre'], 'required'],
+			[['descripcion'], 'string'],
+			[['creado', 'modificado', 'eliminado'], 'safe'],
+			[['nombre'], 'string', 'max' => 100],
+			[['firebaseId'], 'string', 'max' => 50],
+		];
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function attributeLabels() {
+		return [
+			'id' => 'ID',
+			'nombre' => 'Nombre',
+			'descripcion' => 'Descripcion',
+			'creado' => 'Creado',
+			'modificado' => 'Modificado',
+			'eliminado' => 'Eliminado',
+			'firebaseId' => 'Firebase ID',
+		];
+	}
+
+	/**
+	 * Gets query for [[eventoGrupos]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getEventoGrupos() {
+		return $this->hasMany(EventoGrupo::className(), ['idGrupo' => 'id']);
+	}
+
+	/**
+	 * Gets query for [[eventos]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getEventos() {
+		return $this->hasMany(Evento::className(), ['id' => 'idEvento'])->viaTable('EventoGrupo', ['idGrupo' => 'id']);
+	}
+
+	/**
+	 * Gets query for [[usuarios]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getUsuarios() {
+		return $this->hasMany(Usuario::className(), ['id' => 'idUsuario'])->viaTable('UsuarioGrupo', ['idGrupo' => 'id']);
+	}
+
+	/**
+	 * Gets query for [[usuariosGrupos]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getUsuariosGrupos() {
+		return $this->hasMany(UsuarioGrupo::className(), ['idGrupo' => 'id']);
+	}
+}

+ 72 - 0
models/Notificacion.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "Notificacion".
+ *
+ * @property int $id
+ * @property string|null $envio
+ * @property string|null $estatus
+ * @property string|null $creado
+ * @property string|null $modificado
+ * @property string|null $detalle
+ *
+ * @property NotificacionUsuario[] $notificacionUsuarios
+ */
+class Notificacion extends \yii\db\ActiveRecord {
+
+  public const ESTATUS_NUEVO = "Nuevo";
+  public const ESTATUS_ENVIANDO = "Enviando";
+  public const ESTATUS_TERMINADO = "Terminado";
+  public const ESTATUS_ERROR = "Error";
+
+  const PLANTILLA_EVENTO = "laud_resumen_eventos";
+  const PLANTILLA_LIDER_EVENTO = "laud_resumen_eventos_dependencia";
+  const PLANTILLA_LIDER_GLOBAL = "laud_resumen_dependencias_lider_global";
+  
+  const PLANTILLA_LIDER_EVENTO_URL = "laud_lider_dependencia_url";
+  const PLANTILLA_LIDER_GLOBAL_URL = "laud_lider_global_url";
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'Notificacion';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['envio', 'creado', 'modificado', 'detalle'], 'safe'],
+      [['estatus'], 'string', 'max' => 10],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'id' => 'ID',
+      'envio' => 'Envio',
+      'estatus' => 'Estatus',
+      'creado' => 'Creado',
+      'modificado' => 'Modificado',
+      'detalle' => 'Detalle',
+    ];
+  }
+
+  /**
+   * Gets query for [[NotificacionUsuarios]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getNotificacionUsuarios() {
+    return $this->hasMany(NotificacionUsuario::class, ['idNotificacion' => 'id']);
+  }
+}

+ 78 - 0
models/NotificacionUsuario.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "NotificacionUsuario".
+ *
+ * @property int $id
+ * @property int|null $idNotificacion
+ * @property int|null $idUsuario
+ * @property string|null $nombre
+ * @property string|null $telefono
+ * @property string|null $parametros
+ * @property string|null $detalle
+ * @property string|null $plantilla
+ *
+ * @property Notificacion $notificacion
+ * @property Usuario $usuario
+ */
+class NotificacionUsuario extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'NotificacionUsuario';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['idNotificacion', 'idUsuario'], 'default', 'value' => null],
+      [['idNotificacion', 'idUsuario'], 'integer'],
+      [['parametros', 'detalle'], 'safe'],
+      [['nombre', 'plantilla'], 'string', 'max' => 100],
+      [['telefono'], 'string', 'max' => 10],
+      [['idNotificacion'], 'exist', 'skipOnError' => true, 'targetClass' => Notificacion::class, 'targetAttribute' => ['idNotificacion' => 'id']],
+      [['idUsuario'], 'exist', 'skipOnError' => true, 'targetClass' => Usuario::class, 'targetAttribute' => ['idUsuario' => 'id']],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'id' => 'ID',
+      'idNotificacion' => 'Id Notificacion',
+      'idUsuario' => 'Id Usuario',
+      'nombre' => 'Nombre',
+      'telefono' => 'Telefono',
+      'parametros' => 'Parametros',
+      'detalle' => 'Detalle',
+      'plantilla' => 'Plantilla',
+    ];
+  }
+
+  /**
+   * Gets query for [[notificacion]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getNotificacion() {
+    return $this->hasOne(Notificacion::class, ['id' => 'idNotificacion']);
+  }
+
+  /**
+   * Gets query for [[usuario]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getUsuario() {
+    return $this->hasOne(Usuario::class, ['id' => 'idUsuario']);
+  }
+}

+ 61 - 0
models/Red.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "Red".
+ *
+ * @property int $idEvento
+ * @property string|null $key
+ * @property string $url
+ * @property string|null $redSocial
+ *
+ * @property Evento $evento
+ */
+class Red extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'Red';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['idEvento', 'url'], 'required'],
+      [['idEvento'], 'default', 'value' => null],
+      [['idEvento'], 'integer'],
+      [['key'], 'string', 'max' => 50],
+      [['url'], 'string', 'max' => 500],
+      [['redSocial'], 'string', 'max' => 250],
+      [['idEvento', 'url'], 'unique', 'targetAttribute' => ['idEvento', 'url']],
+      [['idEvento'], 'exist', 'skipOnError' => true, 'targetClass' => Evento::class, 'targetAttribute' => ['idEvento' => 'id']],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'idEvento' => 'Id Evento',
+      'key' => 'Key',
+      'url' => 'Url',
+      'redSocial' => 'Red Social',
+    ];
+  }
+
+  /**
+   * Gets query for [[evento]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getEvento() {
+    return $this->hasOne(Evento::class, ['id' => 'idEvento']);
+  }
+}

+ 75 - 0
models/Resultado.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "Resultado".
+ *
+ * @property int $id
+ * @property int|null $idUsuario
+ * @property int|null $idEvento
+ * @property string|null $accion ver,likes,compartir
+ * @property string|null $creado
+ * @property string|null $modificado
+ * @property string|null $eliminado
+ *
+ * @property Evento $idEvento0
+ * @property Usuario $idUsuario0
+ */
+class Resultado extends \yii\db\ActiveRecord {
+	/**
+	 * {@inheritdoc}
+	 */
+	public static function tableName() {
+		return 'Resultado';
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function rules() {
+		return [
+			[['idUsuario', 'idEvento'], 'default', 'value' => null],
+			[['idUsuario', 'idEvento'], 'integer'],
+			[['creado', 'modificado', 'eliminado'], 'safe'],
+			[['accion'], 'string', 'max' => 20],
+			[['idEvento'], 'exist', 'skipOnError' => true, 'targetClass' => Evento::className(), 'targetAttribute' => ['idEvento' => 'id']],
+			[['idUsuario'], 'exist', 'skipOnError' => true, 'targetClass' => Usuario::className(), 'targetAttribute' => ['idUsuario' => 'id']],
+		];
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function attributeLabels() {
+		return [
+			'id' => 'ID',
+			'idUsuario' => 'Id Usuario',
+			'idEvento' => 'Id Evento',
+			'accion' => 'Accion',
+			'creado' => 'Creado',
+			'modificado' => 'Modificado',
+			'eliminado' => 'Eliminado',
+		];
+	}
+
+	/**
+	 * Gets query for [[evento]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getEvento() {
+		return $this->hasOne(Evento::className(), ['id' => 'idEvento']);
+	}
+
+	/**
+	 * Gets query for [[usuario]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getUsuario() {
+		return $this->hasOne(Usuario::className(), ['id' => 'idUsuario']);
+	}
+}

+ 125 - 0
models/Usuario.php

@@ -0,0 +1,125 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "Usuario".
+ *
+ * @property int $id
+ * @property string|null $uid
+ * @property string $email
+ * @property string $nombre
+ * @property string|null $telefono
+ * @property string|null $facebook
+ * @property bool|null $facebookVerificado
+ * @property string|null $instagram
+ * @property bool|null $instagramVerificado
+ * @property string|null $twitter
+ * @property bool|null $twitterVerificado
+ * @property string|null $genero H: Hombre - M: Mujer
+ * @property string|null $verificado
+ * @property bool|null $liderGlobal
+ * @property string|null $creado
+ * @property string|null $modificado
+ * @property string|null $eliminado
+ *
+ * @property Dependencia[] $dependencias
+ * @property Grupo[] $grupos
+ * @property UsuarioDependencia[] $usuariosDependencias
+ * @property UsuarioGrupo[] $usuarioGrupos
+ */
+class Usuario extends \yii\db\ActiveRecord {
+  /**
+   * {@inheritdoc}
+   */
+  public static function tableName() {
+    return 'Usuario';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rules() {
+    return [
+      [['nombre'], 'required'],
+      [['facebookVerificado', 'instagramVerificado', 'twitterVerificado', 'liderGlobal'], 'boolean'],
+      [['verificado', 'creado', 'modificado', 'eliminado'], 'safe'],
+      [['uid', 'genero'], 'string', 'max' => 50],
+      [['email', 'nombre', 'facebook', 'instagram', 'twitter'], 'string', 'max' => 100],
+      [['telefono'], 'string', 'max' => 10],
+      [['uid'], 'unique'],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attributeLabels() {
+    return [
+      'id' => 'ID',
+      'uid' => 'Uid',
+      'email' => 'Email',
+      'nombre' => 'Nombre',
+      'telefono' => 'Teléfono',
+      'facebook' => 'Facebook',
+      'facebookVerificado' => 'Facebook Verificado',
+      'instagram' => 'Instagram',
+      'instagramVerificado' => 'Instagram Verificado',
+      'twitter' => 'Twitter',
+      'twitterVerificado' => 'Twitter Verificado',
+      'genero' => 'Género',
+      'verificado' => 'Verificado',
+      'liderGlobal' => 'Lider Global',
+      'creado' => 'Creado',
+      'modificado' => 'Modificado',
+      'eliminado' => 'Eliminado',
+    ];
+  }
+
+  /**
+   * Gets query for [[dependencias]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getDependencias() {
+    return $this->hasMany(Dependencia::className(), ['id' => 'idDependencia'])->viaTable('UsuarioDependencia', ['idUsuario' => 'id']);
+  }
+
+  /**
+   * Gets query for [[grupos]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getGrupos() {
+    return $this->hasMany(Grupo::className(), ['id' => 'idGrupo'])->viaTable('UsuarioGrupo', ['idUsuario' => 'id']);
+  }
+
+  /**
+   * Gets query for [[usuariosDependencias]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getUsuariosDependencias() {
+    return $this->hasMany(UsuarioDependencia::className(), ['idUsuario' => 'id']);
+  }
+
+  /**
+   * Gets query for [[usuariosGrupos]].
+   *
+   * @return \yii\db\ActiveQuery
+   */
+  public function getUsuariosGrupos() {
+    return $this->hasMany(UsuarioGrupo::className(), ['idUsuario' => 'id']);
+  }
+
+  public function agregarClave($pwd) {
+    $this->clave = Yii::$app->getSecurity()->generatePasswordHash($pwd);
+  }
+
+  public function validarClave($pwd) {
+    return Yii::$app->getSecurity()->validatePassword($pwd, $this->clave);
+  }
+
+}

+ 65 - 0
models/UsuarioDependencia.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "UsuarioDependencia".
+ *
+ * @property int $idUsuario
+ * @property int $idDependencia
+ *
+ * @property Dependencia $dependencia
+ * @property Usuario $usuario
+ */
+class UsuarioDependencia extends \yii\db\ActiveRecord {
+	/**
+	 * {@inheritdoc}
+	 */
+	public static function tableName() {
+		return 'UsuarioDependencia';
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function rules() {
+		return [
+			[['idUsuario', 'idDependencia'], 'required'],
+			[['idUsuario', 'idDependencia'], 'default', 'value' => null],
+			[['idUsuario', 'idDependencia'], 'integer'],
+			[['idUsuario', 'idDependencia'], 'unique', 'targetAttribute' => ['idUsuario', 'idDependencia']],
+			[['idDependencia'], 'exist', 'skipOnError' => true, 'targetClass' => Dependencia::className(), 'targetAttribute' => ['idDependencia' => 'id']],
+			[['idUsuario'], 'exist', 'skipOnError' => true, 'targetClass' => Usuario::className(), 'targetAttribute' => ['idUsuario' => 'id']],
+		];
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function attributeLabels() {
+		return [
+			'idUsuario' => 'Id Usuario',
+			'idDependencia' => 'Id Dependencia',
+		];
+	}
+
+	/**
+	 * Gets query for [[dependencia]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getDependencia() {
+		return $this->hasOne(Dependencia::className(), ['id' => 'idDependencia']);
+	}
+
+	/**
+	 * Gets query for [[usuario]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getUsuario() {
+		return $this->hasOne(Usuario::className(), ['id' => 'idUsuario']);
+	}
+}

+ 65 - 0
models/UsuarioGrupo.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace app\models;
+
+use Yii;
+
+/**
+ * This is the model class for table "UsuarioGrupo".
+ *
+ * @property int $idUsuario
+ * @property int $idGrupo
+ *
+ * @property Grupo $grupo
+ * @property Usuario $usuario
+ */
+class UsuarioGrupo extends \yii\db\ActiveRecord {
+	/**
+	 * {@inheritdoc}
+	 */
+	public static function tableName() {
+		return 'UsuarioGrupo';
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function rules() {
+		return [
+			[['idUsuario', 'idGrupo'], 'required'],
+			[['idUsuario', 'idGrupo'], 'default', 'value' => null],
+			[['idUsuario', 'idGrupo'], 'integer'],
+			[['idUsuario', 'idGrupo'], 'unique', 'targetAttribute' => ['idUsuario', 'idGrupo']],
+			[['idGrupo'], 'exist', 'skipOnError' => true, 'targetClass' => Grupo::className(), 'targetAttribute' => ['idGrupo' => 'id']],
+			[['idUsuario'], 'exist', 'skipOnError' => true, 'targetClass' => Usuario::className(), 'targetAttribute' => ['idUsuario' => 'id']],
+		];
+	}
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function attributeLabels() {
+		return [
+			'idUsuario' => 'Id Usuario',
+			'idGrupo' => 'Id Grupo',
+		];
+	}
+
+	/**
+	 * Gets query for [[grupo]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getGrupo() {
+		return $this->hasOne(Grupo::className(), ['id' => 'idGrupo']);
+	}
+
+	/**
+	 * Gets query for [[usuario]].
+	 *
+	 * @return \yii\db\ActiveQuery
+	 */
+	public function getUsuario() {
+		return $this->hasOne(Usuario::className(), ['id' => 'idUsuario']);
+	}
+}

+ 38 - 0
modules/common/Module.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace common;
+
+use Yii;
+
+/**
+ * v1 module definition class
+ */
+class Module extends \yii\base\Module {
+
+  /**
+   * {@inheritdoc}
+   */
+  public $controllerNamespace = 'common\controllers';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function init() {
+    parent::init();
+    $response = Yii::$app->getResponse();
+    $headers = $response->getHeaders();
+
+    $headers->set('Access-Control-Allow-Methods', 'POST, GET, DELETE, OPTIONS');
+    $headers->set('Access-Control-Allow-Headers', 'Content-Type,Accept,Authorization');
+    $headers->set('Access-Control-Allow-Origin', '*');
+    $headers->set('Access-Control-Request-Method', 'POST, GET, DELETE, PUT, OPTIONS');
+    $headers->set('Access-Control-Allow-Credentials', 'true');
+    $headers->set('Access-Control-Max-Age', 86400);
+    if (Yii::$app->getRequest()->isOptions) {
+      Yii::$app->end();
+    }
+    Yii::$app->getUser()->enableSession = false;
+    Yii::$app->getUser()->identityClass = 'common\models\Usuario';
+  }
+
+}

+ 159 - 0
modules/common/data/Respuesta.php

@@ -0,0 +1,159 @@
+<?php
+
+namespace common\data;
+
+use common\rest\Serializer;
+use yii\data\ActiveDataProvider;
+
+class Respuesta {
+
+  public $cuerpo = [];
+  protected $atributosPermitidos = [
+    'resultado',
+    'mensaje',
+    'errores',
+    'detalle',
+    'paginacion'
+  ];
+
+  protected $parametros = [
+    "total" => 0,
+    "pagina" => 0,
+    "limite" => 0,
+    "ordenar" => false
+  ];
+
+  public function __set($nombre, $valor) {
+    if(!in_array($nombre, $this->atributosPermitidos)) {
+      return;
+    }
+    $this->cuerpo[$nombre] = $valor;
+  }
+
+  public function __get($nombre) {
+    if(isset($this->cuerpo[$nombre])) {
+      return $this->cuerpo[$nombre];
+    }
+
+    return null;
+  }
+
+  public function __construct($modelo = null, $limite = 20, $pagina = 1, $ordenar = false) {
+    $this->parametros['limite'] = $limite;
+    $this->parametros['pagina'] = $pagina;
+    $this->parametros['ordenar'] = $ordenar;
+    if($modelo !== null) {
+      $this->modelo($modelo);
+    }
+  }
+
+  public function modelo($modelo) {
+    $this->esExitoso();
+    if ($modelo instanceof \yii\db\ActiveRecord) {
+      if ($modelo->hasErrors()) {
+        $this->esError();
+        $this->errores = $modelo->getFirstErrors();
+      } else {
+        $this->detalle($modelo->toArray());
+      }
+    } elseif ($modelo instanceof \yii\db\ActiveQuery || $modelo instanceof \yii\db\Query) {
+      \Yii::$app->getResponse()->setStatusCode(200);
+      $req = \Yii::$app->getRequest();
+      $sql = intval($req->get("sql", "")) === 1;
+      if ($sql) {
+        \Yii::$app->getResponse()->format = \yii\web\Response::FORMAT_RAW;
+        echo $modelo->createCommand()->getRawSql();
+        exit(0);
+      }
+      $limite = intval($this->parametros['limite']);
+      $pagina = intval($this->parametros['pagina']);
+      $ordenar = $this->parametros['ordenar'];
+      $total = $modelo->count();
+
+      if($pagina <= 0) {
+        $pagina = 1;
+      }
+
+      $offset = 0;
+      if (($pagina - 1) >= 0) {
+        $offset = $limite * ($pagina - 1);
+      }
+
+      if($offset > 0) {
+        $modelo->offset($offset);
+      }
+
+      $modelo->limit($limite);
+
+      if ($ordenar !== false && ($campo = trim($ordenar)) !== "") {
+        $separar = explode(",", $ordenar);
+        $ordenamiento = [];
+        foreach ($separar as $segmento) {
+          $exp = explode("-", trim($segmento));
+          $desc = false;
+          if (count($exp) > 1) {
+            $campo = $exp[0];
+            $desc = $exp[1] === 'desc';
+          }
+          $ordenamiento[$campo] = $desc ? SORT_DESC : SORT_ASC;
+        }
+        if (!empty($ordenamiento)) {
+          $modelo->orderBy($ordenamiento);
+        }
+      }
+
+      if ($limite > $total || $limite <= 0) {
+        $limite = $total;
+      }
+
+      $this->paginacion = [
+        "total" => (int)$total, # Total de elementos
+        "pagina" => $pagina, # Página actual
+        "limite" => $limite # Elementos por página
+      ];
+
+      $s = new Serializer();
+      $this->resultado = $s->serialize(new ActiveDataProvider(["query" => $modelo, "pagination" => false]));
+    } elseif(is_array($modelo) && isset($modelo[0])) {
+      $total = count($modelo);
+      $this->paginacion = [
+        "total" => $total,
+        "pagina" => 1,
+        "limite" => $total
+      ];
+      $this->resultado = $modelo;
+    } else {
+      $this->paginacion = [
+        "total" => 1,
+        "pagina" => 1,
+        "limite" => 1
+      ];
+      $this->resultado = [$modelo];
+    }
+    return $this;
+  }
+
+  public function esExitoso($codigo = 200) {
+    \Yii::$app->getResponse()->setStatusCode($codigo);
+    return $this;
+  }
+  
+  public function esError($codigo = 400) {
+    \Yii::$app->getResponse()->setStatusCode($codigo);
+    return $this;
+  }
+
+  public function detalle($detalle) {
+    $this->detalle = $detalle;
+    return $this;
+  }
+
+  public function mensaje($mensaje) {
+    $this->mensaje = $mensaje;
+    return $this;
+  }
+
+  public function getParametros() {
+    return $this->parametros;
+  }
+}

+ 127 - 0
modules/common/models/Usuario.php

@@ -0,0 +1,127 @@
+<?php
+
+namespace common\models;
+
+use Yii;
+use yii\web\IdentityInterface;
+use Firebase\JWT\JWT;
+use Kreait\Firebase\Factory;
+use Kreait\Firebase\Exception\AuthException;
+use Kreait\Firebase\Exception\FirebaseException;
+
+
+class Usuario implements IdentityInterface {
+  
+  public $uid;
+  public $correo;
+  public $nombre;
+
+  protected static function firebase() {
+    $params = \Yii::$app->params;
+
+    $firebase = (new Factory())
+      ->withServiceAccount($params['firebaseKey'])
+      ->createAuth();
+
+    return $firebase;
+  }
+
+  /**
+   * Finds an identity by the given id.
+   *
+   * @param string|int $id the id to be looked for
+   * @return IdentityInterface|null the identity object that matches the given id.
+   */
+  public static function findIdentity($uid) {
+    $firebase = self::firebase();
+    try {
+      $fUsuario = $firebase->getUser($uid);
+      if ($fUsuario->disabled === true) {
+        return null;
+      }
+
+      $usuario = new static();
+      $usuario->uid = $uid;
+      $usuario->nombre = "";
+      if($fUsuario->displayName) {
+        $usuario->nombre = $fUsuario->displayName;
+      }
+      $usuario->correo = $fUsuario->email;
+
+      return $usuario;
+    } catch (AuthException $e) {
+      return null;
+    } catch (FirebaseException $e) {
+      return null;
+    }
+  }
+
+  /**
+   * Finds an identity by the given token.
+   *
+   * @param string $token the token to be looked for
+   * @return IdentityInterface|null the identity object that matches the given token.
+   */
+  public static function findIdentityByAccessToken($token, $type = null) {
+    $firebase = self::firebase();
+
+    try {
+      $verifiedIdToken = $firebase->verifyIdToken($token);
+      $uid = $verifiedIdToken->claims()->get('sub');
+      $fUsuario = $firebase->getUser($uid);
+      if ($fUsuario->disabled === true) {
+        return null;
+      }
+
+      $usuario = new static();
+      $usuario->uid = $uid;
+      $usuario->nombre = "";
+      if($fUsuario->displayName) {
+        $usuario->nombre = $fUsuario->displayName;
+      }
+      $usuario->correo = $fUsuario->email;
+
+      return $usuario;
+    } catch (AuthException $e) {
+      return null;
+    } catch (FirebaseException $e) {
+      return null;
+    }
+  }
+
+  /**
+   * @return int|string current user ID
+   */
+  public function getId() {
+    return $this->uid;
+  }
+
+  /**
+   * @return string current user auth key
+   */
+  public function getAuthKey() {
+    $key = Yii::$app->params['jwt.key'];
+    $token = [
+      "id" => $this->id,
+      "pass" => $this->clave
+    ];
+
+    $jwt = JWT::encode($token, $key);
+    return $jwt;
+  }
+
+  /**
+   * @param string $authKey
+   * @return bool if auth key is valid for current user
+   */
+  public function validateAuthKey($authKey) {
+    $key = Yii::$app->params['jwt.key'];
+    $jwt = JWT::decode($authKey, $key);
+    if(!isset($jwt["id"])) {
+      return false;
+    }
+
+    return $jwt["id"] == $this->id;
+  }
+
+}

+ 33 - 0
modules/common/rest/AuthController.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace common\rest;
+
+use Yii;
+use yii\filters\auth\HttpBearerAuth;
+use yii\filters\auth\QueryParamAuth;
+
+/**
+ * @var $usuario \common\models\Usuario
+ */
+class AuthController extends JsonController {
+
+  public $usuario;
+
+  public function behaviors() {
+    $behavior = parent::behaviors();
+    $behavior["authenticator"]["authMethods"] = [
+      QueryParamAuth::className(),
+      HttpBearerAuth::className()
+    ];
+    return $behavior;
+  }
+
+  public function beforeAction($action) {
+    parent::beforeAction($action);
+
+    $this->usuario = \Yii::$app->getUser()->getIdentity();
+
+    return true;
+  }
+
+}

+ 83 - 0
modules/common/rest/JsonController.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace common\rest;
+
+use yii\filters\ContentNegotiator;
+use yii\filters\Cors;
+use yii\rest\Controller;
+use yii\web\Response;
+use Yii;
+
+/**
+ * @property \yii\web\Application $app
+ * @property \yii\web\Request $req
+ * @property \yii\web\Response $res
+ * @property \yii\db\ActiveQuery $queryInicial
+ * @property int $limite
+ * @property int $pagina
+ * @property string $ordenar
+ * @property string $modelClass
+ */
+class JsonController extends Controller {
+
+  public $app = null;
+  public $req = null;
+  public $res = null;
+
+  public $queryInicial = null;
+  public $modelClass = null;
+
+  public $limite = null;
+  public $pagina = null;
+  public $ordenar = null;
+
+  public $serializer = 'common\rest\Serializer';
+
+  public function behaviors() {
+    $behavior = parent::behaviors();
+    $behavior['contentNegotiator'] =  [
+      'class' => ContentNegotiator::className(),
+      'formats' => [
+        'application/json' => Response::FORMAT_JSON,
+        'application/xml' => Response::FORMAT_XML,
+      ],
+    ];
+    $behavior['corsFilter'] = [
+      'class' => Cors::className(),
+      'cors' => [
+        'Origin' => ['*'],
+        'Access-Control-Request-Method' => [
+          'GET', 'POST', 'PUT', 'PATCH', 
+          'DELETE', 'HEAD', 'OPTIONS'
+        ],
+        'Access-Control-Request-Headers' => ['*'],
+      ],
+    ];
+    $behavior["authenticator"]["except"] = ['options'];
+    return $behavior;
+  }
+
+  public function beforeAction($action) {
+    parent::beforeAction($action);
+    Yii::$app->getResponse()->format = Response::FORMAT_JSON;
+    $this->app = Yii::$app;
+    $this->req = $this->app->getRequest();
+    $this->res = $this->app->getResponse();
+    if ($this->req->isGet) {
+      $this->limite = $this->req->get("limite", 20);
+      $this->pagina = $this->req->get("pagina", 0);
+      $this->ordenar = $this->req->get("ordenar", "");
+    }
+    if ($this->modelClass !== null) {
+      $model = new $this->modelClass;
+      $tableName = $this->modelClass::tableName();
+      $this->queryInicial = $this->modelClass::find();
+      if ($model->hasProperty('eliminado')) {
+        $this->queryInicial
+          ->where(["{{{$tableName}}}.[[eliminado]]" => null]);
+      }
+    }
+    return true;
+  }
+
+}

+ 19 - 0
modules/common/rest/Serializer.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace common\rest;
+
+use yii\rest\Serializer as YiiSerializer;
+use common\data\Respuesta;
+
+class Serializer extends YiiSerializer {
+
+  public function serialize($data) {
+    $data = parent::serialize($data);
+    if ($data instanceof Respuesta) {
+      return $data->cuerpo;
+    }
+
+    return $data;
+  }
+
+}

+ 17 - 0
modules/common/rest/UrlRule.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace common\rest;
+
+class UrlRule extends \yii\rest\UrlRule {
+
+  public $pluralize = false;
+
+  public $patterns = [
+    'PUT' => 'guardar',
+    'DELETE' => 'eliminar',
+    'GET,HEAD' => 'index',
+    'POST' => 'guardar',
+    '' => 'options',
+  ];
+
+}

+ 38 - 0
modules/v1/Module.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace v1;
+
+use Yii;
+
+/**
+ * v1 module definition class
+ */
+class Module extends \yii\base\Module {
+
+  /**
+   * {@inheritdoc}
+   */
+  public $controllerNamespace = 'v1\controllers';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function init() {
+    parent::init();
+    $response = Yii::$app->getResponse();
+    $headers = $response->getHeaders();
+    
+    $headers->set('Access-Control-Allow-Methods', 'POST, GET, DELETE, PUT, OPTIONS');
+    $headers->set('Access-Control-Allow-Headers', 'Content-Type,Accept,Authorization');
+    $headers->set('Access-Control-Allow-Origin', '*');
+    $headers->set('Access-Control-Request-Method', 'POST, GET, DELETE, PUT, OPTIONS');
+    $headers->set('Access-Control-Allow-Credentials', 'true');
+    $headers->set('Access-Control-Max-Age', 86400);
+    if (Yii::$app->getRequest()->isOptions) {
+      Yii::$app->end();
+    } // */
+    Yii::$app->getUser()->enableSession = false;
+    Yii::$app->getUser()->identityClass = 'common\models\Usuario';
+  }
+
+}

+ 102 - 0
modules/v1/controllers/ComparativaDependenciaController.php

@@ -0,0 +1,102 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\JsonController;
+use v1\models\UsuarioDependencia;
+use yii\db\Query;
+use yii\web\NotFoundHttpException;
+
+class ComparativaDependenciaController extends JsonController {
+
+  public function actionIndex() {
+    $fechaInicio = trim($this->req->get("inicio", ""));
+    $fechaFinal = trim($this->req->get("fin", ""));
+
+    if($fechaInicio === "" || $fechaFinal === "") {
+      throw new NotFoundHttpException("Los parámetros inicio y fin son obligatorios.");
+    }
+
+    $query = (new Query())
+      ->select([
+        "{{Dependencia}}.id as dependenciaId",
+        "{{Dependencia}}.nombre as dependenciaNombre",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Facebook' and {{Usuario}}.[[facebookVerificado]]) as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Twitter' and {{Usuario}}.[[twitterVerificado]]) as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Instagram' and {{Usuario}}.[[instagramVerificado]]) as eventosInstagram",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] not in('Facebook', 'Twitter', 'Instagram') and {{Usuario}}.[[instagramVerificado]]) as eventos",
+        "count({{Resultado}}.accion) as cantidadResultados",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.id = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->innerJoin("UsuarioDependencia", "{{UsuarioDependencia}}.[[idUsuario]] = {{Usuario}}.[[id]]")
+      ->innerJoin("Dependencia", "{{Dependencia}}.id = {{UsuarioDependencia}}.[[idDependencia]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->andWhere(["{{Evento}}.eliminado" => null])
+      ->andWhere(["{{Dependencia}}.eliminado" => null])
+      ->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ])
+      ->groupBy([
+        "dependenciaId",
+        "dependenciaNombre",
+      ])
+      ->orderBy(["dependenciaNombre" => SORT_ASC]);
+
+    $query2 = (new Query())
+      ->select([
+        "*",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) as [[cantidadEventos]]",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) - [[cantidadResultados]] as [[cantidadPendientes]]"
+      ])
+      ->from(["t" => $query])
+      ->orderBy(["t.[[cantidadResultados]]" => SORT_DESC]);
+
+    $data = [];
+
+    $eventosAtendidos = 0;
+    $eventosPendientes = 0;
+    $csv = "nombre,participaciones,pendientes,cantidad de usuarios, porcentaje de participación\n";
+    foreach($query2->each() as $resultado) {
+      $eventosAtendidos += $resultado["cantidadResultados"];
+      $eventosPendientes += $resultado["cantidadPendientes"];
+
+      $usuariosDependencia = UsuarioDependencia::find()
+        ->innerJoin('Usuario', '{{Usuario}}.id = {{UsuarioDependencia}}.[[idUsuario]]')
+        ->innerJoin('Dependencia', '{{Dependencia}}.id = {{UsuarioDependencia}}.[[idDependencia]]')
+        ->andWhere(['{{UsuarioDependencia}}.[[idDependencia]]' => $resultado["dependenciaId"]])
+        ->andWhere(['{{Dependencia}}.eliminado' => null])
+        ->andWhere(['{{Usuario}}.eliminado' => null])
+        ->count();
+
+      $total = intval($resultado["cantidadResultados"]) + intval($resultado["cantidadPendientes"]);
+
+      $porcentaje = 0;
+      if ($total > 0) {
+        $porcentaje = ($resultado["cantidadResultados"] * 100) / $total;
+        $porcentaje = round($porcentaje, 2);
+      }
+
+      $data[] = [
+        "id" => $resultado["dependenciaId"],
+        "nombre" => $resultado["dependenciaNombre"],
+        "participaciones" => $resultado["cantidadResultados"],
+        "pendientes" => $resultado["cantidadPendientes"],
+        "porcentajeParticipacion" => $porcentaje,
+        "cantidadUsuarios" => $usuariosDependencia
+      ];
+
+      $csv .= "{$resultado["dependenciaNombre"]},{$resultado["cantidadResultados"]},{$resultado["cantidadPendientes"]},{$usuariosDependencia},{$porcentaje}%\n";
+    }
+
+    \Yii::$app->getResponse()->sendContentAsFile($csv, "comparativa_dep_{$fechaInicio}_{$fechaFinal}.csv");
+    \Yii::$app->end();
+  }
+
+}

+ 28 - 0
modules/v1/controllers/DefaultController.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace v1\controllers;
+
+use common\rest\AuthController;
+
+class DefaultController extends AuthController {
+
+  public function actionIndex() {
+    return \Yii::$app->getUser()->getIdentity();
+  }
+
+  public function actionGuardar() {
+    $metodo = "";
+    if(\Yii::$app->request->isPost) {
+      $metodo = "POST";
+    }
+    if(\Yii::$app->request->isPut) {
+      $metodo = "PUT";
+    }
+
+    return "Ejemplo de un método {$metodo}";
+  }
+  
+  public function actionEliminar() {
+    return "Ejemplo de un delete";
+  }
+}

+ 85 - 0
modules/v1/controllers/DependenciaController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+
+class DependenciaController extends AuthController {
+
+  public $modelClass = "v1\models\Dependencia";
+  public $modelName = "Dependencia";
+
+  public function actionIndex() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    $query = $this->queryInicial;
+
+    if($id > 0) {
+      $query->andWhere(["id" => $id]);
+    }
+
+    if($q !== "") {
+      /*# Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+        ["ilike", "direccion", $q],
+      ]);
+      // */
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar la {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardada correctamente");
+  }
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrada");
+    }
+    $modelo->eliminado = null;
+    if(!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar la {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminada");
+  }
+
+}

+ 85 - 0
modules/v1/controllers/EventoAccionController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+
+class EventoAccionController extends AuthController {
+
+  public $modelClass = "v1\models\EventoAccion";
+  public $modelName = "EventoAccion";
+
+  public function actionIndex() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    $query = $this->queryInicial;
+
+    if($id > 0) {
+      $query->andWhere(["id" => $id]);
+    }
+
+    if($q !== "") {
+      /*# Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+        ["ilike", "direccion", $q],
+      ]);
+      // */
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar el {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardado correctamente");
+  }
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrado");
+    }
+    $modelo->eliminado = null;
+    if(!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar el {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminado");
+  }
+
+}

+ 735 - 0
modules/v1/controllers/EventoController.php

@@ -0,0 +1,735 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use v1\models\Evento;
+use v1\models\Usuario;
+use v1\models\UsuarioDependencia;
+use yii\db\Expression;
+use yii\db\Query;
+
+class EventoController extends AuthController {
+
+  public $modelClass = "v1\models\Evento";
+  public $modelName = "Evento";
+
+  public function actionIndex() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    $query = $this->queryInicial;
+
+    if($id > 0) {
+      $query->andWhere(["id" => $id]);
+    }
+
+    if($q !== "") {
+      # Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+        // ["ilike", "direccion", $q],
+      ]);
+      //
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar el {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardado correctamente");
+  }
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrado");
+    }
+    $modelo->eliminado = null;
+    if(!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar el {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminado");
+  }
+
+  public function actionResultadosIndividuales() {
+    $idUsuario = intval($this->req->getBodyParam("idUsuario", null));
+    $fechaInicio = trim($this->req->getBodyParam("fechaInicio", ""));
+    $fechaFinal = trim($this->req->getBodyParam("fechaFinal", ""));
+
+    $query = (new Query())
+      ->select([
+        "{{Evento}}.id as eventoId",
+        "{{Resultado}}.accion as accionRes",
+        "{{Evento}}.redSocial as redSocial",
+        "{{Usuario}}.[[facebookVerificado]] as facebookVerificado",
+        "{{Usuario}}.[[twitterVerificado]] as twitterVerificado",
+        "{{Usuario}}.[[instagramVerificado]] as instagramVerificado",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{UsuarioGrupo}}.[[idUsuario]] = {{Usuario}}.id")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->andWhere(["{{Evento}}.eliminado" => null])
+      ->orderBy(["eventoId" => SORT_ASC]);
+    
+    /* $query = (new Query())
+      ->select([
+        "{{Usuario}}.nombre as nombre",
+        "{{Usuario}}.facebook as facebook",
+        "{{Usuario}}.facebookVerificado as facebookVerificado",
+        "{{Usuario}}.twitter as twitter",
+        "{{Usuario}}.twitterVerificado as twitterVerificado",
+        "{{Usuario}}.instagram as instagram",
+        "{{Usuario}}.instagramVerificado as instagramVerificado",
+        "{{Usuario}}.id as uId",
+        // "{{Evento}}.id as eventoId",
+        // "{{Evento}}.redSocial",
+        "count({{Evento}}.id) as cantidadEventos",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = Facebook) as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = Twitter) as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = Instagram) as eventosInstagram",
+        "count({{Resultado}}.accion) as cantidadResultados",
+        "(count({{Evento}}.id) - count({{Resultado}}.accion)) as cantidadPendientes",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.id = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->groupBy(["{{Usuario}}.nombre", "facebook", "facebookVerificado", "twitter", "twitterVerificado", "instagram", "instagramVerificado", "uId"]); */
+      // ->orderBy(["eventoId" => SORT_ASC]);
+    
+    if ($idUsuario > 0) {
+      $query->andWhere(["{{UsuarioGrupo}}.[[idUsuario]]" => $idUsuario]);
+    }
+
+    if ($fechaInicio != "" && $fechaFinal != ""){
+      $query->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ]);
+    }
+
+    
+    
+    $total = 0;
+    $participo = 0;
+    foreach($query->each() as $resultado) {
+      $total++;
+      if ($resultado["redSocial"] === "Facebook" && !isset($resultado["facebookVerificado"])){
+        $total--;
+      } else if ($resultado["redSocial"] === "Twitter" && !isset($resultado["twitterVerificado"])){
+        $total--;
+      } else if ($resultado["redSocial"] === "Instagram" && !isset($resultado["instagramVerificado"])){
+        $total--;
+      }
+      
+      if ($resultado["accionRes"] !== null) {
+        $participo ++;
+      }
+    };
+    return (new Respuesta())
+      ->detalle([
+        "total" => $total,
+        "participo" => $participo,
+        "pendientes" => ($total - $participo)
+      ]);
+    // return new Respuesta($query);
+  }
+
+  public function actionResultadosDependencia() {
+    $idDependencia = intval($this->req->getBodyParam("idDependencia", null));
+    $fechaInicio = trim($this->req->getBodyParam("fechaInicio", ""));
+    $fechaFinal = trim($this->req->getBodyParam("fechaFinal", ""));
+
+    $query = (new Query())
+      ->select([
+        "{{Usuario}}.nombre as nombre",
+        "{{UsuarioDependencia}}.[[idDependencia]]",
+        "{{Usuario}}.facebook as facebook",
+        "{{Usuario}}.facebookVerificado as facebookVerificado",
+        "{{Usuario}}.twitter as twitter",
+        "{{Usuario}}.twitterVerificado as twitterVerificado",
+        "{{Usuario}}.instagram as instagram",
+        "{{Usuario}}.instagramVerificado as instagramVerificado",
+        "{{Usuario}}.id as uId",
+        "count({{Evento}}.id) as cantidadEventos",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Facebook' and {{Usuario}}.[[facebookVerificado]]) as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Twitter' and {{Usuario}}.[[twitterVerificado]]) as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Instagram' and {{Usuario}}.[[instagramVerificado]]) as eventosInstagram",
+        "count({{Resultado}}.accion) as cantidadResultados",
+        "(count({{Evento}}.id) - count({{Resultado}}.accion)) as cantidadPendientes",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.[[id]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->innerJoin("UsuarioDependencia", "{{UsuarioDependencia}}.[[idUsuario]] = {{Usuario}}.id")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->andWhere(['{{Evento}}.eliminado' => null])
+      ->andWhere(['{{Usuario}}.eliminado' => null])
+      ->groupBy([
+        "{{Usuario}}.nombre",
+        "{{UsuarioDependencia}}.[[idDependencia]]",
+        "facebook",
+        "[[facebookVerificado]]",
+        "twitter",
+        "[[twitterVerificado]]",
+        "instagram",
+        "[[instagramVerificado]]",
+        "uId"
+      ]);
+
+    if ($idDependencia > 0) {
+      $query->andWhere(["{{UsuarioDependencia}}.[[idDependencia]]" => $idDependencia]);
+    }
+
+    if ($fechaInicio != "" && $fechaFinal != ""){
+      $query->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ]);
+    }
+
+    $query2 = (new Query())
+      ->select([
+        "*",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) as [[cantidadEventos]]",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) - [[cantidadResultados]] as [[cantidadPendientes]]"
+      ])
+      ->from(["t" => $query]);
+
+    // return new Respuesta($query2);
+
+    $info = [];
+    $totalEventos = 0;
+    $eventosAtendidos = 0;
+    $eventosPendientes = 0;
+    foreach($query2->each() as $resultado) {
+      $info[] = $resultado;
+      $totalEventos += $resultado["cantidadEventos"];
+      $eventosAtendidos += $resultado["cantidadResultados"];
+      $eventosPendientes += $resultado["cantidadPendientes"];
+    }
+
+    return (new Respuesta())->detalle([
+      "total" => $totalEventos,
+      "participo" => $eventosAtendidos,
+      "pendientes" => $eventosPendientes,
+      "usuarios" => $info
+    ]);
+
+    /* $total = 0;
+    $participo = 0;
+    foreach($query->each() as $resultado) {
+      $total++;
+      if ($resultado["accionRes"] !== null) {
+        $participo ++;
+      }
+    }
+
+    return (new Respuesta())
+      ->detalle([
+        "total" => $total,
+        "participo" => $participo,
+        "pendientes" => ($total - $participo)
+      ]); */
+  }
+
+  public function actionComparativaDependencia() {
+    $fechaInicio = trim($this->req->getBodyParam("fechaInicio", ""));
+    $fechaFinal = trim($this->req->getBodyParam("fechaFinal", ""));
+
+    /* $query = (new Query())
+      ->select([
+        "{{Dependencia}}.id as dependenciaId",
+        "{{Dependencia}}.nombre as dependenciaNombre",
+        "COUNT({{Resultado}}.[[idUsuario]]) filter ( where {{Resultado}}.[[idUsuario]] is not null ) as conteoNotNull",
+        "COUNT({{UsuarioGrupo}}.[[idUsuario]]) as totalDependencia"
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("UsuarioDependencia", "{{UsuarioDependencia}}.[[idUsuario]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->innerJoin("Dependencia", "{{Dependencia}}.id = {{UsuarioDependencia}}.[[idDependencia]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{UsuarioDependencia}}.[[idUsuario]]")
+      ->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ])
+      ->groupBy([
+        "dependenciaId",
+        "dependenciaNombre"
+      ])
+      ->orderBy(["dependenciaNombre" => SORT_ASC]); */
+
+      $query = (new Query())
+      ->select([
+        "{{Dependencia}}.id as dependenciaId",
+        "{{Dependencia}}.nombre as dependenciaNombre",
+        "count({{Evento}}.id) as cantidadEventos",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Facebook' and {{Usuario}}.[[facebookVerificado]]) as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Twitter' and {{Usuario}}.[[twitterVerificado]]) as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Instagram' and {{Usuario}}.[[instagramVerificado]]) as eventosInstagram",
+        "count({{Resultado}}.accion) as cantidadResultados",
+        "(count({{Evento}}.id) - count({{Resultado}}.accion)) as cantidadPendientes",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.id = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->innerJoin("UsuarioDependencia", "{{UsuarioDependencia}}.[[idUsuario]] = {{Usuario}}.[[id]]")
+      ->innerJoin("Dependencia", "{{Dependencia}}.id = {{UsuarioDependencia}}.[[idDependencia]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->andWhere(["{{Evento}}.eliminado" => null])
+      ->andWhere(["{{Dependencia}}.eliminado" => null])
+      ->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ])
+      ->groupBy([
+        "dependenciaId",
+        "dependenciaNombre",
+      ])
+      ->orderBy(["dependenciaNombre" => SORT_ASC]);
+
+    $query2 = (new Query())
+      ->select([
+        "*",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) as [[cantidadEventos]]",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) - [[cantidadResultados]] as [[cantidadPendientes]]"
+      ])
+      ->from(["t" => $query])
+      ->orderBy(["t.[[cantidadResultados]]" => SORT_DESC]);
+
+    $data = [];
+    /* foreach($query->each() as $resultado) {
+      $data[] = [
+        "id" => $resultado["dependenciaId"],
+        "nombre" => $resultado["dependenciaNombre"],
+        "participaciones" => $resultado["conteoNotNull"],
+        "pendientes" => $resultado["totalDependencia"] - $resultado["conteoNotNull"]
+      ];
+    }
+
+    return (new Respuesta())
+      ->detalle($data); */
+
+    $eventosAtendidos = 0;
+    $eventosPendientes = 0;
+    foreach($query2->each() as $resultado) {
+      $eventosAtendidos += $resultado["cantidadResultados"];
+      $eventosPendientes += $resultado["cantidadPendientes"];
+
+      $usuariosDependencia = UsuarioDependencia::find()
+        ->innerJoin('Usuario', '{{Usuario}}.id = {{UsuarioDependencia}}.[[idUsuario]]')
+        ->innerJoin('Dependencia', '{{Dependencia}}.id = {{UsuarioDependencia}}.[[idDependencia]]')
+        ->andWhere(['{{UsuarioDependencia}}.[[idDependencia]]' => $resultado["dependenciaId"]])
+        ->andWhere(['{{Dependencia}}.eliminado' => null])
+        ->andWhere(['{{Usuario}}.eliminado' => null])
+        ->count();
+
+      $total = intval($resultado["cantidadResultados"]) + intval($resultado["cantidadPendientes"]);
+
+      $porcentaje = 0;
+      if ($total > 0) {
+        $porcentaje = ($resultado["cantidadResultados"] * 100) / $total;
+      }
+
+      $data[] = [
+        "id" => $resultado["dependenciaId"],
+        "nombre" => $resultado["dependenciaNombre"],
+        "participaciones" => $resultado["cantidadResultados"],
+        "pendientes" => $resultado["cantidadPendientes"],
+        "porcentajeParticipacion" => $porcentaje,
+        "cantidadUsuarios" => $usuariosDependencia
+      ];
+    }
+
+    return (new Respuesta())
+      ->detalle($data);
+  }
+
+  public function actionPorEvento() {
+    $idEvento = trim($this->req->getBodyParam("tag", null));
+    $fechaInicio = trim($this->req->getBodyParam("fechaInicio", ""));
+    $fechaFinal = trim($this->req->getBodyParam("fechaFinal", ""));
+
+    /* $queryUsuario = (new Query())
+      ->select([
+        "{{Evento}}.id as eventoId",
+        // "{{Usuario}}.id",
+        "{{Resultado}}.accion as accionRes",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      // ->innerJoin("Usuario", "{{Usuario}}.[[id]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ])
+      ->andWhere(["{{Evento}}.id" => $idEvento])
+      ->orderBy(["eventoId" => SORT_ASC]); */
+
+    $queryUsuario = (new Query())
+      ->select([
+        "{{Usuario}}.id as idUsuario",
+        "{{Resultado}}.accion as accionRes",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.[[id]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.[[id]]")
+      ->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ])
+      ->andWhere(["{{Evento}}.tag" => $idEvento])
+      ->groupBy([
+        "{{Usuario}}.id",
+        "{{Resultado}}.accion",
+        "{{Evento}}.tag"
+      ])
+      ->orderBy(["{{Evento}}.tag" => SORT_ASC]);
+    
+    $totalUsuario = 0;
+    $participoUsuario = 0;
+    $idUsuarios = [];
+    foreach($queryUsuario->each() as $resultado) {
+      $totalUsuario++;
+      if ($resultado["accionRes"] !== null && !in_array($resultado["idUsuario"], $idUsuarios)) {
+        $participoUsuario ++;
+        $idUsuarios[] = $resultado["idUsuario"];
+      } else if ($resultado["accionRes"] === null && in_array($resultado["idUsuario"], $idUsuarios)) {
+        $totalUsuario--;
+      }
+    }
+
+    $queryDependencia = (new Query())
+      ->select([
+        "{{Dependencia}}.id as dependenciaId",
+        "{{Dependencia}}.nombre as dependenciaNombre",
+        "COUNT({{Resultado}}.[[idUsuario]]) filter ( where {{Resultado}}.[[idUsuario]] is not null ) as conteoNotNull",
+        "COUNT({{UsuarioGrupo}}.[[idUsuario]]) as totalDependencia"
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("UsuarioDependencia", "{{UsuarioDependencia}}.[[idUsuario]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->innerJoin("Dependencia", "{{Dependencia}}.id = {{UsuarioDependencia}}.[[idDependencia]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{UsuarioDependencia}}.[[idUsuario]]")
+      ->andWhere([
+        "AND",
+        [">=", "fechaInicio", $fechaInicio],
+        ["<=", "fechaFinal", $fechaFinal],
+      ])
+      ->andWhere(["{{Evento}}.tag" => $idEvento])
+      ->groupBy([
+        "{{Evento}}.tag",
+        "dependenciaId",
+        "dependenciaNombre"
+      ])
+      ->orderBy(["dependenciaNombre" => SORT_ASC]);
+
+      // $this->res->format = \yii\web\Response::FORMAT_RAW;
+      // $sql = $queryDependencia->createCommand()->getRawSql();
+      // return $sql;
+
+    $dataDependencias = [];
+    $totalParticipantesDependencias = 0;
+    $totalPendientesDependencias = 0;
+    foreach($queryDependencia->each() as $resultado) {
+      $totalParticipantesDependencias += $resultado["conteoNotNull"];
+      $totalPendientesDependencias += $resultado["totalDependencia"] - $resultado["conteoNotNull"];
+      $dataDependencias[] = [
+        "id" => $resultado["dependenciaId"],
+        "nombre" => $resultado["dependenciaNombre"],
+        "participaciones" => $resultado["conteoNotNull"],
+        "pendientes" => $resultado["totalDependencia"] - $resultado["conteoNotNull"]
+      ];
+    }
+
+    return (new Respuesta())
+      ->detalle([
+        "totalResultadosUsuarios" => $totalUsuario,
+        "participoResultadosUsuarios" => $participoUsuario,
+        "pendientesResultadosUsuarios" => ($totalUsuario - $participoUsuario),
+        "datosDependencias" => $dataDependencias,
+        "totalParticipantesDependencias" => $totalParticipantesDependencias,
+        "totalPendientesDependencias" => $totalPendientesDependencias,
+        "totalDependencias" => $totalPendientesDependencias + $totalPendientesDependencias
+      ]);
+  }
+
+  public function actionTag() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    // $query = $this->queryInicial;
+    $query = (new Query())
+      ->select([
+        '{{Evento}}.tag',
+        '{{Evento}}.nombre',
+        '{{Evento}}.[[fechaInicio]]',
+        '{{Evento}}.[[fechaFinal]]',
+        'case when count({{Resultado}}.accion) > 0 then true else false end as paticipo'
+      ])
+      ->from('Evento')
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.[[id]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->andWhere(["{{Evento}}.eliminado" => null])
+      ->andWhere("{{Evento}}.tag is not null")
+      ->groupBy([
+        '{{Evento}}.tag',
+        '{{Evento}}.nombre',
+        '{{Evento}}.[[fechaInicio]]',
+        '{{Evento}}.[[fechaFinal]]',
+      ]);
+
+    /* if($id > 0) {
+      $query->andWhere(["id" => $id]);
+    } */
+
+    if($q !== "") {
+      # Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "{{Evento}}.nombre", $q],
+        // ["ilike", "direccion", $q],
+      ]);
+      //
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionCondensado() {
+    $tag = trim($this->req->getBodyParam("tag", null));
+    $fechaInicio = trim($this->req->getBodyParam("fechaInicio", ""));
+    $fechaFinal = trim($this->req->getBodyParam("fechaFinal", ""));
+
+    try {
+      $usuarios = (new Query())
+        ->select([
+          "{{Usuario}}.id as usuarioId",
+          "{{Usuario}}.uid as uid",
+          "{{Usuario}}.nombre as nombre",
+          "case when  {{Usuario}}.[[facebookVerificado]] = true then 1 else 0 end as [[tieneFb]]",
+          "case when  {{Usuario}}.[[twitterVerificado]] = true then 1 else 0 end as [[tieneTw]]",
+          "case when  {{Usuario}}.[[instagramVerificado]] = true then 1 else 0 end as [[tieneIg]]",
+          "{{Usuario}}.facebook as facebook",
+          "{{Usuario}}.instagram as instagram",
+          "{{Usuario}}.twitter as twitter",
+          "{{Usuario}}.verificado as verificado",
+          "{{Dependencia}}.id as [[idDependencia]]",
+          "{{Dependencia}}.nombre as dependencia",
+        ])
+        ->from("Usuario")
+        ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idUsuario]] = {{Usuario}}.id")
+        ->innerJoin("UsuarioDependencia", "{{UsuarioDependencia}}.[[idUsuario]] = {{Usuario}}.id")
+        ->innerJoin("Dependencia", "{{Dependencia}}.id = {{UsuarioDependencia}}.[[idDependencia]]")
+        ->andWhere(["{{Usuario}}.eliminado" => null])
+        ->andWhere(["{{UsuarioGrupo}}.[[idGrupo]]" => 1]) //Grupo ENLACES 2022
+        ->andWhere(["!=", "{{UsuarioDependencia}}.[[idDependencia]]", 33]) //Diferente a dependencia Soporte
+        ->orderBy(['dependencia' => SORT_ASC, 'nombre' => SORT_ASC])
+        ->indexBy("usuarioId")
+        ->all();
+
+      $eventos = Evento::find()
+        ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id")
+        ->andWhere(["{{Evento}}.eliminado" => null])
+        ->andWhere(["tag" => $tag])
+        ->andWhere([
+          "AND",
+          [">=", "fechaInicio", $fechaInicio],
+          ["<=", "fechaFinal", $fechaFinal],
+        ]);
+
+      $auxiliar = [];
+      $auxiliarDependencias = [];
+
+      foreach($eventos->each() as $e) {
+        foreach($e->resultados as $resultado) {
+          if (isset($usuarios[$resultado->idUsuario])) {
+            $usuario = $usuarios[$resultado->idUsuario];
+            if (!isset($auxiliar[$resultado->idUsuario])) {
+              $auxiliar[$resultado->idUsuario] = [
+                "id" => $usuario['usuarioId'],
+                "uid" => $usuario['uid'],
+                "nombre" => $usuario['nombre'],
+                "idDependencia" => $usuario['idDependencia'],
+                "dependencia" => $usuario['dependencia'],
+                "tieneFb" => $usuario['tieneFb'],
+                "facebook" => $usuario['facebook'],
+                "tieneTw" => $usuario['tieneTw'],
+                "twitter" => $usuario['twitter'],
+                "tieneIg" => $usuario['tieneIg'],
+                "instagram" => $usuario['instagram'],
+                "verificado" => $usuario['verificado'],
+                "participoFacebook" => 0,
+                "participoTwitter" => 0,
+                "participoInstagram" => 0,
+              ];
+            }
+
+            if (!isset($auxiliarDependencias[$usuario['idDependencia']])) {
+              $auxiliarDependencias[$usuario['idDependencia']] = [
+                "id" => $usuario['idDependencia'],
+                "nombre" => $usuario['dependencia'],
+                "participaciones" => 0,
+                "pendientes" => 0
+              ];
+            }
+
+            if ($e->redSocial === 'Facebook') {
+              $auxiliar[$resultado->idUsuario]["participoFacebook"] = 1;
+            }
+            if ($e->redSocial === 'Twitter') {
+              $auxiliar[$resultado->idUsuario]["participoTwitter"] = 1;
+            }
+            if ($e->redSocial === 'Instagram') {
+              $auxiliar[$resultado->idUsuario]["participoInstagram"] = 1;
+            }
+          }
+        }
+
+        foreach ($usuarios as $usr) {
+          if (!isset($auxiliar[$usr["usuarioId"]])) {
+            $auxiliar[$usr["usuarioId"]] = [
+              "id" => $usr['usuarioId'],
+              "uid" => $usr['uid'],
+              "nombre" => $usr['nombre'],
+              "idDependencia" => $usr['idDependencia'],
+              "dependencia" => $usr['dependencia'],
+              "tieneFb" => $usr['tieneFb'],
+              "facebook" => $usr['facebook'],
+              "tieneTw" => $usr['tieneTw'],
+              "twitter" => $usr['twitter'],
+              "tieneIg" => $usr['tieneIg'],
+              "instagram" => $usr['instagram'],
+              "verificado" => $usr['verificado'],
+              "participoFacebook" => 0,
+              "participoTwitter" => 0,
+              "participoInstagram" => 0,
+            ];
+          }
+
+          if (!isset($auxiliarDependencias[$usr['idDependencia']])) {
+            $auxiliarDependencias[$usr['idDependencia']] = [
+              "id" => $usr['idDependencia'],
+              "nombre" => $usr['dependencia'],
+              "participaciones" => 0,
+              "pendientes" => 0
+            ];
+          }
+        }
+      }
+
+      $segundoAuxiliar = [];
+      $segundoAuxiliarDependencias = [];
+      foreach($auxiliar as $aux) {
+        if ($aux['tieneFb'] > 0) {
+          if ($aux['participoFacebook'] > 0) {
+            $auxiliarDependencias[$aux['idDependencia']]['participaciones'] += 1;
+          } else {
+            $auxiliarDependencias[$aux['idDependencia']]['pendientes'] += 1;
+          }
+        }
+        if ($aux['tieneTw'] > 0) {
+          if ($aux['participoTwitter'] > 0) {
+            $auxiliarDependencias[$aux['idDependencia']]['participaciones'] += 1;
+          } else {
+            $auxiliarDependencias[$aux['idDependencia']]['pendientes'] += 1;
+          }
+        }
+        if ($aux['tieneIg'] > 0) {
+          if ($aux['participoInstagram'] > 0) {
+            $auxiliarDependencias[$aux['idDependencia']]['participaciones'] += 1;
+          } else {
+            $auxiliarDependencias[$aux['idDependencia']]['pendientes'] += 1;
+          }
+        }
+        $segundoAuxiliar[] = $aux;
+      }
+
+      $participaciones = 0;
+      $pendientes = 0;
+      foreach($auxiliarDependencias as $aux) {
+        $participaciones += $aux['participaciones'];
+        $pendientes += $aux['pendientes'];
+        $segundoAuxiliarDependencias[] = $aux;
+      }
+
+      $total = $pendientes + $participaciones;
+
+      $detalle = [
+        "usuarios" => $segundoAuxiliar,
+        "dependencias" => $segundoAuxiliarDependencias,
+        "total" => $total,
+        "participaciones" => $participaciones,
+        "pendientes" => $pendientes
+      ];
+
+      return (new Respuesta())->detalle($detalle);
+    } catch (\Exception $e) {
+      return (new Respuesta())
+        ->mensaje($e->getLine().'. '.$e->getMessage());
+    }
+  }
+}

+ 116 - 0
modules/v1/controllers/EventoNotificacionController.php

@@ -0,0 +1,116 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\JsonController;
+use yii\db\Expression;
+use yii\db\Query;
+
+class EventoNotificacionController extends JsonController {
+
+  public function actionIndex() {
+    /* $desde = trim($this->req->get("desde", ""));
+    $hasta = trim($this->req->get("hasta", "")); */
+
+    $eventos = (new Query())
+      ->select([
+        "nombre",
+        "tag"
+      ])
+      ->from("Evento")
+      ->andWhere([">=", "fechaFinal", new Expression("now()-interval '7 days'")])
+      // ->andWhere([
+      //   "AND",
+      //   [">=", "fechaFinal", $desde],
+      //   ["<=", "fechaFinal", $hasta]
+      // ])
+      ->groupBy(["tag", "nombre"])
+      ->indexBy("tag")
+      ->column();
+
+    // $sql = $eventos->createCommand()->getRawSql();
+
+    $query2 = (new Query())
+      ->select([
+        "tag",
+        "{{Usuario}}.id",
+        "{{Usuario}}.nombre",
+        "{{Usuario}}.telefono",
+        "case when count({{Resultado}}.accion) > 0 then true else false end as [[Participo]]",
+        "{{UsuarioDependencia}}.[[idDependencia]]"
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.[[id]] = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->innerJoin("UsuarioDependencia", "{{UsuarioDependencia}}.[[idUsuario]] = {{Usuario}}.id")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->andWhere(["{{Usuario}}.eliminado" => null])
+      ->andWhere([">=", "fechaFinal", new Expression("now()-interval '7 days'")])
+      /* ->andWhere([
+        "AND",
+        [">=", "fechaFinal", $desde],
+        ["<=", "fechaFinal", $hasta]
+      ]) */
+      ->groupBy([
+        "{{Usuario}}.nombre",
+        "{{Usuario}}.telefono",
+        "{{Usuario}}.id",
+        "tag",
+        "{{UsuarioDependencia}}.[[idDependencia]]"
+      ])
+      ->orderBy([
+        "{{Usuario}}.id" => SORT_ASC,
+        // "tag" => SORT_ASC,
+        "[[Participo]]" => SORT_DESC,
+      ]);
+
+    $aux = [];
+    $auxDependencia = [];
+    foreach ($query2->each() as $consulta) {
+      if (!isset($aux[$consulta['id']])) {
+        $aux[$consulta['id']] = [
+          "nombreUsuario" => $consulta['nombre'],
+          "telefono" => $consulta['telefono'],
+          "id" => $consulta['id'],
+          "idDependencia" => $consulta['idDependencia'],
+          "eventosFaltantes" => [],
+          "eventosParticipo" => []
+        ];
+      }
+      $nombreEvento = $eventos[$consulta['tag']];
+      if ($consulta['Participo']) {
+        $aux[$consulta['id']]['eventosParticipo'][] = $nombreEvento;
+      } else {
+        $aux[$consulta['id']]['eventosFaltantes'][] = $nombreEvento;
+      }
+    }
+
+    foreach ($aux as $consulta) {
+      if (!isset($auxDependencia[$consulta['idDependencia']])) {
+        $auxDependencia[$consulta['idDependencia']] = [
+          "id" => $consulta['idDependencia'],
+          "eventosFaltantes" => 0,
+          "eventosParticipo" => 0
+        ];
+      }
+      $eventosFaltantes = count($consulta['eventosFaltantes']);
+      $auxDependencia[$consulta['idDependencia']]['eventosFaltantes']+= $eventosFaltantes;
+      $eventosParticipo = count($consulta['eventosParticipo']);
+      $auxDependencia[$consulta['idDependencia']]['eventosParticipo']+= $eventosParticipo;
+      /* if ($consulta['Participo']) {
+        // $auxDependencia[$consulta['idDependencia']]['eventosParticipo'][] = $nombreEvento;
+        $auxDependencia[$consulta['idDependencia']]['eventosParticipo'][] = $aux[$consulta['id']]['eventosParticipo'];
+      } else {
+        // $auxDependencia[$consulta['idDependencia']]['eventosFaltantes'][] = $nombreEvento;
+        $auxDependencia[$consulta['idDependencia']]['eventosFaltantes'][] = $aux[$consulta['id']]['eventosFaltantes'];
+      } */
+    }
+
+    return (new Respuesta())
+      ->detalle($aux);
+      // ->detalle($auxDependencia);
+  }
+}

+ 90 - 0
modules/v1/controllers/EventoResumenController.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace v1\controllers;
+
+use app\models\EventoResumen;
+use app\models\EventoResumenDependencia;
+use common\data\Respuesta;
+use common\rest\JsonController;
+use yii\db\Expression;
+
+class EventoResumenController extends JsonController {
+
+  public $modelClass = "v1\models\EventoResumenParticipante";
+  public $modelName = "EventoResumen";
+
+  public function actionIndex() {
+    $clave = trim($this->req->get("id", ""));
+
+
+    $modelo = EventoResumen::find()
+      ->andWhere(['uuid' => $clave])
+      ->one();
+
+    if ($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("Clave no válida");
+    }
+
+    $query = $this->queryInicial
+      ->andWhere([
+        'idEventoResumen' => $modelo->id,
+      ]);
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionConsultaDependencia() {
+
+    $id = trim($this->req->get("id", ""));
+
+
+    $modelo = EventoResumenDependencia::find()
+      ->andWhere(['clave' => $id])
+      ->one();
+
+    if ($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("ID no válida");
+    }
+
+    $query = $this->queryInicial
+      ->andWhere([
+        'idEventoResumen' => $modelo->idEventoResumen,
+        'idDependencia' => $modelo->idDependencia
+      ]);
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionConsulta() {
+    $c = $this->req->get("c", "");
+    $d = $this->req->get("d", "");
+
+    $modelo = null;
+    if ($d !== "") {
+      $temp = EventoResumenDependencia::find()
+        ->andWhere(['clave' => $d])
+        ->one();
+      if ($temp !== null) {
+        $modelo = $temp->eventoResumen;
+      }
+    }
+
+    if ($c !== "") {
+      $modelo = EventoResumen::find()
+        ->andWhere(['uuid' => $c])
+        ->one();
+    }
+
+    if ($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("ID no válida");
+    }
+
+    return new Respuesta($modelo);
+  }
+}

+ 85 - 0
modules/v1/controllers/GrupoController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+
+class GrupoController extends AuthController {
+
+  public $modelClass = "v1\models\Grupo";
+  public $modelName = "Grupo";
+
+  public function actionIndex() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    $query = $this->queryInicial;
+
+    if($id > 0) {
+      $query->andWhere(["id" => $id]);
+    }
+
+    if($q !== "") {
+      /*# Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+        ["ilike", "direccion", $q],
+      ]);
+      // */
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar el {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardado correctamente");
+  }
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrado");
+    }
+    $modelo->eliminado = null;
+    if(!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar el {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminado");
+  }
+
+}

+ 85 - 0
modules/v1/controllers/RedController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+
+class RedController extends AuthController {
+
+  public $modelClass = "v1\models\Red";
+  public $modelName = "Red";
+
+  public function actionIndex() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    $query = $this->queryInicial;
+
+    if($id > 0) {
+      $query->andWhere(["id" => $id]);
+    }
+
+    if($q !== "") {
+      /*# Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+        ["ilike", "direccion", $q],
+      ]);
+      // */
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar el {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardado correctamente");
+  }
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrado");
+    }
+    $modelo->eliminado = null;
+    if(!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar el {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminado");
+  }
+
+}

+ 346 - 0
modules/v1/controllers/ReporteGlobalController.php

@@ -0,0 +1,346 @@
+<?php
+
+namespace v1\controllers;
+
+use common\rest\AuthController;
+use common\rest\JsonController;
+use DateTime;
+use yii\db\Query;
+
+class ReporteGlobalController extends JsonController {
+
+  public function actionIndex() {
+    $fechas = [
+      ["2022-08-01 00:00:00", "2022-08-01 00:00:00","2022-08-31 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-09-01 00:00:00","2022-09-30 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-10-01 00:00:00","2022-10-31 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-11-01 00:00:00","2022-11-30 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-12-01 00:00:00","2022-12-31 23:59:59"],
+      ["2022-08-01 00:00:00", "2023-01-01 00:00:00","2023-01-31 23:59:59"],
+    ];
+    
+    $query = (new Query())
+      ->select([
+        "{{Usuario}}.nombre as nombre",
+        "{{Usuario}}.verificado as verificado",
+        "{{Usuario}}.facebook as facebook",
+        "{{Usuario}}.facebookVerificado as facebookVerificado",
+        "{{Usuario}}.twitter as twitter",
+        "{{Usuario}}.twitterVerificado as twitterVerificado",
+        "{{Usuario}}.instagram as instagram",
+        "{{Usuario}}.instagramVerificado as instagramVerificado",
+        "{{Usuario}}.id as uId",
+        "count({{Evento}}.id) as cantidadEventos",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Facebook') as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Twitter') as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Instagram') as eventosInstagram",
+        "count({{Resultado}}.accion) as cantidadResultados",
+        "count({{Resultado}}.accion) filter (where {{Evento}}.[[redSocial]] = 'Facebook') as participacionesFacebook",
+        "count({{Resultado}}.accion) filter (where {{Evento}}.[[redSocial]] = 'Twitter') as participacionesTwitter",
+        "count({{Resultado}}.accion) filter (where {{Evento}}.[[redSocial]] = 'Instagram') as participacionesInstagram",
+        "(count({{Evento}}.id) - count({{Resultado}}.accion)) as cantidadPendientes",
+      ])
+      ->from("Usuario")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idUsuario]] = {{Usuario}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{UsuarioGrupo}}.[[idGrupo]]")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Evento", "{{Evento}}.id = {{EventoGrupo}}.[[idEvento]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idUsuario]] = {{Usuario}}.id and {{Resultado}}.[[idEvento]] = {{Evento}}.id")
+      ->andWhere(["{{Usuario}}.eliminado" => null])
+      ->groupBy(["{{Usuario}}.verificado", "facebook", "facebookVerificado", "twitter", "twitterVerificado", "instagram", "instagramVerificado", "uId"]);
+
+    $query2 = (new Query())
+      ->select([
+        // "verificado",
+        "[[eventosFacebook]]",
+        "[[participacionesFacebook]]",
+        "[[eventosTwitter]]",
+        "[[participacionesTwitter]]",
+        "[[eventosInstagram]]",
+        "[[participacionesInstagram]]",
+        "[[cantidadResultados]]",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) as [[cantidadEventos]]",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) - [[cantidadResultados]] as [[cantidadPendientes]]"
+      ]);
+      // ->from(["t" => $query]);
+    
+    $meses = [];
+    foreach($fechas as $_fechas) {
+      $queryClon = (clone $query)->andWhere([
+        "AND",
+        [">=", "{{Evento}}.[[fechaInicio]]", $_fechas[1]],
+        ["<=", "{{Evento}}.[[fechaInicio]]", $_fechas[2]],
+        [">=", "{{Usuario}}.verificado", $_fechas[0]],
+        ["<=", "{{Usuario}}.verificado", $_fechas[2]],
+      ]);
+
+      $mes = (clone $query2)->from(["t" => $queryClon]);
+
+      $contadorPorcentajesFacebook = 0;
+      $porcentajesFacebook = 0;
+      $contadorPorcentajesTwitter = 0;
+      $porcentajesTwitter = 0;
+      $contadorPorcentajesInstagram = 0;
+      $porcentajesInstagram = 0;
+      foreach($mes->each() as $_mes){
+        $eventosFacebook = $_mes["eventosFacebook"];
+        $participacionesFacebook = $_mes["participacionesFacebook"];
+        $eventosTwitter = $_mes["eventosTwitter"];
+        $participacionesTwitter = $_mes["participacionesTwitter"];
+        $eventosInstagram = $_mes["eventosInstagram"];
+        $participacionesInstagram = $_mes["participacionesInstagram"];
+
+        $porcentajeParticipacionFacebook = 0;
+        if ($eventosFacebook > 0) {
+          $contadorPorcentajesFacebook += 1;
+          $porcentajeParticipacionFacebook = ($participacionesFacebook/$eventosFacebook)*100;
+          $porcentajesFacebook += $porcentajeParticipacionFacebook;
+        }
+
+        $porcentajeParticipacionTwitter = 0;
+        if ($eventosTwitter > 0) {
+          $contadorPorcentajesTwitter += 1;
+          $porcentajeParticipacionTwitter = ($participacionesTwitter/$eventosTwitter)*100;
+          $porcentajesTwitter += $porcentajeParticipacionTwitter;
+        }
+
+        $porcentajeParticipacionInstagram = 0;
+        if ($eventosInstagram > 0) {
+          $contadorPorcentajesInstagram += 1;
+          $porcentajeParticipacionInstagram = ($participacionesInstagram/$eventosInstagram)*100;
+          $porcentajesInstagram += $porcentajeParticipacionInstagram;
+        }
+      }
+
+      $totalPorcentajesFacebook = 0;
+      $totalPorcentajesTwitter = 0;
+      $totalPorcentajesInstagram = 0;
+      
+      if ($contadorPorcentajesFacebook > 0) {
+        $totalPorcentajesFacebook = $porcentajesFacebook/$contadorPorcentajesFacebook;
+      }
+
+      if ($contadorPorcentajesTwitter > 0) {
+        $totalPorcentajesTwitter = $porcentajesTwitter/$contadorPorcentajesTwitter;
+      }
+
+      if ($contadorPorcentajesInstagram > 0) {
+        $totalPorcentajesInstagram = $porcentajesInstagram/$contadorPorcentajesInstagram;
+      }
+
+      $porcentajeMaximo = 0;
+      if($totalPorcentajesFacebook > $totalPorcentajesTwitter) {
+        if ($totalPorcentajesFacebook > $totalPorcentajesInstagram) {
+          $porcentajeMaximo = $totalPorcentajesFacebook;
+        } else {
+          $porcentajeMaximo = $totalPorcentajesInstagram;
+        }
+      } else {
+        if ($totalPorcentajesTwitter > $totalPorcentajesInstagram) {
+          $porcentajeMaximo = $totalPorcentajesTwitter;
+        } else {
+          $porcentajeMaximo = $totalPorcentajesInstagram;
+        }
+      }
+      
+      $meses[] = [
+        "fechaInicio" => $_fechas[0],
+        "fechaFinal" => $_fechas[1],
+        "totalParticipantesFacebook" => $contadorPorcentajesFacebook,
+        "porcentajesParticipacionFacebook" => $totalPorcentajesFacebook,
+        "totalParticipantesTwitter" => $contadorPorcentajesTwitter,
+        "porcentajesParticipacionTwitter" => $totalPorcentajesTwitter,
+        "totalParticipantesInstagram" => $contadorPorcentajesInstagram,
+        "porcentajesParticipacionInstagram" => $totalPorcentajesInstagram,
+        "porcentajeParticipacionGlobal" => $totalPorcentajesFacebook+$totalPorcentajesTwitter+$totalPorcentajesInstagram,
+        "porcentajeMaximoGlobal" => $porcentajeMaximo
+      ];
+    }
+
+    return $meses;
+  }
+
+  public function actionCsv() {
+    $fechas = [
+      ["2022-08-01 00:00:00", "2022-08-01 00:00:00","2022-08-31 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-09-01 00:00:00","2022-09-30 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-10-01 00:00:00","2022-10-31 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-11-01 00:00:00","2022-11-30 23:59:59"],
+      ["2022-08-01 00:00:00", "2022-12-01 00:00:00","2022-12-31 23:59:59"],
+      ["2022-08-01 00:00:00", "2023-01-01 00:00:00","2023-01-31 23:59:59"],
+    ];
+    
+    $query = (new Query())
+      ->select([
+        "{{Usuario}}.nombre as nombre",
+        "{{Usuario}}.verificado as verificado",
+        "{{Usuario}}.facebook as facebook",
+        "{{Usuario}}.facebookVerificado as facebookVerificado",
+        "{{Usuario}}.twitter as twitter",
+        "{{Usuario}}.twitterVerificado as twitterVerificado",
+        "{{Usuario}}.instagram as instagram",
+        "{{Usuario}}.instagramVerificado as instagramVerificado",
+        "{{Usuario}}.id as uId",
+        "count({{Evento}}.id) as cantidadEventos",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Facebook') as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Twitter') as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Instagram') as eventosInstagram",
+        "count({{Resultado}}.accion) as cantidadResultados",
+        "count({{Resultado}}.accion) filter (where {{Evento}}.[[redSocial]] = 'Facebook') as participacionesFacebook",
+        "count({{Resultado}}.accion) filter (where {{Evento}}.[[redSocial]] = 'Twitter') as participacionesTwitter",
+        "count({{Resultado}}.accion) filter (where {{Evento}}.[[redSocial]] = 'Instagram') as participacionesInstagram",
+        "(count({{Evento}}.id) - count({{Resultado}}.accion)) as cantidadPendientes",
+      ])
+      ->from("Usuario")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idUsuario]] = {{Usuario}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{UsuarioGrupo}}.[[idGrupo]]")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Evento", "{{Evento}}.id = {{EventoGrupo}}.[[idEvento]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idUsuario]] = {{Usuario}}.id and {{Resultado}}.[[idEvento]] = {{Evento}}.id")
+      ->andWhere(["{{Usuario}}.eliminado" => null])
+      ->groupBy(["{{Usuario}}.verificado", "facebook", "facebookVerificado", "twitter", "twitterVerificado", "instagram", "instagramVerificado", "uId"]);
+
+    $query2 = (new Query())
+      ->select([
+        // "verificado",
+        "[[eventosFacebook]]",
+        "[[participacionesFacebook]]",
+        "[[eventosTwitter]]",
+        "[[participacionesTwitter]]",
+        "[[eventosInstagram]]",
+        "[[participacionesInstagram]]",
+        "[[cantidadResultados]]",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) as [[cantidadEventos]]",
+        "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) - [[cantidadResultados]] as [[cantidadPendientes]]"
+      ]);
+      // ->from(["t" => $query]);
+    
+    $meses = [];
+    foreach($fechas as $_fechas) {
+      $queryClon = (clone $query)->andWhere([
+        "AND",
+        [">=", "{{Evento}}.[[fechaInicio]]", $_fechas[1]],
+        ["<=", "{{Evento}}.[[fechaInicio]]", $_fechas[2]],
+        [">=", "{{Usuario}}.verificado", $_fechas[0]],
+        ["<=", "{{Usuario}}.verificado", $_fechas[2]],
+      ]);
+
+      $mes = (clone $query2)->from(["t" => $queryClon]);
+
+      $contadorPorcentajesFacebook = 0;
+      $porcentajesFacebook = 0;
+      $contadorPorcentajesTwitter = 0;
+      $porcentajesTwitter = 0;
+      $contadorPorcentajesInstagram = 0;
+      $porcentajesInstagram = 0;
+      foreach($mes->each() as $_mes){
+        $eventosFacebook = $_mes["eventosFacebook"];
+        $participacionesFacebook = $_mes["participacionesFacebook"];
+        $eventosTwitter = $_mes["eventosTwitter"];
+        $participacionesTwitter = $_mes["participacionesTwitter"];
+        $eventosInstagram = $_mes["eventosInstagram"];
+        $participacionesInstagram = $_mes["participacionesInstagram"];
+
+        $porcentajeParticipacionFacebook = 0;
+        if ($eventosFacebook > 0) {
+          $contadorPorcentajesFacebook += 1;
+          $porcentajeParticipacionFacebook = ($participacionesFacebook/$eventosFacebook)*100;
+          $porcentajesFacebook += $porcentajeParticipacionFacebook;
+        }
+
+        $porcentajeParticipacionTwitter = 0;
+        if ($eventosTwitter > 0) {
+          $contadorPorcentajesTwitter += 1;
+          $porcentajeParticipacionTwitter = ($participacionesTwitter/$eventosTwitter)*100;
+          $porcentajesTwitter += $porcentajeParticipacionTwitter;
+        }
+
+        $porcentajeParticipacionInstagram = 0;
+        if ($eventosInstagram > 0) {
+          $contadorPorcentajesInstagram += 1;
+          $porcentajeParticipacionInstagram = ($participacionesInstagram/$eventosInstagram)*100;
+          $porcentajesInstagram += $porcentajeParticipacionInstagram;
+        }
+      }
+
+      $totalPorcentajesFacebook = 0;
+      $totalPorcentajesTwitter = 0;
+      $totalPorcentajesInstagram = 0;
+      
+      if ($contadorPorcentajesFacebook > 0) {
+        $totalPorcentajesFacebook = $porcentajesFacebook/$contadorPorcentajesFacebook;
+      }
+
+      if ($contadorPorcentajesTwitter > 0) {
+        $totalPorcentajesTwitter = $porcentajesTwitter/$contadorPorcentajesTwitter;
+      }
+
+      if ($contadorPorcentajesInstagram > 0) {
+        $totalPorcentajesInstagram = $porcentajesInstagram/$contadorPorcentajesInstagram;
+      }
+
+      $porcentajeMaximo = 0;
+      if($totalPorcentajesFacebook > $totalPorcentajesTwitter) {
+        if ($totalPorcentajesFacebook > $totalPorcentajesInstagram) {
+          $porcentajeMaximo = $totalPorcentajesFacebook;
+        } else {
+          $porcentajeMaximo = $totalPorcentajesInstagram;
+        }
+      } else {
+        if ($totalPorcentajesTwitter > $totalPorcentajesInstagram) {
+          $porcentajeMaximo = $totalPorcentajesTwitter;
+        } else {
+          $porcentajeMaximo = $totalPorcentajesInstagram;
+        }
+      }
+      
+      $meses[] = [
+        "fechaInicio" => $_fechas[1],
+        "fechaFinal" => $_fechas[2],
+        "totalParticipantesFacebook" => $contadorPorcentajesFacebook,
+        "porcentajesParticipacionFacebook" => $totalPorcentajesFacebook,
+        "totalParticipantesTwitter" => $contadorPorcentajesTwitter,
+        "porcentajesParticipacionTwitter" => $totalPorcentajesTwitter,
+        "totalParticipantesInstagram" => $contadorPorcentajesInstagram,
+        "porcentajesParticipacionInstagram" => $totalPorcentajesInstagram,
+        "porcentajeParticipacionGlobal" => $totalPorcentajesFacebook+$totalPorcentajesTwitter+$totalPorcentajesInstagram,
+        "porcentajeMaximoGlobal" => $porcentajeMaximo
+      ];
+    }
+
+    $texto = ",VERIFICADOS FACEBOOK,VERIFICADOS INSTAGRAM,VERIFICADOS TWITTER,PORCENTAJE DE PARTICIPACIÓN GLOBAL,PORCENTAJE DE PARTICIPACIÓN - FACEBOOK,PORCENTAJE DE PARTICIPACIÓN - INSTAGRAM,PORCENTAJE DE PARTICIPACIÓN - TWITTER,PORCENTAJE MÁXIMO DE PARTICIPACIÓN GLOBAL\n";
+
+    foreach($meses as $mes) {
+      $fechaInicio = (DateTime::createFromFormat("Y-m-d H:i:s", $mes["fechaInicio"]))->format('d-m-Y');
+      $fechaFinal = (DateTime::createFromFormat("Y-m-d H:i:s", $mes["fechaFinal"]))->format('d-m-Y');
+      $texto .= "".
+        $fechaInicio." - ".$fechaFinal.
+        ",".$mes["totalParticipantesFacebook"].
+        ",".$mes["totalParticipantesInstagram"].
+        ",".$mes["totalParticipantesTwitter"].
+        ",".$mes["porcentajeParticipacionGlobal"].
+        ",".$mes["porcentajesParticipacionFacebook"].
+        ",".$mes["porcentajesParticipacionInstagram"].
+        ",".$mes["porcentajesParticipacionTwitter"].
+        ",".$mes["porcentajeMaximoGlobal"]."\n";
+    }
+
+    return \Yii::$app->getResponse()->sendContentAsFile($texto, "reporte_global.csv");
+  }
+
+  public function actionGuardar() {
+    $metodo = "";
+    if(\Yii::$app->request->isPost) {
+      $metodo = "POST";
+    }
+    if(\Yii::$app->request->isPut) {
+      $metodo = "PUT";
+    }
+
+    return "Ejemplo de un método {$metodo}";
+  }
+  
+  public function actionEliminar() {
+    return "Ejemplo de un delete";
+  }
+}

+ 169 - 0
modules/v1/controllers/ReporteIndividualController.php

@@ -0,0 +1,169 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+use yii\db\Query;
+
+class ReporteIndividualController extends AuthController {
+
+  /* public $modelClass = "v1\models\ReporteIndividual";
+  public $modelName = "ReporteIndividual"; */
+
+  public function actionGuardar() {
+    $idUsuario = intval($this->req->getBodyParam("idUsuario", ""));
+    $fechaInicio = trim($this->req->getBodyParam("fechaInicio", ""));
+    $fechaFinal = trim($this->req->getBodyParam("fechaFinal", ""));
+    $limite = intval($this->req->getBodyParam("limite", ""));
+    $pagina = intval($this->req->getBodyParam("pagina", 1));
+    // $q = trim($this->req->get("q", ""));
+
+    $query = (new Query())
+      ->select([
+        "{{Usuario}}.nombre as nombre",
+        "{{Usuario}}.facebook as facebook",
+        "{{Usuario}}.facebookVerificado as facebookVerificado",
+        "{{Usuario}}.twitter as twitter",
+        "{{Usuario}}.twitterVerificado as twitterVerificado",
+        "{{Usuario}}.instagram as instagram",
+        "{{Usuario}}.instagramVerificado as instagramVerificado",
+        "{{Usuario}}.id as uId",
+        // "{{Evento}}.id as eventoId",
+        // "{{Evento}}.redSocial",
+        "count({{Evento}}.id) as cantidadEventos",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Facebook') as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Twitter') as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Instagram') as eventosInstagram",
+        "count({{Resultado}}.accion) as cantidadResultados",
+        "(count({{Evento}}.id) - count({{Resultado}}.accion)) as cantidadPendientes",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.id = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->groupBy(["{{Usuario}}.nombre", "facebook", "facebookVerificado", "twitter", "twitterVerificado", "instagram", "instagramVerificado", "uId"]);
+
+    /* $query = (new QuerY())
+      ->select([
+        "{{ReporteIndividual}}.nombre",
+        "{{ReporteIndividual}}.facebook",
+        "{{ReporteIndividual}}.[[facebookVerificado]]",
+        "{{ReporteIndividual}}.twitter",
+        "{{ReporteIndividual}}.[[twitterVerificado]]",
+        "{{ReporteIndividual}}.instagram",
+        "{{ReporteIndividual}}.[[instagramVerificado]]",
+        "{{ReporteIndividual}}.[[idUsuario]]",
+        "{{ReporteIndividual}}.[[cantidadFacebook]]",
+        "{{ReporteIndividual}}.[[cantidadTwitter]]",
+        "{{ReporteIndividual}}.[[cantidadInstagram]]",
+        "{{ReporteIndividual}}.[[cantidadInstagram]]",
+        "{{ReporteIndividual}}.[[cantidadResultados]]",
+        "({{ReporteIndividual}}.[[cantidadFacebook]] + {{ReporteIndividual}}.[[cantidadTwitter]] + {{ReporteIndividual}}.[[cantidadInstagram]]) as cantidadEventos",
+        "({{ReporteIndividual}}.[[cantidadFacebook]] + {{ReporteIndividual}}.[[cantidadTwitter]] + {{ReporteIndividual}}.[[cantidadInstagram]]) - {{ReporteIndividual}}.[[cantidadResultados]] as cantidadPendientes"
+      ])
+      ->from("ReporteIndividual")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idUsuario]] = {{ReporteIndividual}}.[[idUsuario]]")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idGrupo]] = {{UsuarioGrupo}}.[[idGrupo]]")
+      ->innerJoin("Evento", "{{Evento}}.id = {{EventoGrupo}}.[[idEvento]]")
+      ->groupBy([
+        "{{ReporteIndividual}}.nombre",
+        "{{ReporteIndividual}}.facebook",
+        "{{ReporteIndividual}}.facebookVerificado",
+        "{{ReporteIndividual}}.twitter",
+        "{{ReporteIndividual}}.twitterVerificado",
+        "{{ReporteIndividual}}.instagram",
+        "{{ReporteIndividual}}.instagramVerificado",
+        "{{ReporteIndividual}}.idUsuario",
+        "{{ReporteIndividual}}.cantidadFacebook",
+        "{{ReporteIndividual}}.cantidadTwitter",
+        "{{ReporteIndividual}}.cantidadInstagram",
+        "{{ReporteIndividual}}.cantidadResultados",
+        "({{ReporteIndividual}}.[[cantidadFacebook]] + {{ReporteIndividual}}.[[cantidadTwitter]] + {{ReporteIndividual}}.[[cantidadInstagram]])",
+        "({{ReporteIndividual}}.[[cantidadFacebook]] + {{ReporteIndividual}}.[[cantidadTwitter]] + {{ReporteIndividual}}.[[cantidadInstagram]]) - {{ReporteIndividual}}.[[cantidadResultados]]"
+      ]); */
+
+    if($idUsuario > 0) {
+      $query->andWhere(["{{Usuario}}.[[id]]" => $idUsuario]);
+      $limite = 1;
+      $pagina = 1;
+    }
+
+    if ($fechaInicio != "" && $fechaFinal != ""){
+      $query->andWhere([
+        "AND",
+        [">=", "{{Evento}}.[[fechaInicio]]", $fechaInicio],
+        ["<=", "{{Evento}}.[[fechaInicio]]", $fechaFinal],
+      ]);
+    }
+
+    /*if($q !== "") {
+      # Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+        ["ilike", "direccion", $q],
+      ]);
+      //
+    } */
+
+    /* if ($limite > 0) {
+      return new Respuesta($query, $limite);
+    }
+    return new Respuesta($query); */
+
+    return new Respuesta($query, $limite, $pagina, $this->ordenar);
+  }
+
+  /* public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar el {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardado correctamente");
+  } */
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrado");
+    }
+    $modelo->eliminado = null;
+    if(!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar el {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminado");
+  }
+
+}

+ 85 - 0
modules/v1/controllers/ResultadoController.php

@@ -0,0 +1,85 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+
+class ResultadoController extends AuthController {
+
+  public $modelClass = "v1\models\Resultado";
+  public $modelName = "Resultado";
+
+  public function actionIndex() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    $query = $this->queryInicial;
+
+    if($id > 0) {
+      $query->andWhere(["id" => $id]);
+    }
+
+    if($q !== "") {
+      /*# Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+        ["ilike", "direccion", $q],
+      ]);
+      // */
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar el {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardado correctamente");
+  }
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrado");
+    }
+    $modelo->eliminado = null;
+    if(!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar el {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminado");
+  }
+
+}

+ 69 - 0
modules/v1/controllers/ResultadosIndividualesController.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+use yii\db\Query;
+
+class ResultadosIndividualesController extends AuthController {
+
+  public function actionIndex() {
+    $idUsuario = intval($this->req->getBodyParam("idUsuario", ""));
+    $fechaInicio = trim($this->req->getBodyParam("fechaInicio", ""));
+    $fechaFinal = trim($this->req->getBodyParam("fechaFinal", ""));
+    $limite = intval($this->req->getBodyParam("limite", ""));
+    $pagina = intval($this->req->getBodyParam("pagina", 1));
+
+    $query = (new Query())
+      ->select([
+        "{{Usuario}}.nombre as nombre",
+        "{{Usuario}}.facebook as facebook",
+        "{{Usuario}}.facebookVerificado as facebookVerificado",
+        "{{Usuario}}.twitter as twitter",
+        "{{Usuario}}.twitterVerificado as twitterVerificado",
+        "{{Usuario}}.instagram as instagram",
+        "{{Usuario}}.instagramVerificado as instagramVerificado",
+        "{{Usuario}}.id as uId",
+        "count({{Evento}}.id) as cantidadEventos",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Facebook') as eventosFacebook",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Twitter') as eventosTwitter",
+        "count({{Evento}}.[[redSocial]]) filter (where {{Evento}}.[[redSocial]] = 'Instagram') as eventosInstagram",
+        "count({{Resultado}}.accion) as cantidadResultados",
+        "(count({{Evento}}.id) - count({{Resultado}}.accion)) as cantidadPendientes",
+      ])
+      ->from("Evento")
+      ->innerJoin("EventoGrupo", "{{EventoGrupo}}.[[idEvento]] = {{Evento}}.id")
+      ->innerJoin("Grupo", "{{Grupo}}.id = {{EventoGrupo}}.[[idGrupo]]")
+      ->innerJoin("UsuarioGrupo", "{{UsuarioGrupo}}.[[idGrupo]] = {{Grupo}}.id")
+      ->innerJoin("Usuario", "{{Usuario}}.id = {{UsuarioGrupo}}.[[idUsuario]]")
+      ->leftJoin("Resultado", "{{Resultado}}.[[idEvento]] = {{Evento}}.id and {{Resultado}}.[[idUsuario]] = {{Usuario}}.id")
+      ->groupBy(["{{Usuario}}.nombre", "facebook", "facebookVerificado", "twitter", "twitterVerificado", "instagram", "instagramVerificado", "uId"]);
+
+
+    if ($idUsuario > 0) {
+      $query->andWhere(["{{Usuario}}.[[id]]" => $idUsuario]);
+      $limite = 1;
+      $pagina = 1;
+    }
+
+    if ($fechaInicio != "" && $fechaFinal != "") {
+      $query->andWhere([
+        "AND",
+        [">=", "{{Evento}}.[[fechaInicio]]", $fechaInicio],
+        ["<=", "{{Evento}}.[[fechaFinal]]", $fechaFinal],
+      ]);
+    }
+
+    $query2 = (new Query())
+        ->select([
+          "*",
+          "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) as [[cantidadEventos]]",
+          "([[eventosFacebook]] + [[eventosTwitter]] + [[eventosInstagram]]) - [[cantidadResultados]] as [[cantidadPendientes]]"
+        ])
+        ->from(["t" => $query]);
+
+    return new Respuesta($query2, $limite, $pagina, $this->ordenar);
+  }
+}

+ 83 - 0
modules/v1/controllers/UsuarioController.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace v1\controllers;
+
+use common\data\Respuesta;
+use common\rest\AuthController;
+use yii\db\Expression;
+
+class UsuarioController extends AuthController {
+
+  public $modelClass = "v1\models\Usuario";
+  public $modelName = "Usuario";
+
+  public function actionIndex() {
+    $id = intval($this->req->get("id", ""));
+    $q = trim($this->req->get("q", ""));
+
+    $query = $this->queryInicial;
+
+    if ($id > 0) {
+      $query->andWhere(["id" => $id]);
+    }
+
+    if ($q !== "") {
+      # Ejemplo de buscador
+      $query->andWhere([
+        "OR",
+        ["ilike", "nombre", $q],
+      ]);
+      //
+    }
+
+    return new Respuesta($query, $this->limite, $this->pagina, $this->ordenar);
+  }
+
+  public function actionGuardar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if ($id > 0) {
+      $modelo = $this->modelClass::findOne($id);
+    }
+    if ($modelo === null) {
+      $modelo = new $this->modelClass();
+      $modelo->creado = new Expression('now()');
+      $modelo->idUsuarioCreador = $this->usuario->id;
+    } else {
+      $modelo->modificado = new Expression('now()');
+    }
+
+    $modelo->load($this->req->getBodyParams(), '');
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("Hubo un problema al guardar el {$this->modelName}");
+    }
+
+    $modelo->refresh();
+    return (new Respuesta($modelo))
+      ->mensaje("{$this->modelName} guardado correctamente");
+  }
+
+  public function actionEliminar() {
+    $id = intval($this->req->getBodyParam("id", null));
+    $modelo = null;
+
+    if ($id > 0) {
+      $modelo = $this->modelClass::findOne(["id" => $id]);
+    }
+    if ($modelo === null) {
+      return (new Respuesta())
+        ->esError()
+        ->mensaje("{$this->modelName} no encontrado");
+    }
+    $modelo->eliminado = null;
+    if (!$modelo->save()) {
+      return (new Respuesta($modelo))
+        ->mensaje("No se pudo eliminar el {$this->modelName}");
+    }
+
+    return (new Respuesta())
+      ->mensaje("{$this->modelName} eliminado");
+  }
+}

+ 38 - 0
modules/v1/models/Dependencia.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace v1\models;
+
+use app\models\Dependencia as ModeloDependencia;
+
+class Dependencia extends ModeloDependencia {
+
+  public function fields() {
+    return [
+			'id',
+			'nombre',
+			'descripcion',
+			'creado',
+			'modificado',
+			'eliminado',
+      'firebaseId',
+      'estatus'
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'usuarios',
+      'usuariosDependencias',
+    ];
+  }
+
+
+  public function getUsuarios() {
+		return $this->hasMany(Usuario::className(), ['id' => 'idUsuario'])->viaTable('UsuarioDependencia', ['idDependencia' => 'id']);
+	}
+
+	public function getUsuariosDependencias() {
+		return $this->hasMany(UsuarioDependencia::className(), ['idDependencia' => 'id']);
+	}
+
+}

+ 30 - 0
modules/v1/models/DependenciaLider.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace v1\models;
+
+use app\models\DependenciaLider as ModelsDependenciaLider;
+
+class DependenciaLider extends ModelsDependenciaLider {
+
+  public function fields () {
+    return [
+      'idDependencia',
+      'idUsuario',
+    ];
+  }
+
+  public function extraFields () {
+    return [
+      'dependencia',
+      'usuario'
+    ];
+  }
+
+  public function getDependencia() {
+    return $this->hasOne(Dependencia::class, ['id' => 'idDependencia']);
+  }
+
+  public function getUsuario() {
+    return $this->hasOne(Usuario::class, ['id' => 'idUsuario']);
+  }
+}

+ 57 - 0
modules/v1/models/Evento.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace v1\models;
+
+use app\models\Evento as ModeloEvento;
+
+class Evento extends ModeloEvento {
+
+  public function fields() {
+    return [
+      'id',
+      'nombre',
+      'descripcion',
+      'fotoEvento',
+      'tag',
+      'url',
+      'fechaInicio',
+      'fechaFinal',
+      'creado',
+      'modificado',
+      'eliminado',
+      'firebaseId',
+      'ciudad',
+      'redSocial'
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'eventoAcciones',
+      'eventoGrupos',
+      'grupos',
+      'redes',
+      'resultados',
+    ];
+  }
+
+  public function getEventoAcciones() {
+    return $this->hasMany(EventoAccion::class, ['idEvento' => 'id']);
+  }
+
+  public function getEventoGrupos() {
+    return $this->hasMany(EventoGrupo::className(), ['idEvento' => 'id']);
+  }
+
+  public function getGrupos() {
+    return $this->hasMany(Grupo::className(), ['id' => 'idGrupo'])->viaTable('EventoGrupo', ['idEvento' => 'id']);
+  }
+
+  public function getRedes() {
+    return $this->hasMany(Red::class, ['idEvento' => 'id']);
+  }
+
+  public function getResultados() {
+    return $this->hasMany(Resultado::className(), ['idEvento' => 'id']);
+  }
+}

+ 25 - 0
modules/v1/models/EventoAccion.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace v1\models;
+
+use app\models\EventoAccion as ModelsEventoAccion;
+
+class EventoAccion extends ModelsEventoAccion {
+
+  public function fields() { 
+    return [
+      'idEvento',
+      'accion',
+    ];
+  }
+
+  public function extraFields() { 
+    return [
+      'evento'
+    ];
+  }
+  
+  public function getEvento() {
+    return $this->hasOne(Evento::class, ['id' => 'idEvento']);
+  }
+}

+ 32 - 0
modules/v1/models/EventoGrupo.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace v1\models;
+
+use app\models\EventoGrupo as ModeloEventoGrupo;
+
+class EventoGrupo extends ModeloEventoGrupo {
+
+  public function fields() {
+    return [
+			'idEvento',
+			'idGrupo',
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'evento',
+      'grupo'
+    ];
+  }
+
+  public function getEvento() {
+		return $this->hasOne(Evento::className(), ['id' => 'idEvento']);
+	}
+
+
+	public function getGrupo() {
+		return $this->hasOne(Grupo::className(), ['id' => 'idGrupo']);
+	}
+
+}

+ 29 - 0
modules/v1/models/EventoResumen.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace v1\models;
+
+use app\models\EventoResumen as ModeloEventoResumen;
+
+class EventoResumen extends ModeloEventoResumen {
+
+  public function fields() {
+    return [
+      'id',
+      'uuid',
+      'inicio',
+      'fin',
+      'creado',
+      'modificado'
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'eventoResumenParticipantes',
+    ];
+  }
+
+  public function getEventoResumenParticipantes() {
+    return $this->hasMany(EventoResumenParticipante::class, ['idEventoResumen' => 'id']);
+  }
+}

+ 31 - 0
modules/v1/models/EventoResumenDependencia.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace v1\models;
+
+use app\models\EventoResumenDependencia as ModeloEventoResumenDependencia;
+
+class EventoResumenDependencia extends ModeloEventoResumenDependencia {
+
+  public function fields() {
+    return [
+      'idEventoResumen',
+      'idDependencia',
+      'clave',
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'eventoResumen',
+      'dependencia',
+    ];
+  }
+
+  public function getDependencia() {
+    return $this->hasOne(Dependencia::class, ['id' => 'idDependencia']);
+  }
+
+  public function getEventoResumen() {
+    return $this->hasOne(EventoResumen::class, ['id' => 'idEventoResumen']);
+  }
+}

+ 45 - 0
modules/v1/models/EventoResumenParticipante.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace v1\models;
+
+use app\models\EventoResumenParticipante as ModeloEventoResumenParticipante;
+
+class EventoResumenParticipante extends ModeloEventoResumenParticipante {
+
+  public function fields() {
+    return [
+      'id',
+      'idEventoResumen',
+      'idDependencia',
+      'nombreDependencia',
+      'idGrupo',
+      'nombreGrupo',
+      'idUsuario',
+      'nombre',
+      'totalEventos',
+      'participacion',
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'dependencia','eventoResumen','grupo','usuario'
+    ];
+  }
+
+  public function getDependencia() {
+    return $this->hasOne(Dependencia::class, ['id' => 'idDependencia']);
+  }
+
+  public function getEventoResumen() {
+    return $this->hasOne(EventoResumen::class, ['id' => 'idEventoResumen']);
+  }
+
+  public function getGrupo() {
+    return $this->hasOne(Grupo::class, ['id' => 'idGrupo']);
+  }
+
+  public function getUsuario() {
+    return $this->hasOne(Usuario::class, ['id' => 'idUsuario']);
+  }
+}

+ 46 - 0
modules/v1/models/Grupo.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace v1\models;
+
+use app\models\Grupo as ModeloGrupo;
+
+class Grupo extends ModeloGrupo {
+
+  public function fields() {
+    return [
+			'id',
+			'nombre',
+			'descripcion',
+			'creado',
+			'modificado',
+			'eliminado',
+      'firebaseId'
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'eventoGrupos',
+      'eventos',
+      'usuarios',
+      'usuariosGrupos',
+    ];
+  }
+
+  public function getEventoGrupos() {
+		return $this->hasMany(EventoGrupo::className(), ['idGrupo' => 'id']);
+	}
+
+	public function getEventos() {
+		return $this->hasMany(Evento::className(), ['id' => 'idEvento'])->viaTable('EventoGrupo', ['idGrupo' => 'id']);
+	}
+
+  public function getUsuarios() {
+		return $this->hasMany(Usuario::className(), ['id' => 'idUsuario'])->viaTable('UsuarioGrupo', ['idGrupo' => 'id']);
+	}
+
+	public function getUsuariosGrupos() {
+		return $this->hasMany(UsuarioGrupo::className(), ['idGrupo' => 'id']);
+	}
+
+}

+ 36 - 0
modules/v1/models/NotificacionUsuario.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace v1\models;
+
+use app\models\NotificacionUsuario as ModelsNotificacionUsuario;
+
+class NotificacionUsuario extends ModelsNotificacionUsuario {
+
+  public function fields () {
+    return [
+      'id',
+      'idNotificacion',
+      'idUsuario',
+      'nombre',
+      'telefono',
+      'parametros',
+      'detalle',
+      'plantilla',
+    ];
+  }
+
+  public function extraFields () {
+    return [
+      'notificacion',
+      'usuario'
+    ];
+  }
+
+  public function getNotificacion() {
+    return $this->hasOne(Notificacion::class, ['id' => 'idNotificacion']);
+  }
+
+  public function getUsuario() {
+    return $this->hasOne(Usuario::class, ['id' => 'idUsuario']);
+  }
+}

+ 29 - 0
modules/v1/models/Notificacon.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace v1\models;
+
+use app\models\Notificacion as ModelsNotificacion;
+
+class Notificacion extends ModelsNotificacion {
+
+  public function fields () {
+    return [
+      'id',
+      'envio',
+      'estatus',
+      'creado',
+      'modificado',
+      'detalle',
+    ];
+  }
+
+  public function extraFields () {
+    return [
+      'notificacionUsuarios'
+    ];
+  }
+
+  public function getNotificacionUsuarios() {
+    return $this->hasMany(NotificacionUsuario::class, ['idNotificacion' => 'id']);
+  }
+}

+ 27 - 0
modules/v1/models/Red.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace v1\models;
+
+use app\models\Red as ModelsRed;
+
+class Red extends ModelsRed {
+
+  public function fields() { 
+    return [
+      'idEvento',
+      'key',
+      'url',
+      'redSocial',
+    ];
+  }
+
+  public function extraFields() { 
+    return [
+      'evento'
+    ];
+  }
+
+  public function getEvento() {
+    return $this->hasOne(Evento::class, ['id' => 'idEvento']);
+  }
+}

+ 36 - 0
modules/v1/models/Resultado.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace v1\models;
+
+use app\models\Resultado as ModeloResultado;
+
+class Resultado extends ModeloResultado {
+
+  public function fields() {
+    return [
+			'id',
+			'idUsuario',
+			'idEvento',
+			'accion',
+			'creado',
+			'modificado',
+			'eliminado',
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'evento',
+      'usuario',
+    ];
+  }
+
+	public function getEvento() {
+		return $this->hasOne(Evento::className(), ['id' => 'idEvento']);
+	}
+
+	public function getUsuario() {
+		return $this->hasOne(Usuario::className(), ['id' => 'idUsuario']);
+	}
+
+}

+ 22 - 0
modules/v1/models/Sesion.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace v1\models;
+
+class Sesion extends \common\models\Usuario {
+
+  public function fields() {
+    return [
+      'id',
+      'rfc',
+      'correo',
+      'nombre',
+      'apellidoPaterno',
+      'apellidoMaterno',
+      'estatus',
+      'token' => function($model) {
+        return $model->getAuthKey();
+      }
+    ];
+  }
+
+}

+ 57 - 0
modules/v1/models/Usuario.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace v1\models;
+
+use app\models\Usuario as ModeloUsuario;
+
+class Usuario extends ModeloUsuario {
+
+  public function fields() {
+    return [
+      'id',
+      'uid',
+      'email',
+      'nombre',
+      'telefono',
+      'facebook',
+      'facebookVerificado',
+      'instagram',
+      'instagramVerificado',
+      'twitter',
+      'twitterVerificado',
+      'genero',
+      'verificado',
+      'liderGlobal',
+      'creado',
+      'modificado',
+      'eliminado',
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'dependencias',
+      'grupos',
+      'usuariosDependencias',
+      'usuariosGrupos'
+    ];
+  }
+
+
+  public function getDependencias() {
+    return $this->hasMany(Dependencia::className(), ['id' => 'idDependencia'])->viaTable('UsuarioDependencia', ['idUsuario' => 'id']);
+  }
+
+  public function getGrupos() {
+    return $this->hasMany(Grupo::className(), ['id' => 'idGrupo'])->viaTable('UsuarioGrupo', ['idUsuario' => 'id']);
+  }
+ 
+  public function getUsuariosDependencias() {
+    return $this->hasMany(UsuarioDependencia::className(), ['idUsuario' => 'id']);
+  }
+
+  public function getUsuariosGrupos() {
+    return $this->hasMany(UsuarioGrupo::className(), ['idUsuario' => 'id']);
+  }
+
+}

+ 32 - 0
modules/v1/models/UsuarioDependencia.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace v1\models;
+
+use app\models\UsuarioDependencia as ModeloUsuarioDependencia;
+
+class UsuarioDependencia extends ModeloUsuarioDependencia {
+
+  public function fields() {
+    return [
+			'idUsuario',
+			'idDependencia',
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'dependencia',
+      'usuario',
+    ];
+  }
+
+
+  public function getDependencia() {
+		return $this->hasOne(Dependencia::className(), ['id' => 'idDependencia']);
+	}
+
+	public function getUsuario() {
+		return $this->hasOne(Usuario::className(), ['id' => 'idUsuario']);
+	}
+
+}

+ 32 - 0
modules/v1/models/UsuarioGrupo.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace v1\models;
+
+use app\models\UsuarioGrupo as ModeloUsuarioGrupo;
+
+class UsuarioGrupo extends ModeloUsuarioGrupo {
+
+  public function fields() {
+    return [
+      'idUsuario',
+      'idGrupo',
+    ];
+  }
+
+  public function extraFields() {
+    return [
+      'grupo',
+      'usuario',
+    ];
+  }
+
+
+  public function getGrupo() {
+		return $this->hasOne(Grupo::className(), ['id' => 'idGrupo']);
+	}
+
+	public function getUsuario() {
+		return $this->hasOne(Usuario::className(), ['id' => 'idUsuario']);
+	}
+
+}

+ 162 - 0
requirements.php

@@ -0,0 +1,162 @@
+<?php
+/**
+ * Application requirement checker script.
+ *
+ * In order to run this script use the following console command:
+ * php requirements.php
+ *
+ * In order to run this script from the web, you should copy it to the web root.
+ * If you are using Linux you can create a hard link instead, using the following command:
+ * ln ../requirements.php requirements.php
+ */
+
+// you may need to adjust this path to the correct Yii framework path
+// uncomment and adjust the following line if Yii is not located at the default path
+//$frameworkPath = dirname(__FILE__) . '/vendor/yiisoft/yii2';
+
+
+if (!isset($frameworkPath)) {
+    $searchPaths = array(
+        dirname(__FILE__) . '/vendor/yiisoft/yii2',
+        dirname(__FILE__) . '/../vendor/yiisoft/yii2',
+    );
+    foreach ($searchPaths as $path) {
+        if (is_dir($path)) {
+            $frameworkPath = $path;
+            break;
+        }
+    }
+}
+
+if (!isset($frameworkPath) || !is_dir($frameworkPath)) {
+    $message = "<h1>Error</h1>\n\n"
+        . "<p><strong>The path to yii framework seems to be incorrect.</strong></p>\n"
+        . '<p>You need to install Yii framework via composer or adjust the framework path in file <abbr title="' . __FILE__ . '">' . basename(__FILE__) . "</abbr>.</p>\n"
+        . '<p>Please refer to the <abbr title="' . dirname(__FILE__) . "/README.md\">README</abbr> on how to install Yii.</p>\n";
+
+    if (!empty($_SERVER['argv'])) {
+        // do not print HTML when used in console mode
+        echo strip_tags($message);
+    } else {
+        echo $message;
+    }
+    exit(1);
+}
+
+require_once($frameworkPath . '/requirements/YiiRequirementChecker.php');
+$requirementsChecker = new YiiRequirementChecker();
+
+$gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.';
+$gdOK = $imagickOK = false;
+
+if (extension_loaded('imagick')) {
+    $imagick = new Imagick();
+    $imagickFormats = $imagick->queryFormats('PNG');
+    if (in_array('PNG', $imagickFormats)) {
+        $imagickOK = true;
+    } else {
+        $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.';
+    }
+}
+
+if (extension_loaded('gd')) {
+    $gdInfo = gd_info();
+    if (!empty($gdInfo['FreeType Support'])) {
+        $gdOK = true;
+    } else {
+        $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.';
+    }
+}
+
+/**
+ * Adjust requirements according to your application specifics.
+ */
+$requirements = array(
+    // Database :
+    array(
+        'name' => 'PDO extension',
+        'mandatory' => true,
+        'condition' => extension_loaded('pdo'),
+        'by' => 'All DB-related classes',
+    ),
+    array(
+        'name' => 'PDO SQLite extension',
+        'mandatory' => false,
+        'condition' => extension_loaded('pdo_sqlite'),
+        'by' => 'All DB-related classes',
+        'memo' => 'Required for SQLite database.',
+    ),
+    array(
+        'name' => 'PDO MySQL extension',
+        'mandatory' => false,
+        'condition' => extension_loaded('pdo_mysql'),
+        'by' => 'All DB-related classes',
+        'memo' => 'Required for MySQL database.',
+    ),
+    array(
+        'name' => 'PDO PostgreSQL extension',
+        'mandatory' => false,
+        'condition' => extension_loaded('pdo_pgsql'),
+        'by' => 'All DB-related classes',
+        'memo' => 'Required for PostgreSQL database.',
+    ),
+    // Cache :
+    array(
+        'name' => 'Memcache extension',
+        'mandatory' => false,
+        'condition' => extension_loaded('memcache') || extension_loaded('memcached'),
+        'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-caching-memcache.html">MemCache</a>',
+        'memo' => extension_loaded('memcached') ? 'To use memcached set <a href="http://www.yiiframework.com/doc-2.0/yii-caching-memcache.html#$useMemcached-detail">MemCache::useMemcached</a> to <code>true</code>.' : ''
+    ),
+    // CAPTCHA:
+    array(
+        'name' => 'GD PHP extension with FreeType support',
+        'mandatory' => false,
+        'condition' => $gdOK,
+        'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-captcha-captcha.html">Captcha</a>',
+        'memo' => $gdMemo,
+    ),
+    array(
+        'name' => 'ImageMagick PHP extension with PNG support',
+        'mandatory' => false,
+        'condition' => $imagickOK,
+        'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-captcha-captcha.html">Captcha</a>',
+        'memo' => $imagickMemo,
+    ),
+    // PHP ini :
+    'phpExposePhp' => array(
+        'name' => 'Expose PHP',
+        'mandatory' => false,
+        'condition' => $requirementsChecker->checkPhpIniOff("expose_php"),
+        'by' => 'Security reasons',
+        'memo' => '"expose_php" should be disabled at php.ini',
+    ),
+    'phpAllowUrlInclude' => array(
+        'name' => 'PHP allow url include',
+        'mandatory' => false,
+        'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"),
+        'by' => 'Security reasons',
+        'memo' => '"allow_url_include" should be disabled at php.ini',
+    ),
+    'phpSmtp' => array(
+        'name' => 'PHP mail SMTP',
+        'mandatory' => false,
+        'condition' => strlen(ini_get('SMTP')) > 0,
+        'by' => 'Email sending',
+        'memo' => 'PHP mail SMTP server required',
+    ),
+);
+
+// OPcache check
+if (!version_compare(phpversion(), '5.5', '>=')) {
+    $requirements[] = array(
+        'name' => 'APC extension',
+        'mandatory' => false,
+        'condition' => extension_loaded('apc'),
+        'by' => '<a href="http://www.yiiframework.com/doc-2.0/yii-caching-apccache.html">ApcCache</a>',
+    );
+}
+
+$result = $requirementsChecker->checkYii()->check($requirements)->getResult();
+$requirementsChecker->render();
+exit($result['summary']['errors'] === 0 ? 0 : 1);

+ 2 - 0
runtime/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 6 - 0
tests/_bootstrap.php

@@ -0,0 +1,6 @@
+<?php
+define('YII_ENV', 'test');
+defined('YII_DEBUG') or define('YII_DEBUG', true);
+
+require_once __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
+require __DIR__ .'/../vendor/autoload.php';

+ 1 - 0
tests/_data/.gitkeep

@@ -0,0 +1 @@
+

+ 0 - 0
tests/_output/.gitignore


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff