public static function deny($url, $node = \GOTEO_NODE, $role = '*', $user = '******') { //si ya tiene un permiso, se elimina el permiso en vez de añadir una denegacion if (!empty($user) && $user != '*') { $values = array(':user' => $user, ':url' => $url); $sql = "SELECT id FROM acl WHERE user_id = :user AND url = :url AND allow = 1"; $query = Model::query($sql, $values); if ($query->rowCount() > 0) { return (bool) Model::query("DELETE FROM acl WHERE user_id = :user AND url = :url", $values); } } return static::addperms($url, $node, $role, $user, false); }
public static function getDonors($year) { $year0 = $year; $year1 = $year + 1; $list = array(); $sql = "SELECT\n user.id as user,\n user.name as name,\n user.email as email,\n user.lang as lang\n FROM invest\n INNER JOIN user ON user.id = invest.user\n WHERE invest.status IN ('1', '3')\n AND invest.charged >= '{$year0}-01-01'\n AND invest.charged < '{$year1}-01-01'\n GROUP BY invest.user\n ORDER BY user.email ASC"; if ($query = Model::query($sql, $values)) { foreach ($query->fetchAll(\PDO::FETCH_OBJ) as $receiver) { $list[] = $receiver; } } return $list; }
/** * Metodo para sacar las que hay en proyectos * @return array strings */ public static function getList() { $results = array(); $sql = "SELECT distinct(project_location) as location\n FROM project\n WHERE status > 2\n ORDER BY location ASC"; try { $query = Model::query($sql); foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $item) { $results[md5($item->location)] = $item->location; } return $results; } catch (\PDOException $e) { throw new Exception('Fallo la lista de localizaciones'); } }
private static function getDataRow($sql, $filters) { if (empty($sql)) { return array(); } $query = Model::query($sql); $rows = $query->fetchAll(\PDO::FETCH_NUM); $data = ''; foreach ($rows as $row) { if ($data == '') { $data .= $row[0]; } else { $data .= '<br /> ' . $row[0]; } } return array($data); }
/** * solo si recibe un token válido */ public function index($token) { if (!empty($token) && !empty($_GET['email'])) { $token = base64_decode($token); $parts = explode('¬', $token); if (count($parts) > 2 && ($_GET['email'] == $parts[1] || $parts[1] == 'any') && !empty($parts[2])) { // cogemos el contenido de la bbdd y lo pintamos aqui tal cual if ($query = Model::query('SELECT html FROM mail WHERE email = ? AND id = ?', array($parts[1], $parts[2]))) { $content = $query->fetchColumn(); $baja = SEC_URL . '/user/leave/?email=' . $parts[1]; if ($parts[1] == 'any') { return new View('view/email/newsletter.html.php', array('content' => $content, 'baja' => '')); } else { return new View('view/email/goteo.html.php', array('content' => $content, 'baja' => $baja)); } } } } throw new Redirection('/'); }
public static function reach($amount) { if (!is_numeric($amount)) { return false; } $values = array(':amount' => $amount, ':lang' => \LANG); $sql = "SELECT\n worthcracy.id as id,\n IFNULL(worthcracy_lang.name, worthcracy.name) as name\n FROM worthcracy\n LEFT JOIN worthcracy_lang\n ON worthcracy_lang.id = worthcracy.id\n AND worthcracy_lang.lang = :lang\n WHERE worthcracy.amount <= :amount\n ORDER BY worthcracy.amount DESC\n LIMIT 1\n "; $query = Model::query($sql, $values); return $query->fetchObject(); }
public static function save($data, &$errors = array()) { $fields = static::_fields(); if (empty($data)) { $errors[] = "Sin datos"; return false; } if (empty($data['lang']) || $data['lang'] == 'original') { $errors[] = "No se peude traducir el contenido original, seleccionar un idioma para traducir"; return false; } try { // tenemos el id en $this->id (el campo id siempre se llama id) // tenemos el lang en $this->lang // tenemos el nombre de la tabla en $this->table // tenemos los campos en $fields[$table] y el contenido de cada uno en $this->$field $set = '`id` = :id, `lang` = :lang '; $values = array(':id' => $data['id'], ':lang' => $data['lang']); foreach ($fields[$data['table']] as $field => $fieldDesc) { if ($set != '') { $set .= ", "; } $set .= "`{$field}` = :{$field} "; $values[":{$field}"] = $data[$field]; } $sql = "REPLACE INTO {$data['table']}_lang SET {$set}"; if (Model::query($sql, $values)) { return true; } else { $errors[] = "Ha fallado {$sql} con <pre>" . print_r($values, 1) . "</pre>"; return false; } } catch (\PDOException $e) { $errors[] = 'Error sql al grabar el contenido multiidioma. ' . $e->getMessage(); return false; } }
public static function process($action = 'list', $id = null, $filters = array()) { switch ($action) { case 'init': if ($_SERVER['REQUEST_METHOD'] == 'POST') { // plantilla $template = $_POST['template']; // destinatarios if ($_POST['test']) { $users = Boletin::getTesters(); } elseif ($template == 33) { // los destinatarios de newsletter $users = Boletin::getReceivers(); } elseif ($template == 35) { // los destinatarios para testear a subscriptores $users = Boletin::getReceivers(); } // sin idiomas $nolang = $_POST['nolang']; if ($nolang) { $receivers[LANG] = $users; } else { // separamos destinatarios en idiomas $receivers = array(); foreach ($users as $usr) { if (empty($usr->lang) || $usr->lang == LANG) { $receivers[LANG][] = $usr; } else { $receivers[$usr->lang][] = $usr; } } } // idiomas que vamos a enviar $langs = array_keys($receivers); // para cada idioma foreach ($langs as $lang) { // destinatarios $recipients = $receivers[$lang]; // datos de la plantilla $tpl = Template::get($template, $lang); // contenido de newsletter $content = $template == 33 ? Boletin::getContent($tpl->text, $lang) : ($content = $tpl->text); // asunto $subject = $tpl->title; // creamos instancia $sql = "INSERT INTO mail (id, email, html, template) VALUES ('', :email, :html, :template)"; $values = array(':email' => 'any', ':html' => $content, ':template' => $template); $query = \Goteo\Core\Model::query($sql, $values); $mailId = \Goteo\Core\Model::insertId(); // inicializamos el envío if (Sender::initiateSending($mailId, $subject, $recipients, true)) { // ok... } else { Message::Error('No se ha podido iniciar el mailing con asunto "' . $subject . '"'); } } } throw new Redirection('/admin/newsletter'); break; case 'activate': if (Sender::activateSending($id)) { Message::Info('Se ha activado un nuevo envío automático'); } else { Message::Error('No se pudo activar el envío. Iniciar de nuevo'); } throw new Redirection('/admin/newsletter'); break; case 'detail': $mailing = Sender::getSending($id); $list = Sender::getDetail($id, $filters['show']); return new View('view/admin/index.html.php', array('folder' => 'newsletter', 'file' => 'detail', 'detail' => $filters['show'], 'mailing' => $mailing, 'list' => $list)); break; default: $list = Sender::getMailings(); return new View('view/admin/index.html.php', array('folder' => 'newsletter', 'file' => 'list', 'list' => $list)); } }
$wait_time = ceil($current_rate - MAIL_MAX_RATE * 0.9); $current_concurrency--; if ($debug) { echo "Ratio de envio actual mayor a un 90% del máximo, esperamos {$wait_time} segundos, disminuimos concurrencia a {$current_concurrency}\n"; } sleep($wait_time); } $i += $increment; $increment = $current_concurrency; } //end while } if ($debug) { echo "dbg: desbloqueo este registro\n"; } Model::query('UPDATE mailer_content SET blocked = 0 WHERE id = ?', array($mailing->id)); } else { if ($debug) { echo "dbg: FALLO\n"; } } if ($debug) { echo "dbg: FIN, tiempo de ejecución total " . round(microtime(true) - $itime, 2) . " segundos para enviar {$total_users} emails, ratio medio " . round($total_users / (microtime(true) - $itime), 2) . " emails/segundo\n"; } // limpiamos antiguos procesados Sender::cleanOld(); /** * Comprueba si se está ejecutando un proceso cli-sendmail.php con un pid determinado * @param [type] $pid [description] * @return [type] [description] */
public function save(&$errors = array()) { if (!$this->validate($errors)) { return false; } try { $values = array(':template' => $this->id, ':name' => $this->name, ':group' => $this->group, ':purpose' => $this->purpose, ':title' => $this->title, ':text' => $this->text); $sql = "REPLACE INTO template\n (id, name, purpose, title, text, `group`)\n VALUES\n (:template, :name, :purpose, :title, :text, :group)\n "; if (Model::query($sql, $values)) { return true; } else { $errors[] = Text::_("Ha fallado ") . $sql . Text::_('con') . " <pre>" . print_r($values, 1) . "</pre>"; return false; } } catch (\PDOException $e) { $errors[] = Text::_('Error sql al grabar el contenido de la palntilla. ') . $e->getMessage(); return false; } }
/** * * @param array $filters user (nombre o email), template */ public static function getSended($filters = array(), $node = null, $limit = 9) { $values = array(); $sqlFilter = ''; $and = " WHERE"; if (!empty($filters['user'])) { $sqlFilter .= $and . " mail.email LIKE :user"; $and = " AND"; $values[':user'] = "******"; } if (!empty($filters['template'])) { $sqlFilter .= $and . " mail.template = :template"; $and = " AND"; $values[':template'] = $filters['template']; } /* if ($node != \GOTEO_NODE) { $sqlFilter .= $and . " mail.node = :node"; $and = " AND"; $values[':node'] = $node; } else */ if (!empty($filters['node'])) { $sqlFilter .= $and . " mail.node = :node"; $and = " AND"; $values[':node'] = $filters['node']; } if (!empty($filters['date_from'])) { $sqlFilter .= $and . " mail.date >= :date_from"; $and = " AND"; $values[':date_from'] = $filters['date_from']; } if (!empty($filters['date_until'])) { $sqlFilter .= $and . " mail.date <= :date_until"; $and = " AND"; $values[':date_until'] = $filters['date_until']; } $sql = "SELECT\r\n mail.id as id,\r\n mail.email as email,\r\n mail.template as template,\r\n DATE_FORMAT(mail.date, '%d/%m/%Y %H:%i') as date\r\n FROM mail\r\n {$sqlFilter}\r\n ORDER BY mail.date DESC\r\n LIMIT {$limit}"; $query = Model::query($sql, $values); return $query->fetchAll(\PDO::FETCH_OBJ); }
public static function process($action = 'list', $id = null, $filters = array()) { $errors = array(); $node = empty($_SESSION['admin_node']) ? \GOTEO_NODE : $_SESSION['admin_node']; $blog = Model\Blog::get($node, 'node'); if (!$blog instanceof \Goteo\Model\Blog) { $blog = new Model\Blog(array('type' => 'node', 'owner' => $node, 'active' => 1)); if ($blog->save($errors)) { Message::Info(Text::get('admin-blog-info-initialize')); } else { Message::Error(Text::get('admin-blog-error-initialize')); throw new Redirection('/admin'); } } elseif (!$blog->active) { Message::Error(Text::get('admin-blog-error-no_blog')); throw new Redirection('/admin'); } // primero comprobar que tenemos blog if (!$blog instanceof Model\Blog) { Message::Error(Text::get('admin-blog-error-not_found')); throw new Redirection('/admin'); } $url = '/admin/blog'; if ($_SERVER['REQUEST_METHOD'] == 'POST') { if (empty($_POST['blog'])) { Message::Error(Text::get('admin-blog-error_missing_blog')); break; } $editing = false; if (!empty($_POST['id'])) { $post = Model\Blog\Post::get($_POST['id']); } else { $post = new Model\Blog\Post(); } // campos que actualizamos $fields = array('id', 'blog', 'title', 'text', 'image', 'media', 'legend', 'date', 'publish', 'home', 'footer', 'allow', 'author'); foreach ($fields as $field) { $post->{$field} = $_POST[$field]; } // tratar la imagen y ponerla en la propiedad image if (!empty($_FILES['image_upload']['name'])) { $post->image = $_FILES['image_upload']; $editing = true; } // tratar las imagenes que quitan foreach ($post->gallery as $key => $image) { if (!empty($_POST["gallery-{$image->id}-remove"])) { $image->remove('post'); unset($post->gallery[$key]); if ($post->image == $image->id) { $post->image = ''; } $editing = true; } } if (!empty($post->media)) { $post->media = new Model\Project\Media($post->media); } $post->tags = $_POST['tags']; // si tenemos un nuevio tag hay que añadirlo if (!empty($_POST['new-tag_save']) && !empty($_POST['new-tag'])) { // grabar el tag en la tabla de tag, $new_tag = new Model\Blog\Post\Tag(array('id' => '', 'name' => $_POST['new-tag'])); if ($new_tag->save($errors)) { $post->tags[] = $new_tag->id; // asignar al post } else { Message::Error(implode('<br />', $errors)); } $editing = true; // seguir editando } /// este es el único save que se lanza desde un metodo process_ if ($post->save($errors)) { if ($action == 'edit') { Message::Info(Text::get('admin-blog-info-updates-saved')); } else { Message::Info(Text::get('admin-blog-info-add_new')); $id = $post->id; } $action = $editing ? 'edit' : 'list'; if ((bool) $post->publish) { // Evento Feed $log = new Feed(); $log->setTarget('goteo', 'blog'); $log->populate('nueva entrada blog Goteo (admin)', '/admin/blog', \vsprintf('El admin %s ha %s en el blog Goteo la entrada "%s"', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', 'Publicado'), Feed::item('blog', $post->title, $post->id)))); $log->doAdmin('admin'); // evento público $log->unique = true; $log->populate($post->title, '/blog/' . $post->id, Text::recorta($post->text, 250), $post->gallery[0]->id); $log->doPublic('goteo'); unset($log); } else { //sino lo quitamos \Goteo\Core\Model::query("DELETE FROM feed WHERE url = '/blog/{$post->id}' AND scope = 'public' AND type = 'goteo'"); } } else { Message::Error(Text::get('admin-blog-error-save-fail') . ':<br />' . \implode('<br />', $errors)); } } switch ($action) { case 'list': // lista de entradas // obtenemos los datos $filters['node'] = $node; $show = array('all' => 'Todas las entradas existentes', 'published' => 'Solamente las publicadas en el blog', 'owned' => 'Solamente las del propio nodo', 'home' => 'Solamente las de portada', 'entries' => 'Solamente las de cierto nodo', 'updates' => 'Solamente las de proyectos'); // filtro de blogs de proyectos/nodos switch ($filters['show']) { case 'updates': $blogs = Model\Blog::getListProj(); break; case 'entries': $blogs = Model\Blog::getListNode(); break; } if (!in_array($filters['show'], array('entries', 'updates')) || !isset($blogs[$filters['blog']])) { unset($filters['blog']); } $posts = Model\Blog\Post::getList($filters, false); $homes = Model\Post::getList('home', $node); $footers = Model\Post::getList('footer', $node); if ($node == \GOTEO_NODE) { $show['footer'] = 'Solamente las del footer'; } return new View('view/admin/index.html.php', array('folder' => 'blog', 'file' => 'list', 'posts' => $posts, 'filters' => $filters, 'show' => $show, 'blogs' => $blogs, 'homes' => $homes, 'footers' => $footers, 'node' => $node)); break; case 'add': // nueva entrada con wisiwig // obtenemos datos basicos $post = new Model\Blog\Post(array('blog' => $blog->id, 'date' => date('Y-m-d'), 'publish' => false, 'allow' => true, 'tags' => array(), 'author' => $_SESSION['user']->id)); $message = 'Añadiendo una nueva entrada'; return new View('view/admin/index.html.php', array('folder' => 'blog', 'file' => 'edit', 'action' => 'add', 'post' => $post, 'tags' => Model\Blog\Post\Tag::getAll(), 'message' => $message)); break; case 'edit': if (empty($id)) { Message::Error(Text::get('admin-blog-error-nopost')); throw new Redirection('/admin/blog'); break; } else { $post = Model\Blog\Post::get($id); if (!$post instanceof Model\Blog\Post) { Message::Error(Text::get('admin-blog-error-break_entry')); $action = 'list'; break; } elseif ($node != \GOTEO_NODE && $post->owner_type == 'node' && $post->owner_id != $node) { Message::Error(Text::get('admin-blog-error-noedit')); throw new Redirection('/admin/blog/list'); } } $message = 'Editando una entrada existente'; return new View('view/admin/index.html.php', array('folder' => 'blog', 'file' => 'edit', 'action' => 'edit', 'post' => $post, 'tags' => Model\Blog\Post\Tag::getAll(), 'message' => $message)); break; case 'remove': // eliminar una entrada $tempData = Model\Blog\Post::get($id); if ($node != \GOTEO_NODE && $tempData->owner_type == 'node' && $tempData->owner_id != $node) { Message::Error(Text::get('admin-blog-error-nodelete')); throw new Redirection('/admin/blog'); } if (Model\Blog\Post::delete($id)) { // Evento Feed $log = new Feed(); $log->setTarget('goteo', 'blog'); $log->populate('Quita entrada de blog (admin)', '/admin/blog', \vsprintf('El admin %s ha %s la entrada "%s" del blog de Goteo', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', 'Quitado'), Feed::item('blog', $tempData->title)))); $log->doAdmin('admin'); unset($log); Message::Info(Text::get('admin-blog-info-deleted_entry')); } else { Message::Error(Text::get('admin-blog-error-delete-fail')); } throw new Redirection('/admin/blog/list'); break; // acciones portada // acciones portada case 'reorder': // lista de entradas en portada // obtenemos los datos $posts = Model\Post::getAll('home', $node); return new View('view/admin/index.html.php', array('folder' => 'blog', 'file' => 'order', 'posts' => $posts)); break; case 'up': if ($node != \GOTEO_NODE) { Model\Post::up_node($id, $node); } else { Model\Post::up($id, 'home'); } throw new Redirection('/admin/blog/reorder'); break; case 'down': if ($node != \GOTEO_NODE) { Model\Post::up_node($id, $node); } else { Model\Post::down($id, 'home'); } throw new Redirection('/admin/blog/reorder'); break; case 'add_home': // siguiente orden if ($node != \GOTEO_NODE) { $next = Model\Post::next_node($node); $data = (object) array('post' => $id, 'node' => $node, 'order' => $next); if (Model\Post::update_node($data, $errors)) { Message::Info(Text::get('admin-blog-info-add-home')); } else { Message::Error(Text::get('admin-blog-error-any-problem') . ':<br />' . \implode('<br />', $errors)); } } else { $next = Model\Post::next('home'); $post = new Model\Post(array('id' => $id, 'order' => $next, 'home' => 1)); if ($post->update($errors)) { Message::Info(Text::get('admin-blog-info-add-home')); } else { Message::Error(Text::get('admin-blog-error-any-problem') . ':<br />' . \implode('<br />', $errors)); } } throw new Redirection('/admin/blog/list'); break; case 'remove_home': // se quita de la portada solamente $ok = false; if ($node != \GOTEO_NODE) { $ok = Model\Post::remove_node($id, $node); } else { $ok = Model\Post::remove($id, 'home'); } if ($ok) { Message::Info(Text::get('admin-blog-info-removecover')); } else { Message::Error(Text::get('admin-blog-error-cover-deletefail')); } throw new Redirection('/admin/blog/list'); break; // acciones footer (solo para superadmin y admins de goteo // acciones footer (solo para superadmin y admins de goteo case 'footer': if ($node == \GOTEO_NODE) { // lista de entradas en el footer // obtenemos los datos $posts = Model\Post::getAll('footer'); return new View('view/admin/index.html.php', array('folder' => 'blog', 'file' => 'footer', 'posts' => $posts)); } else { throw new Redirection('/admin/blog/list'); } break; case 'up_footer': if ($node == \GOTEO_NODE) { Model\Post::up($id, 'footer'); throw new Redirection('/admin/blog/footer'); } else { throw new Redirection('/admin/blog'); } break; case 'down_footer': if ($node == \GOTEO_NODE) { Model\Post::down($id, 'footer'); throw new Redirection('/admin/blog/footer'); } else { throw new Redirection('/admin/blog'); } break; case 'add_footer': if ($node == \GOTEO_NODE) { // siguiente orden $next = Model\Post::next('footer'); $post = new Model\Post(array('id' => $id, 'order' => $next, 'footer' => 1)); if ($post->update($errors)) { Message::Info(Text::get('admin-blog-info-footer-complete')); } else { Message::Error(Text::get('admin-blog-error-any-problem') . ':<br />' . \implode('<br />', $errors)); } } throw new Redirection('/admin/blog'); break; case 'remove_footer': if ($node == \GOTEO_NODE) { // se quita del footer solamente if (Model\Post::remove($id, 'footer')) { Message::Info(Text::get('admin-blog-info-footer-delete')); } else { Message::Error(Text::get('admin-blog-error-footer-deletefail')); } } throw new Redirection('/admin/blog/list'); break; } }
/** * Metodo para realizar una busqueda por parametros * @param array multiple $params 'category', 'location', 'reward' * @param bool showall si true, muestra tambien proyectos en estado de edicion y revision * @return array results */ public static function params($params, $showall = false, $limit = null) { $results = array(); $where = array(); $values = array(); if (!empty($params['category'])) { $where[] = 'AND id IN ( SELECT distinct(project) FROM project_category WHERE category IN (' . implode(', ', $params['category']) . ') )'; } if (!empty($params['location'])) { $where[] = 'AND MD5(project_location) IN (' . implode(', ', $params['location']) . ')'; } if (!empty($params['reward'])) { $where[] = 'AND id IN ( SELECT DISTINCT(project) FROM reward WHERE icon IN (' . implode(', ', $params['reward']) . ') )'; } if (!empty($params['query'])) { $where[] = ' AND (name LIKE :text OR description LIKE :text OR motivation LIKE :text OR about LIKE :text OR goal LIKE :text OR related LIKE :text OR keywords LIKE :text OR location LIKE :text )'; $values[':text'] = "%{$params['query']}%"; } if (!empty($params['node'])) { $where[] = ' AND node = :node'; $values[':node'] = NODE_ID; } if (!empty($params['status'])) { $where[] = ' AND status = :status'; $values[':status'] = $params['status']; } $minstatus = $showall ? '1' : '2'; $maxstatus = $showall ? '4' : '7'; $sql = "SELECT id\n FROM project\n WHERE status > {$minstatus}\n AND status < {$maxstatus}\n "; if (!empty($where)) { $sql .= implode(' ', $where); } $sql .= " ORDER BY status ASC, name ASC"; // Limite if (!empty($limit) && \is_numeric($limit)) { $sql .= " LIMIT {$limit}"; } try { $query = Model::query($sql, $values); foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $match) { $results[] = Project::getMedium($match->id); } return $results; } catch (\PDOException $e) { throw new Exception('Fallo la sentencia de busqueda'); } }
public function execute() { if (!\defined('CRON_EXEC')) { @mail(\GOTEO_FAIL_MAIL, 'Se ha lanzado MANUALMENTE el cron ' . __FUNCTION__ . ' en ' . SITE_URL, 'Se ha lanzado manualmente el cron ' . __FUNCTION__ . ' en ' . SITE_URL . ' a las ' . date('H:i:s') . ' Usuario ' . $_SESSION['user']->id); echo 'Lanzamiento manual a las ' . date('H:i:s') . ' <br />'; } else { echo 'Lanzamiento automatico a las ' . date('H:i:s') . ' <br />'; } // a ver si existe el bloqueo $block_file = GOTEO_PATH . 'logs/cron-' . __FUNCTION__ . '.block'; if (file_exists($block_file)) { echo 'Ya existe un archivo de log ' . date('Ymd') . '_' . __FUNCTION__ . '.log<br />'; $block_content = \file_get_contents($block_file); echo 'El contenido del bloqueo es: ' . $block_content; // lo escribimos en el log $log_file = GOTEO_PATH . 'logs/cron/' . date('Ymd') . '_' . __FUNCTION__ . '.log'; \file_put_contents($log_file, \ob_get_contents(), FILE_APPEND); \chmod($log_file, 0777); /* @mail(\GOTEO_FAIL_MAIL, 'Cron '. __FUNCTION__ .' bloqueado en ' . SITE_URL, 'Se ha encontrado con que el cron '. __FUNCTION__ .' está bloqueado el '.date('d-m-Y').' a las ' . date ('H:i:s') . ' El contenido del bloqueo es: '. $block_content); */ die; } else { $block = 'Bloqueo del ' . $block_file . ' activado el ' . date('d-m-Y') . ' a las ' . date('H:i:s') . '<br />'; if (\file_put_contents($block_file, $block, FILE_APPEND)) { \chmod($block_file, 0777); echo $block; } else { echo 'No se ha podido crear el archivo de bloqueo<br />'; @mail(\GOTEO_FAIL_MAIL, 'Cron ' . __FUNCTION__ . ' no se ha podido bloquear en ' . SITE_URL, 'No se ha podido crear el archivo ' . $block_file . ' el ' . date('d-m-Y') . ' a las ' . date('H:i:s')); } } echo '<hr />'; // debug para supervisar en las fechas clave // $debug = ($_GET['debug'] == 'debug') ? true : false; $debug = true; // revision de proyectos: dias, conseguido y cambios de estado // proyectos en campaña, // (publicados hace más de 40 días que no tengan fecha de pase) // o (publicados hace mas de 80 días que no tengan fecha de exito) $projects = Model\Project::getActive(); if ($debug) { echo 'Comenzamos con los proyectos en campaña (esto está en ' . \LANG . ')<br /><br />'; } foreach ($projects as $project) { if ($debug) { echo 'Proyecto ' . $project->name . '<br />'; } // a ver si tiene cuenta paypal $projectAccount = Model\Project\Account::get($project->id); /* if (empty($projectAccount->paypal)) { if ($debug) echo 'No tiene cuenta PayPal<br />'; // Evento Feed solamente si automático if (\defined('CRON_EXEC')) { $log = new Feed(); $log->setTarget($project->id); $log->populate('proyecto sin cuenta paypal (cron)', '/admin/projects', \vsprintf('El proyecto %s aun no ha puesto su %s !!!', array( Feed::item('project', $project->name, $project->id), Feed::item('relevant', 'cuenta PayPal') ))); $log->doAdmin('project'); unset($log); // mail de aviso $mailHandler = new Mail(); $mailHandler->to = \GOTEO_CONTACT_MAIL; $mailHandler->toName = 'Goteo.org'; $mailHandler->subject = 'El proyecto '.$project->name.' no tiene cuenta PayPal'; $mailHandler->content = 'Hola Goteo, el proyecto '.$project->name.' no tiene cuenta PayPal y el proceso automatico no podrá tratar los preaprovals al final de ronda.'; $mailHandler->html = false; $mailHandler->template = null; $mailHandler->send(); unset($mailHandler); $task = new Model\Task(); $task->node = \GOTEO_NODE; $task->text = "Poner la cuenta PayPal al proyecto <strong>{$project->name}</strong> urgentemente!"; $task->url = "/admin/projects/accounts/{$project->id}"; $task->done = null; $task->saveUnique(); } } */ $log_text = null; if ($debug) { echo 'Minimo: ' . $project->mincost . ' ¥ <br />'; } $execute = false; $cancelAll = false; if ($debug) { echo 'Obtenido: ' . $project->amount . ' ¥<br />'; } // porcentaje alcanzado if ($project->mincost > 0) { $per_amount = \floor($project->amount / $project->mincost * 100); } else { $per_amount = 0; } if ($debug) { echo 'Ha alcanzado el ' . $per_amount . ' % del minimo<br />'; } // los dias que lleva el proyecto (ojo que los financiados llevaran mas de 80 dias) $days = $project->daysActive(); if ($debug) { echo 'Lleva ' . $days . ' dias desde la publicacion<br />'; } /* Verificar si enviamos aviso */ $rest = $project->days; $round = $project->round; if ($debug) { echo 'Quedan ' . $rest . ' dias para el final de la ' . $round . 'a ronda<br />'; } // a los 5, 3, 2, y 1 dia para finalizar ronda if ($round > 0 && in_array((int) $rest, array(5, 3, 2, 1))) { if ($debug) { echo 'Feed publico cuando quedan 5, 3, 2, 1 dias<br />'; } // Evento Feed solo si ejecucion automática if (\defined('CRON_EXEC')) { $log = new Feed(); $log->setTarget($project->id); $log->populate('proyecto próximo a finalizar ronda (cron)', '/admin/projects', Text::html('feed-project_runout', Feed::item('project', $project->name, $project->id), $rest, $round)); $log->doAdmin('project'); // evento público $log->title = $project->name; $log->url = null; $log->doPublic('projects'); unset($log); } } // (financiado a los 80 o cancelado si a los 40 no llega al minimo) // si ha llegado a los 40 dias: mínimo-> ejecutar ; no minimo proyecto y todos los preapprovals cancelados // (Funded at 80 or canceled if the 40 does not reach the minimum) // If it has reached 40 days: minimum-> execute; no minimum project and canceled all preapprovals if ($days >= 40) { // si no ha alcanzado el mínimo, pasa a estado caducado // If you have not reached the minimum, goes into Expired if ($project->amount < $project->mincost) { if ($debug) { echo 'Ha llegado a los 40 dias de campaña sin conseguir el minimo, no pasa a segunda ronda<br />'; } echo $project->name . ': ha recaudado ' . $project->amount . ', ' . $per_amount . '% de ' . $project->mincost . '/' . $project->maxcost . '<br />'; echo 'No ha conseguido el minimo, cancelamos todos los aportes y lo caducamos:'; $cancelAll = true; $errors = array(); if ($project->fail($errors)) { $log_text = Text::_('El proyecto %s ha %s obteniendo %s'); } else { @mail(\GOTEO_FAIL_MAIL, 'Fallo al archivar ' . SITE_URL, 'Fallo al marcar el proyecto ' . $project->name . ' como archivado ' . implode(',', $errors)); echo 'ERROR::' . implode(',', $errors); $log_text = Text::_('El proyecto %s ha fallado al, %s obteniendo %s'); } echo '<br />'; // Evento Feed solo si ejecucion automatica if (\defined('CRON_EXEC')) { $log = new Feed(); $log->setTarget($project->id); $log->populate('proyecto archivado (cron)', '/admin/projects', \vsprintf($log_text, array(Feed::item('project', $project->name, $project->id), Feed::item('relevant', 'caducado sin éxito'), Feed::item('money', $project->amount . ' ¥ (' . $per_amount . '%) de aportes sobre minimo')))); $log->doAdmin('project'); // evento público $log->populate($project->name, null, Text::html('feed-project_fail', Feed::item('project', $project->name, $project->id), $project->amount, $per_amount)); $log->doPublic('projects'); unset($log); //Email de proyecto fallido al autor Cron\Send::toOwner('fail', $project); //Email de proyecto fallido a los inversores Cron\Send::toInvestors('fail', $project); } echo '<br />'; } else { // tiene hasta 80 días para conseguir el óptimo (o más) // Has up to 80 days for optimum (or more) if ($days >= 80) { if ($debug) { echo 'Ha llegado a los 80 dias de campaña (final de segunda ronda)<br />'; } echo $project->name . ': ha recaudado ' . $project->amount . ', ' . $per_amount . '% de ' . $project->mincost . '/' . $project->maxcost . '<br />'; echo 'Ha llegado a los 80 días: financiado. '; $execute = true; // ejecutar los cargos de la segunda ronda $errors = array(); if ($project->succeed($errors)) { $log_text = Text::_('El proyecto %s ha sido %s obteniendo %s'); } else { @mail(\GOTEO_FAIL_MAIL, 'Fallo al marcar financiado ' . SITE_URL, 'Fallo al marcar el proyecto ' . $project->name . ' como financiado ' . implode(',', $errors)); echo 'ERROR::' . implode(',', $errors); $log_text = Text::_('El proyecto %s ha fallado al ser, %s obteniendo %s'); } // Evento Feed y mails solo si ejecucion automatica if (\defined('CRON_EXEC')) { $log = new Feed(); $log->setTarget($project->id); $log->populate('proyecto supera segunda ronda (cron)', '/admin/projects', \vsprintf($log_text, array(Feed::item('project', $project->name, $project->id), Feed::item('relevant', 'financiado'), Feed::item('money', $project->amount . ' ¥ (' . \round($per_amount) . '%) de aportes sobre minimo')))); $log->doAdmin('project'); // evento público $log->populate($project->name, null, Text::html('feed-project_finish', Feed::item('project', $project->name, $project->id), $project->amount, \round($per_amount))); $log->doPublic('projects'); unset($log); //Email de proyecto final segunda ronda al autor Cron\Send::toOwner('r2_pass', $project); //Email de proyecto final segunda ronda a los inversores Cron\Send::toInvestors('r2_pass', $project); // Tareas para gestionar // calculamos fecha de passed+90 días $passtime = strtotime($project->passed); $limsec = date('d/m/Y', \mktime(0, 0, 0, date('m', $passtime), date('d', $passtime) + 89, date('Y', $passtime))); /* * Ya no hacemos pagos secundarios mediante sistema $task = new Model\Task(); $task->node = \GOTEO_NODE; $task->text = "Hacer los pagos secundarios al proyecto <strong>{$project->name}</strong> antes del día <strong>{$limsec}</strong>"; $task->url = "/admin/accounts/?projects={$project->id}"; $task->done = null; $task->save(); */ // y preparar contrato $task = new Model\Task(); $task->node = \GOTEO_NODE; $task->text = date('d/m/Y') . ": Enviar datos contrato <strong>{$project->name}</strong>, {$project->user->name}"; //@TODO enlace a gestión de contrato $task->url = "/admin/projects?proj_name={$project->name}"; $task->done = null; $task->saveUnique(); // + mail a mercè @mail(\GOTEO_CONTACT_MAIL, 'Preparar contrato ' . $project->name, 'El proyecto ' . $project->name . ' ha pasado la primera ronda, enviarle los datos de contrato. Se ha creado una tarea para esto.'); } echo '<br />'; } elseif (empty($project->passed)) { if ($debug) { echo 'Ha llegado a los 40 dias de campaña, pasa a segunda ronda<br />'; } echo $project->name . ': ha recaudado ' . $project->amount . ', ' . $per_amount . '% de ' . $project->mincost . '/' . $project->maxcost . '<br />'; echo 'El proyecto supera la primera ronda: marcamos fecha'; $execute = true; // ejecutar los cargos de la primera ronda $errors = array(); if ($project->passed($errors)) { // se crea el registro de contrato // Recording contract is created if (Model\Contract::create($project->id, $errors)) { echo ' -> Ok:: se ha creado el registro de contrato'; } else { @mail(\GOTEO_FAIL_MAIL, 'Fallo al crear registro de contrato ' . SITE_URL, 'Fallo al crear registro de contrato para el proyecto ' . $project->name . ': ' . implode(',', $errors)); echo ' -> semi-Ok: se ha actualiuzado el estado del proyecto pero ha fallado al crear el registro de contrato. ERROR: ' . implode(',', $errors); } } else { @mail(\GOTEO_FAIL_MAIL, 'Fallo al marcar fecha de paso a segunda ronda ' . SITE_URL, 'Fallo al marcar la fecha de paso a segunda ronda para el proyecto ' . $project->name . ': ' . implode(',', $errors)); echo ' -> ERROR::' . implode(',', $errors); } echo '<br />'; // Evento Feed solo si ejecucion automatica if (\defined('CRON_EXEC')) { $log = new Feed(); $log->setTarget($project->id); $log->populate('proyecto supera primera ronda (cron)', '/admin/projects', \vsprintf('El proyecto %s %s en segunda ronda obteniendo %s', array(Feed::item('project', $project->name, $project->id), Feed::item('relevant', 'continua en campaña'), Feed::item('money', $project->amount . ' ¥ (' . \number_format($per_amount, 2) . '%) de aportes sobre minimo')))); $log->doAdmin('project'); // evento público $log->populate($project->name, null, Text::html('feed-project_goon', Feed::item('project', $project->name, $project->id), $project->amount, \round($per_amount))); $log->doPublic('projects'); unset($log); if ($debug) { echo 'Email al autor y a los cofinanciadores<br />'; } // Email de proyecto pasa a segunda ronda al autor Cron\Send::toOwner('r1_pass', $project); //Email de proyecto pasa a segunda ronda a los inversores Cron\Send::toInvestors('r1_pass', $project); // Tarea para hacer los pagos $task = new Model\Task(); $task->node = \GOTEO_NODE; $task->text = date('d/m/Y') . ": Pagar a <strong>{$project->name}</strong>, {$project->user->name}"; $task->url = "/admin/projects/report/{$project->id}"; $task->done = null; $task->saveUnique(); // + mail a susana @mail('*****@*****.**', 'Pagar al proyecto ' . $project->name, 'El proyecto ' . $project->name . ' ha terminado la segunda ronda, hacer los pagos. Se ha creado una tarea para esto.'); } } else { if ($debug) { echo 'Lleva más de 40 dias de campaña, debe estar en segunda ronda con fecha marcada<br />'; } if ($debug) { echo $project->name . ': lleva recaudado ' . $project->amount . ', ' . $per_amount . '% de ' . $project->mincost . '/' . $project->maxcost . ' y paso a segunda ronda el ' . $project->passed . '<br />'; } } } } // si hay que ejecutar o cancelar if ($cancelAll || $execute) { if ($debug) { echo '::::::Comienza tratamiento de aportes:::::::<br />'; } if ($debug) { echo 'Execute=' . (string) $execute . ' CancelAll=' . (string) $cancelAll . '<br />'; } // tratamiento de aportes penddientes $query = \Goteo\Core\Model::query("\n SELECT *\n FROM invest\n WHERE invest.project = ?\n AND (invest.status = 0\n OR (invest.method = 'tpv'\n AND invest.status = 1\n )\n OR (invest.method = 'cash'\n AND invest.status = 1\n )\n )\n AND (invest.campaign IS NULL OR invest.campaign = 0)\n ", array($project->id)); $project->invests = $query->fetchAll(\PDO::FETCH_CLASS, '\\Goteo\\Model\\Invest'); foreach ($project->invests as $key => $invest) { $errors = array(); $log_text = null; $userData = Model\User::getMini($invest->user); if ($invest->invested == date('Y-m-d')) { if ($debug) { echo 'Aporte ' . $invest->id . ' es de hoy.<br />'; } } elseif ($invest->method != 'cash' && empty($invest->preapproval)) { //si no tiene preaproval, cancelar //echo 'Aporte ' . $invest->id . ' cancelado por no tener preapproval.<br />'; //$invest->cancel(); //Model\Invest::setDetail($invest->id, 'no-preapproval', 'Aporte cancelado porque no tiene preapproval. Proceso cron/execute'); //continue; } if ($cancelAll) { if ($debug) { echo 'Cancelar todo<br />'; } switch ($invest->method) { // case 'paypal': // $err = array(); // if (Paypal::cancelPreapproval($invest, $err, true)) { // $log_text = Text::_("Se ha cancelado aporte y preapproval de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s"); // } else { // $txt_errors = implode('; ', $err); // $log_text = Text::_("Ha fallado al cancelar el aporte de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores:") . $txt_errors; // } // break; case 'axes': if ($invest->cancel(true)) { $log_text = Text::_("Contribution is canceled"); } else { $log_text = Text::_("Failed to cancel"); } break; case 'tpv': // se habre la operación en optra ventana $err = array(); if (Tpv::cancelPreapproval($invest, $err, true)) { $log_text = Text::_("Se ha anulado el cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s"); } else { $txt_errors = implode('; ', $err); $log_text = Text::_("Ha fallado al anular el cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores: ") . $txt_errors; } break; case 'cash': if ($invest->cancel(true)) { $log_text = Text::_("Se ha cancelado aporte manual de %s de %s (id: %s) al proyecto %s del dia %s"); } else { $log_text = Text::_("Ha fallado al cancelar el aporte manual de %s de %s (id: %s) al proyecto %s del dia %s. "); } break; } // Evento Feed admin $log = new Feed(); $log->setTarget($project->id); $log->populate('Preapproval cancelado por proyecto archivado (cron)', '/admin/invests', \vsprintf($log_text, array(Feed::item('user', $userData->name, $userData->id), Feed::item('money', $invest->amount . ' ¥'), Feed::item('system', $invest->id), Feed::item('project', $project->name, $project->id), Feed::item('system', date('d/m/Y', strtotime($invest->invested)))))); $log->doAdmin(); unset($log); echo 'Aporte ' . $invest->id . ' cancelado por proyecto caducado.<br />'; $invest->setStatus('4'); Model\Invest::setDetail($invest->id, 'project-expired', 'Aporte marcado como caducado porque el proyecto no ha tenido exito. Proceso cron/execute'); continue; } // si hay que ejecutar if ($execute && empty($invest->payment)) { if ($debug) { echo 'Ejecutando aporte ' . $invest->id . ' [' . $invest->method . ']'; } switch ($invest->method) { /* cronではなく管理画面から手動で(admin/invests/dopay) case 'axes': $err = array(); if ($invest->setPayment(date("YmdHis"))) { $invest->setStatus(1); $log_text = Text::_("Has been executed under its %s %s contribution via Axes (id:%s) to the project %s %s of the day"); if ($debug) echo ' -> Ok'; Model\Invest::setDetail($invest->id, 'executed', 'Preapproval has been executed, has initiated the chained payment. Process cron / execute'); // si era incidencia la desmarcamos if ($invest->issue) { Model\Invest::unsetIssue($invest->id); Model\Invest::setDetail($invest->id, 'issue-solved', 'The incidence has been resolved upon success by the automatic process'); } } break;*/ case 'paypal': if (empty($projectAccount->paypal)) { if ($debug) { echo '<br />El proyecto ' . $project->name . ' no tiene cuenta paypal.<br />'; } Model\Invest::setDetail($invest->id, 'no-paypal-account', 'El proyecto no tiene cuenta paypal en el momento de ejecutar el preapproval. Proceso cron/execute'); break; } $invest->account = $projectAccount->paypal; $err = array(); if (Paypal::pay($invest, $err)) { $log_text = Text::_("Se ha ejecutado el cargo a %s por su aporte de %s mediante PayPal (id: %s) al proyecto %s del dia %s"); if ($debug) { echo ' -> Ok'; } Model\Invest::setDetail($invest->id, 'executed', 'Se ha ejecutado el preapproval, ha iniciado el pago encadenado. Proceso cron/execute'); // si era incidencia la desmarcamos if ($invest->issue) { Model\Invest::unsetIssue($invest->id); Model\Invest::setDetail($invest->id, 'issue-solved', 'La incidencia se ha dado por resuelta al ejecutarse correctamente en el proceso automático'); } } else { $txt_errors = implode('; ', $err); echo 'Aporte ' . $invest->id . ': Fallo al ejecutar cargo paypal: ' . $txt_errors . '<br />'; @mail(\GOTEO_FAIL_MAIL, 'Fallo al ejecutar cargo Paypal ' . SITE_URL, 'Aporte ' . $invest->id . ': Fallo al ejecutar cargo paypal: ' . $txt_errors); if ($debug) { echo ' -> ERROR!!'; } Model\Invest::setDetail($invest->id, 'execution-failed', 'Fallo al ejecutar el preapproval, no ha iniciado el pago encadenado: ' . $txt_errors . '. Proceso cron/execute'); // Notifiacion de incidencia al usuario // Obtenemos la plantilla para asunto y contenido $template = Template::get(37); // Sustituimos los datos $subject = str_replace('%PROJECTNAME%', $project->name, $template->title); $search = array('%USERNAME%', '%PROJECTNAME%', '%PROJECTURL%', '%AMOUNT%', '%DETAILS%'); $replace = array($userData->name, $project->name, SITE_URL . '/project/' . $project->id, $invest->amount, ''); $content = \str_replace($search, $replace, $template->text); // iniciamos mail $mailHandler = new Mail(); $mailHandler->from = GOTEO_CONTACT_MAIL; $mailHandler->to = $userData->email; $mailHandler->toName = $userData->name; $mailHandler->subject = $subject; $mailHandler->content = $content; $mailHandler->html = true; $mailHandler->template = $template->id; if ($mailHandler->send()) { Model\Invest::setDetail($invest->id, 'issue-notified', "Se ha notificado la incidencia al usuario"); } else { Model\Invest::setDetail($invest->id, 'issue-notify-failed', "Ha fallado al enviar el mail de notificacion de la incidencia al usuario"); @mail(\GOTEO_FAIL_MAIL, 'Fallo al enviar email de notificacion de incidencia PayPal' . SITE_URL, 'Fallo al enviar email de notificacion de incidencia PayPal: <pre>' . print_r($mailHandler, 1) . '</pre>'); } } break; case 'tpv': // los cargos con este tpv vienen ejecutados de base if ($debug) { echo ' -> Ok'; } /* $err = array(); if (Tpv::pay($invest, $err)) { echo 'Cargo sermepa correcto'; $log_text = "Se ha ejecutado el cargo a %s por su aporte de %s mediante TPV (id: %s) al proyecto %s del dia %s"; } else { $txt_errors = implode('; ', $err); echo 'Fallo al ejecutar cargo sermepa: ' . $txt_errors; $log_text = "Ha fallado al ejecutar el cargo a %s por su aporte de %s mediante TPV (id: %s) al proyecto %s del dia %s <br />Se han dado los siguientes errores: $txt_errors"; } * */ break; case 'cash': // los cargos manuales no los modificamos if ($debug) { echo ' Cash, nada que hacer -> Ok'; } break; } if ($debug) { echo '<br />'; } if (!empty($log_text)) { // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate('Cargo ejecutado (cron)', '/admin/invests', \vsprintf($log_text, array(Feed::item('user', $userData->name, $userData->id), Feed::item('money', $invest->amount . ' ¥'), Feed::item('system', $invest->id), Feed::item('project', $project->name, $project->id), Feed::item('system', date('d/m/Y', strtotime($invest->invested)))))); $log->doAdmin(); if ($debug) { echo $log->html . '<br />'; } unset($log); } if ($debug) { echo 'Aporte ' . $invest->id . ' tratado<br />'; } } } if ($debug) { echo '::Fin tratamiento aportes<br />'; } } if ($debug) { echo 'Fin tratamiento Proyecto ' . $project->name . '<hr />'; } } // checkeamos campañas activas //$campaigns = Model\Call::getActive(4); $campaigns = array(); foreach ($campaigns as $campaign) { $errors = array(); // tiene que tener presupuesto if (empty($campaign->amount)) { continue; } // si le quedan cero // -> terminar la campaña exitosamente if ($campaign->rest == 0 && !empty($campaign->amount)) { echo 'La convocatoria ' . $campaign->name . ': '; if ($campaign->checkSuccess($errors)) { if ($campaign->succeed($errors)) { echo 'Ha terminado exitosamente.<br />'; $log = new Feed(); $log->setTarget($campaign->id, 'call'); $log->unique = true; $log->populate('Campaña terminada (cron)', '/admin/calls/' . $campaign->id . '?rest=' . $amount, \vsprintf('La campaña %s ha terminado con exito', array(Feed::item('call', $campaign->name, $campaign->id)))); $log->doAdmin('call'); $log->populate($campaign->name, '/call/' . $campaign->id . '?rest=' . $amount, \vsprintf('La campaña %s ha terminado con éxito', array(Feed::item('call', $campaign->name, $campaign->id))), $call->logo); $log->doPublic('projects'); unset($log); } else { echo 'Ha fallado al marcar exitosa.<br />' . implode('<br />', $errors); } } else { echo 'Le Queda algun proyecto en primera ronda.<br />'; } } } // desbloqueamos if (unlink($block_file)) { echo 'Cron ' . __FUNCTION__ . ' desbloqueado<br />'; } else { echo 'ALERT! Cron ' . __FUNCTION__ . ' no se ha podido desbloquear<br />'; if (file_exists($block_file)) { echo 'El archivo ' . $block_file . ' aun existe!<br />'; } else { echo 'No hay archivo de bloqueo ' . $block_file . '!<br />'; } } // recogemos el buffer para grabar el log $log_file = GOTEO_PATH . 'logs/cron/' . date('Ymd') . '_' . __FUNCTION__ . '.log'; \file_put_contents($log_file, \ob_get_contents(), FILE_APPEND); \chmod($log_file, 0777); }
public static function cleanOld() { // eliminamos los envíos de hace más de dos días Model::query("DELETE FROM mailer_content WHERE active = 0\n AND DATE_FORMAT(from_unixtime(unix_timestamp(now()) - unix_timestamp(datetime)), '%j') > 2"); // eliminamos los destinatarios Model::query("DELETE FROM mailer_send WHERE mailing NOT IN (SELECT id FROM mailer_content)"); }
$mailHandler->massive = true; $errors = array(); if ($mailHandler->send($errors)) { // Envio correcto Model::query("UPDATE mailer_send SET sended = 1, datetime = NOW() WHERE id = '{$user->id}' AND mailing = '{$user->mailing_id}'"); if ($debug) { echo "dbg: Enviado OK a {$user->email}\n"; } } else { // falló al enviar $sql = "UPDATE mailer_send\n SET sended = 0 , error = ? , datetime = NOW()\n WHERE id = '{$user->id}' AND mailing = '{$user->mailing_id}'\n "; Model::query($sql, array(implode(',', $errors))); if ($debug) { echo "dbg: Fallo ERROR a {$user->email} " . implode(',', $errors) . "\n"; } } unset($mailHandler); // tiempo de ejecución $now = microtime(true) - $itime; if ($debug) { echo "dbg: Tiempo de envio: {$now} segundos\n"; } } catch (phpmailerException $e) { die($e->errorMessage()); } //desbloquear usuario if ($debug) { echo "dbg: Desbloqueando registro {$user->id} ({$user->email}) mailing: {$user->mailing_id}\n"; } Model::query("UPDATE mailer_send SET blocked = NULL WHERE id = '{$user->id}' AND mailing = '{$user->mailing_id}'");
public static function process($action = 'list', $id = null, $filters = array()) { // año fiscal $year = Model\User\Donor::$currYear; $year0 = $year; $year1 = $year - 1; $errors = array(); $node = isset($_SESSION['admin_node']) ? $_SESSION['admin_node'] : \GOTEO_NODE; // Valores de filtro $interests = Model\User\Interest::getAll(); $status = Model\Project::status(); $methods = Model\Invest::methods(); $types = array('investor' => 'Cofinanciadores', 'owner' => 'Autores', 'user' => 'Usuarios'); $roles = array('admin' => 'Administrador', 'checker' => 'Revisor', 'translator' => 'Traductor'); // una variable de sesion para mantener los datos de todo esto if (!isset($_SESSION['mailing'])) { $_SESSION['mailing'] = array(); } switch ($action) { case 'edit': $_SESSION['mailing']['receivers'] = array(); $values = array(); $sqlFields = ''; $sqlInner = ''; $sqlFilter = ''; // cargamos los destiantarios //---------------------------- // por tipo de usuario switch ($filters['type']) { case 'investor': $sqlInner .= "INNER JOIN invest\n ON invest.user = user.id\n AND (invest.status = 0 OR invest.status = 1 OR invest.status = 3 OR invest.status = 4)\n INNER JOIN project\n ON project.id = invest.project\n "; $sqlFields .= ", project.name as project"; $sqlFields .= ", project.id as projectId"; break; case 'owner': $sqlInner .= "INNER JOIN project\n ON project.owner = user.id\n "; $sqlFields .= ", project.name as project"; $sqlFields .= ", project.id as projectId"; break; default: break; } $_SESSION['mailing']['filters_txt'] = 'los <strong>' . $types[$filters['type']] . '</strong> '; if (!empty($filters['project']) && !empty($sqlInner)) { $sqlFilter .= " AND project.name LIKE (:project) "; $values[':project'] = '%' . $filters['project'] . '%'; $_SESSION['mailing']['filters_txt'] .= 'de proyectos que su nombre contenga <strong>\'' . $filters['project'] . '\'</strong> '; } elseif (empty($filters['project']) && !empty($sqlInner)) { $_SESSION['mailing']['filters_txt'] .= 'de cualquier proyecto '; } if (isset($filters['status']) && $filters['status'] > -1 && !empty($sqlInner)) { $sqlFilter .= "AND project.status = :status "; $values[':status'] = $filters['status']; $_SESSION['mailing']['filters_txt'] .= 'en estado <strong>' . $status[$filters['status']] . '</strong> '; } elseif ($filters['status'] < 0 && !empty($sqlInner)) { $_SESSION['mailing']['filters_txt'] .= 'en cualquier estado '; } if ($filters['type'] == 'investor') { if (!empty($filters['method']) && !empty($sqlInner)) { $sqlFilter .= "AND invest.method = :method "; $values[':method'] = $filters['method']; $_SESSION['mailing']['filters_txt'] .= 'mediante <strong>' . $methods[$filters['method']] . '</strong> '; } elseif (empty($filters['method']) && !empty($sqlInner)) { $_SESSION['mailing']['filters_txt'] .= 'mediante cualquier metodo '; } } if (!empty($filters['interest'])) { $sqlInner .= "INNER JOIN user_interest\n ON user_interest.user = user.id\n AND user_interest.interest = :interest\n "; $values[':interest'] = $filters['interest']; if ($filters['interest'] == 15) { $_SESSION['mailing']['filters_txt'] .= 'del grupo de testeo '; } else { $_SESSION['mailing']['filters_txt'] .= 'interesados en fin <strong>' . $interests[$filters['interest']] . '</strong> '; } } if (!empty($filters['role'])) { $sqlInner .= "INNER JOIN user_role\n ON user_role.user_id = user.id\n AND user_role.role_id = :role\n "; $values[':role'] = $filters['role']; $_SESSION['mailing']['filters_txt'] .= 'que sean <strong>' . $roles[$filters['role']] . '</strong> '; } if (!empty($filters['name'])) { $sqlFilter .= " AND ( user.name LIKE (:name) OR user.email LIKE (:name) ) "; $values[':name'] = '%' . $filters['name'] . '%'; $_SESSION['mailing']['filters_txt'] .= 'que su nombre o email contenga <strong>\'' . $filters['name'] . '\'</strong> '; } if (!empty($filters['donant'])) { if ($filters['type'] == 'investor') { $sqlFilter .= " AND invest.resign = 1\n AND invest.status IN (1, 3)\n AND invest.charged >= '{$year0}-01-01'\n AND invest.charged < '{$year1}-01-01'\n AND (project.passed IS NOT NULL AND project.passed != '0000-00-00')\n "; $_SESSION['mailing']['filters_txt'] .= 'que haya hecho algun donativo '; } else { Message::Error('Solo se filtran donantes si se envia "A los: Cofinanciadores"'); } } if ($node != \GOTEO_NODE) { $sqlFilter .= " AND user.node = :node"; $values[':node'] = $node; if (!empty($sqlInner)) { $sqlFilter .= " AND project.node = :node"; } } $sql = "SELECT\n user.id as id,\n user.id as user,\n user.name as name,\n user.email as email\n {$sqlFields}\n FROM user\n {$sqlInner}\n WHERE user.active = 1\n {$sqlFilter}\n GROUP BY user.id\n ORDER BY user.name ASC\n "; // die('<pre>'.$sql . '<br />'.print_r($values, 1).'</pre>'); if ($query = Model\User::query($sql, $values)) { foreach ($query->fetchAll(\PDO::FETCH_OBJ) as $receiver) { $_SESSION['mailing']['receivers'][$receiver->id] = $receiver; } } else { Message::Error('Fallo el SQL!!!!! <br />' . $sql . '<pre>' . print_r($values, 1) . '</pre>'); } // si no hay destinatarios, salta a la lista con mensaje de error if (empty($_SESSION['mailing']['receivers'])) { Message::Error('No se han encontrado destinatarios para ' . $_SESSION['mailing']['filters_txt']); throw new Redirection('/admin/mailing/list'); } // si hay, mostramos el formulario de envio return new View('view/admin/index.html.php', array('folder' => 'mailing', 'file' => 'edit', 'filters' => $filters, 'interests' => $interests, 'status' => $status, 'types' => $types, 'roles' => $roles)); break; case 'send': // die(\trace($_POST)); $URL = NODE_ID != GOTEO_NODE ? NODE_URL : SITE_URL; // Enviando contenido recibido a destinatarios recibidos $receivers = array(); $subject = $_POST['subject']; $templateId = !empty($_POST['template']) ? $_POST['template'] : 11; $content = \str_replace('%SITEURL%', $URL, $_POST['content']); // quito usuarios desmarcados foreach ($_SESSION['mailing']['receivers'] as $usr => $userData) { $errors = array(); $campo = 'receiver_' . $usr; if (!isset($_POST[$campo])) { $_SESSION['mailing']['receivers'][$usr]->ok = null; } else { $receivers[] = $userData; } } // montamos el mailing // - se crea un registro de tabla mail $sql = "INSERT INTO mail (id, email, html, template, node) VALUES ('', :email, :html, :template, :node)"; $values = array(':email' => 'any', ':html' => $content, ':template' => $templateId, ':node' => $node); $query = \Goteo\Core\Model::query($sql, $values); $mailId = \Goteo\Core\Model::insertId(); // - se usa el metodo initializeSending para grabar el envío (parametro para autoactivar) // - initiateSending ($mailId, $subject, $receivers, $autoactive = 0) if (\Goteo\Library\Sender::initiateSending($mailId, $subject, $receivers, 1)) { $ok = true; // Evento Feed $log = new Feed(); $log->populate('comunicación masiva a usuarios (admin)', '/admin/mailing', \vsprintf("El admin %s ha iniciado una %s a %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', 'Comunicacion masiva'), $_SESSION['mailing']['filters_txt']))); $log->doAdmin('admin'); unset($log); } else { $ok = false; // Evento Feed $log = new Feed(); $log->populate('comunicación masiva a usuarios (admin)', '/admin/mailing', \vsprintf("El admin %s le ha %s una %s a %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', 'fallado'), Feed::item('relevant', 'Comunicacion masiva'), $_SESSION['mailing']['filters_txt']))); $log->doAdmin('admin'); unset($log); } return new View('view/admin/index.html.php', array('folder' => 'mailing', 'file' => 'send', 'subject' => $subject, 'interests' => $interests, 'status' => $status, 'methods' => $methods, 'types' => $types, 'roles' => $roles, 'users' => $receivers, 'ok' => $ok)); break; } return new View('view/admin/index.html.php', array('folder' => 'mailing', 'file' => 'list', 'interests' => $interests, 'status' => $status, 'methods' => $methods, 'types' => $types, 'roles' => $roles, 'filters' => $filters)); }
public static function process($action = 'list', $id = null, $filters = array()) { $node = isset($_SESSION['admin_node']) ? $_SESSION['admin_node'] : \GOTEO_NODE; // métodos de pago $methods = Model\Invest::methods(); // estados del proyecto $status = Model\Project::status(); // estados de aporte $investStatus = Model\Invest::status(); // listado de proyectos $projects = Model\Invest::projects(false, $node); // usuarios cofinanciadores $users = Model\Invest::users(true); // campañas que tienen aportes $calls = Model\Invest::calls(); // extras $types = array('donative' => 'Solo los donativos', 'anonymous' => 'Solo los anónimos', 'manual' => 'Solo los manuales', 'campaign' => 'Solo con riego'); if ($action == 'csv') { $invest = Model\Invest::getPreapproval($id); foreach ($invest as $value) { $csv[] = array($value->id, $value->amount); } $fileName = "axes_" . date("YmdHis") . ".csv"; header("Content-Disposition: attachment; filename=\"{$filename}\""); header("Content-type: application/octet-stream"); header("Pragma: no-cache"); header("Expires: 0"); $fp = fopen('php://output', 'w'); foreach ($csv as $fields) { fputcsv($fp, $fields); } fclose($fp); exit; } if ($action == 'dopay') { $query = \Goteo\Core\Model::query("\n SELECT *\n FROM invest\n WHERE invest.project = ?\n AND (invest.status = 0\n OR (invest.method = 'tpv'\n AND invest.status = 1\n )\n OR (invest.method = 'cash'\n AND invest.status = 1\n )\n )\n AND (invest.campaign IS NULL OR invest.campaign = 0)\n ", array($id)); $invests = $query->fetchAll(\PDO::FETCH_CLASS, '\\Goteo\\Model\\Invest'); foreach ($invests as $key => $invest) { if ($invest->setPayment(date("YmdHis"))) { $invest->setStatus(1); Model\Invest::setDetail($invest->id, 'executed', 'Preapproval has been executed, has initiated the chained payment. Process cron / execute'); if ($invest->issue) { Model\Invest::unsetIssue($invest->id); Model\Invest::setDetail($invest->id, 'issue-solved', 'The incidence has been resolved upon success by the automatic process'); } } } Message::Info("処理しました"); throw new Redirection('/admin/projects/list'); exit; } // detalles del aporte if ($action == 'details') { $invest = Model\Invest::get($id); $project = Model\Project::get($invest->project); $userData = Model\User::get($invest->user); if (!empty($invest->droped)) { $droped = Model\Invest::get($invest->droped); } else { $droped = null; } if ($project->node != $node) { throw new Redirection('/admin/invests'); } return new View('view/admin/index.html.php', array('folder' => 'invests', 'file' => 'details', 'invest' => $invest, 'project' => $project, 'user' => $userData, 'status' => $status, 'investStatus' => $investStatus, 'droped' => $droped, 'calls' => $calls)); } // listado de aportes if ($filters['filtered'] == 'yes') { if (!empty($filters['calls'])) { $filters['types'] = ''; } $list = Model\Invest::getList($filters, $node, 999); } else { $list = array(); } $viewData = array('folder' => 'invests', 'file' => 'list', 'list' => $list, 'filters' => $filters, 'projects' => $projects, 'users' => $users, 'calls' => $calls, 'methods' => $methods, 'types' => $types, 'investStatus' => $investStatus); return new View('view/admin/index.html.php', $viewData); }
/** * Metodo para grabar eventos * * Los datos del evento estan en el objeto * * * @param array $errors * * @access public * @return boolean true | false as success * */ public function add() { if (empty($this->html)) { @mail(\GOTEO_MAIL, 'Evento feed sin html: ' . SITE_URL, "Feed sin contenido html<hr /><pre>" . print_r($this, 1) . "</pre>"); return false; } // we dont want to show the actions made by root user if ($this->scope == 'public' && $_SESSION['user']->id == 'root') { return false; } // primero, verificar si es unique, no duplicarlo if ($this->unique === true) { $query = Model::query("SELECT id FROM feed WHERE url = :url AND scope = :scope AND type = :type", array(':url' => $this->url, ':scope' => $this->scope, ':type' => $this->type)); if ($query->fetchColumn(0) != false) { $this->unique_issue = true; return true; } } try { $values = array(':title' => $this->title, ':url' => $this->url, ':image' => $this->image, ':scope' => $this->scope, ':type' => $this->type, ':html' => $this->html, ':target_type' => $this->target_type, ':target_id' => $this->target_id); $sql = "INSERT INTO feed\n (id, title, url, scope, type, html, image, target_type, target_id)\n VALUES\n ('', :title, :url, :scope, :type, :html, :image, :target_type, :target_id)\n "; if (Model::query($sql, $values)) { return true; } else { @mail(\GOTEO_MAIL, 'Fallo al hacer evento feed: ' . SITE_URL, "Ha fallado Feed<br /> {$sql} con <pre>" . print_r($values, 1) . "</pre><hr /><pre>" . print_r($this, 1) . "</pre>"); return false; } } catch (\PDOException $e) { @mail(\GOTEO_MAIL, 'PDO Exception evento feed: ' . SITE_URL, "Ha fallado Feed PDO Exception<br /> {$sql} con " . $e->getMessage() . "<hr /><pre>" . print_r($this, 1) . "</pre>"); return false; } }
public static function wordCount($section, $table, $fields = array(), &$total = 0) { $count = 0; $sqlFilter = ''; switch ($section) { case 'texts': // todos son de la tabla purpose, $table nos indica la agrupación // y hay que filtrar la columna group $sqlFilter = " WHERE `group` = '{$table}'"; $table = 'purpose'; $fields = array('purpose'); break; case 'pages': // table nos indica si es la de descripciones o la de contenido, // en la de contenido hay que filtrar nodo goteo y español if ($table == 'page_node') { $sqlFilter = " WHERE node = 'goteo' AND lang = 'es'"; } break; case 'contents': case 'home': // ojo! post es solo del blog 1 (goteo) if ($table == 'post') { $sqlFilter = " WHERE blog = '1'"; } break; } // seleccionar toda la tabla, $sql = "SELECT " . implode(', ', $fields) . " FROM {$table}{$sqlFilter}"; $query = Model::query($sql, $values); foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $row) { // para cada campo foreach ($fields as $field) { // contar palabras (ojo! hay que quitar los tags html) $count += count(explode(' ', \strip_tags($row[$field]))); } } $total += $count; return $count; }
/** * Realiza el envio masivo a participantees o cofinanciadores * * @param type $option 'messegers' || 'rewards' * @param type $project Instancia del proyecto de trabajo * @return boolean */ public static function process_mailing($option, $project) { $who = array(); // verificar que hay mensaje if (empty($_POST['message'])) { Message::Error(Text::get('dashboard-investors-mail-text-required')); return false; } else { $msg_content = nl2br(\strip_tags($_POST['message'])); } // si a todos los participantes if ($option == 'messegers' && !empty($_POST['msg_all'])) { // a todos los participantes foreach (Model\Message::getMessegers($project->id) as $messeger => $msgData) { if ($messeger == $project->owner) { continue; } $who[$messeger] = $messeger; // unset($msgData); // los datos del mensaje del participante no se usan } } elseif ($option == 'rewards' && !empty($_POST['msg_all'])) { // a todos los cofinanciadores foreach (Model\Invest::investors($project->id, false, true) as $user => $investor) { // no duplicar $who[$investor->user] = $investor->user; } } elseif (!empty($_POST['msg_user'])) { // a usuario individual $who[$_POST['msg_user']] = $_POST['msg_user']; } elseif ($option == 'rewards') { $msg_rewards = array(); // estos son msg_reward-[rewardId], a un grupo de recompensa foreach ($_POST as $key => $value) { $parts = explode('-', $key); if ($parts[0] == 'msg_reward' && $value == 1) { $msg_rewards[] = $parts[1]; } } // para cada recompensa foreach ($msg_rewards as $reward) { foreach (Model\Invest::choosed($reward) as $user) { $who[$user] = $user; } } } // no hay destinatarios if (count($who) == 0) { Message::Error(Text::get('dashboard-investors-mail-nowho')); return false; } // obtener contenido // segun destinatarios $allsome = explode('/', Text::get('regular-allsome')); $enviandoa = !empty($_POST['msg_all']) ? $allsome[0] : $allsome[1]; if ($option == 'messegers') { Message::Info(Text::get('dashboard-messegers-mail-sendto', $enviandoa)); } else { Message::Info(Text::get('dashboard-investors-mail-sendto', $enviandoa)); } // Obtenemos la plantilla para asunto y contenido $template = Template::get(2); // Sustituimos los datos if (!empty($_POST['subject'])) { $subject = $_POST['subject']; } else { $subject = str_replace('%PROJECTNAME%', $project->name, $template->title); } $remite = $project->name . ' ' . Text::get('regular-from') . ' '; $remite .= NODE_ID != GOTEO_NODE ? NODE_NAME : GOTEO_MAIL_NAME; $search = array('%MESSAGE%', '%PROJECTNAME%', '%PROJECTURL%', '%OWNERURL%', '%OWNERNAME%'); $replace = array($msg_content, $project->name, SITE_URL . "/project/" . $project->id, SITE_URL . "/user/profile/" . $project->owner, $project->user->name); $content = \str_replace($search, $replace, $template->text); // para usar el proceso Sender: // - $who debe ser compatible con el formato $receivers // (falta nombre e email), sacarlo con getMini $receivers = array(); foreach ($who as $userId) { $user = Model\User::getMini($userId); $user->user = $user->id; $receivers[] = $user; } // - en la plantilla hay que cambiar %NAME% por %USERNAME% para que sender reemplace // - // - se crea un registro de tabla mail $sql = "INSERT INTO mail (id, email, html, template, node) VALUES ('', :email, :html, :template, :node)"; $values = array(':email' => 'any', ':html' => $content, ':template' => $template->id, ':node' => \GOTEO_NODE); $query = \Goteo\Core\Model::query($sql, $values); $mailId = \Goteo\Core\Model::insertId(); // - se usa el metodo initializeSending para grabar el envío (parametro para autoactivar) // , también metemos el reply y repplyName (remitente) en la instancia de envío if (\Goteo\Library\Sender::initiateSending($mailId, $subject, $receivers, 1, $project->user->email, $remite)) { Message::Info(Text::get('dashboard-investors-mail-sended', 'la cola de envíos')); // cambiar este texto } else { Message::Error(Text::get('dashboard-investors-mail-fail', 'la cola de envíos')); // cambiar este texto } return true; }
/** * PAra actualizar solamente el contenido * @param <type> $errors * @return <type> */ public function update($id, $lang, $node, $name, $description, $content, &$errors = array()) { try { $values = array(':page' => $id, ':lang' => $lang, ':node' => $node, ':name' => $name, ':description' => $description, ':content' => $content); $sql = "REPLACE INTO page_node\n (page, node, lang, name, description, content)\n VALUES\n (:page, :node, :lang, :name, :description, :content)\n "; if (Model::query($sql, $values)) { return true; } else { $errors[] = Text::_("Ha fallado ") . $sql . Text::_('con') . " <pre>" . print_r($values, 1) . "</pre>"; return false; } } catch (\PDOException $e) { $errors[] = Text::_('Error sql al grabar el contenido de la pagina. ') . $e->getMessage(); return false; } }