public function project($id) { $project = Project::getMedium($id, LANG); if (!$project instanceof Project) { throw new Redirection('/', Redirection::TEMPORARY); } return new View('view/widget/project.html.php', array('project' => $project, 'global' => true)); throw new Redirection('/fail', Redirection::TEMPORARY); }
public function index() { if (isset($_GET['error'])) { throw new \Goteo\Core\Error('418', Text::html('fatal-error-teapot')); } // orden de los elementos en portada $order = Home::getAll(); // si estamos en easy mode, quitamos el feed if (defined('GOTEO_EASY') && \GOTEO_EASY === true && isset($order['feed'])) { unset($order['feed']); } // entradas de blog if (isset($order['posts'])) { // entradas en portada $posts = Post::getAll(); } // Proyectos destacados if (isset($order['promotes'])) { $promotes = Promote::getAll(true); foreach ($promotes as $key => &$promo) { try { $promo->projectData = Project::getMedium($promo->project, LANG); } catch (\Goteo\Core\Error $e) { unset($promotes[$key]); } } } // actividad reciente if (isset($order['feed'])) { $feed = array(); $feed['goteo'] = Feed::getAll('goteo', 'public', 15); $feed['projects'] = Feed::getAll('projects', 'public', 15); $feed['community'] = Feed::getAll('community', 'public', 15); } // Banners siempre /* $banners = Banner::getAll(true); foreach ($banners as $id => &$banner) { if (!empty($banner->project)) { try { $banner->project = Project::get($banner->project, LANG); } catch (\Goteo\Core\Error $e) { unset($banners[$id]); } } }*/ $template = VIEW_PATH . '/index.html.php'; return new View($template, array('banners' => $banners, 'posts' => $posts, 'promotes' => $promotes, 'order' => $order)); }
public static function getAll($activeonly = false, $node = \GOTEO_NODE) { // estados $status = Project::status(); $banners = array(); $sqlFilter = $activeonly ? " AND banner.active = 1" : ''; $query = static::query("\n SELECT\n banner.id as id,\n banner.node as node,\n banner.project as project,\n project.name as name,\n IFNULL(banner_lang.title, banner.title) as title,\n IFNULL(banner_lang.description, banner.description) as description,\n banner.url as url,\n project.status as status,\n banner.image as image,\n banner.order as `order`,\n banner.active as `active`\n FROM banner\n LEFT JOIN project\n ON project.id = banner.project\n LEFT JOIN banner_lang\n ON banner_lang.id = banner.id\n AND banner_lang.lang = :lang\n WHERE banner.node = :node\n {$sqlFilter}\n ORDER BY `order` ASC\n ", array(':node' => $node, ':lang' => \LANG)); foreach ($query->fetchAll(\PDO::FETCH_CLASS, __CLASS__) as $banner) { $banner->image = !empty($banner->image) ? Image::get($banner->image) : null; $banner->status = $status[$banner->status]; $banners[] = $banner; } return $banners; }
public static function getAll($activeonly = false, $node = \GOTEO_NODE) { // estados $status = Project::status(); $promos = array(); $sqlFilter = $activeonly ? " AND promote.active = 1" : ''; $query = static::query("\n SELECT\n promote.id as id,\n promote.project as project,\n project.name as name,\n project.status as status,\n IFNULL(promote_lang.title, promote.title) as title,\n IFNULL(promote_lang.description, promote.description) as description,\n promote.order as `order`,\n promote.active as `active`\n FROM promote\n LEFT JOIN promote_lang\n ON promote_lang.id = promote.id\n AND promote_lang.lang = :lang\n INNER JOIN project\n ON project.id = promote.project\n WHERE promote.node = :node\n {$sqlFilter}\n ORDER BY `order` ASC, title ASC\n ", array(':node' => $node, ':lang' => \LANG)); foreach ($query->fetchAll(\PDO::FETCH_CLASS, __CLASS__) as $promo) { $promo->description = Text::recorta($promo->description, 100, false); $promo->status = $status[$promo->status]; $promos[] = $promo; } return $promos; }
public static function projList($user) { $lists = array(); // mis proyectos $projects = Model\Project::ofmine($user->id); if (!empty($projects)) { $lists['my_projects'] = Listing::get($projects); } // proyectos que cofinancio $invested = Model\User::invested($user->id, false); if (!empty($invested)) { $lists['invest_on'] = Listing::get($invested); } return $lists; }
public static function getAll($position = 'home', $node = \GOTEO_NODE) { if (!in_array($position, array('home', 'footer'))) { $position = 'home'; } $list = array(); $values = array(':lang' => \LANG); if ($node == \GOTEO_NODE || empty($node)) { // portada goteo, sacamos todas las de blogs tipo nodo // que esten marcadas en la tabla post $sqlFilter = " WHERE post.{$position} = 1\n AND post.publish = 1\n "; $sqlField = "post.order as `order`,"; } else { // portada nodo, igualmente las entradas de blogs tipo nodo // perosolo la que esten en la tabla de entradas en portada de ese nodo $sqlFilter = " WHERE post.id IN (SELECT post FROM post_node WHERE node = :node)\n AND post.publish = 1\n "; $values[':node'] = $node; $sqlField = "(SELECT `order` FROM post_node WHERE node = :node AND post = post.id) as `order`,"; } $sql = "\n SELECT\n post.id as id,\n post.blog as blog,\n IFNULL(post_lang.title, post.title) as title,\n IFNULL(post_lang.text, post.text) as `text`,\n post.image as `image`,\n post.media as `media`,\n {$sqlField}\n DATE_FORMAT(post.date, '%d-%m-%Y') as date,\n DATE_FORMAT(post.date, '%d | %m | %Y') as fecha,\n post.publish as publish,\n post.author as author,\n post.home as home,\n post.footer as footer,\n blog.type as owner_type,\n blog.owner as owner_id\n FROM post\n INNER JOIN blog\n ON blog.id = post.blog\n LEFT JOIN post_lang\n ON post_lang.id = post.id\n AND post_lang.lang = :lang\n {$sqlFilter}\n ORDER BY `order` ASC, title ASC\n "; $query = static::query($sql, $values); foreach ($query->fetchAll(\PDO::FETCH_CLASS, __CLASS__) as $post) { // galeria $post->gallery = Image::getAll($post->id, 'post'); $post->image = $post->gallery[0]; $post->media = new Media($post->media); $post->type = $post->home == 1 ? 'home' : 'footer'; // datos del autor switch ($post->owner_type) { case 'project': $proj_blog = Project::getMini($post->owner_id); $post->author = $proj_blog->owner; $post->user = $proj_blog->user; $post->owner_name = $proj_blog->name; $sql = "UPDATE post SET author = '.{$proj_blog->owner}.' WHERE post.id = ?"; self::query($sql, array($post->id)); break; case 'node': $post->user = User::getMini($post->author); // (Nodesys) break; } $list[$post->id] = $post; } return $list; }
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'); // 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); }
/** * Verificación de proyecto de trabajo * * @param object $user instancia Model\User del convocador * @param string $action por si es 'select' * @return array(project, projects) */ public static function verifyProject($user, $action) { $projects = Model\Project::ofmine($user->id); // sus proyectos // si no tiene, no debería estar aquí if (empty($projects) || !is_array($projects)) { return array(null, null); } // comprobamos que tenga los permisos para editar y borrar foreach ($projects as $proj) { // comprueba que puede editar sus proyectos if (!ACL::check('/project/edit/' . $proj->id)) { ACL::allow('/project/edit/' . $proj->id . '/', '*', 'user', $user); } // y borrarlos if (!ACL::check('/project/delete/' . $proj->id)) { ACL::allow('/project/delete/' . $proj->id . '/', '*', 'user', $user); } } // si está seleccionando otro proyecto if ($action == 'select' && !empty($_POST['project'])) { $project = Model\Project::get($_POST['project']); } elseif (!empty($_SESSION['project']->id)) { // mantener los datos del proyecto de trabajo $project = Model\Project::get($_SESSION['project']->id); } // si aun no tiene proyecto de trabajo, coge el primero if (empty($project)) { $project = $projects[0]; } // tiene que volver con un proyecto de trabajo if ($project instanceof \Goteo\Model\Project) { $_SESSION['project'] = $project; // lo guardamos en sesión para la próxima verificación } else { Message::Error('No se puede trabajar con el proyecto seleccionado, contacta con nosotros'); $project = null; } // devolvemos lista de proyectos y proyecto de trabajo return array($project, $projects); }
/** * * @param type mixed $id Identificador * @return type object Objeto */ public function __construct($id, $all_avatars = true, $with_title = true) { if ($this->project = Project::get($id)) { $this->show_title = $with_title; $this->investors = $this->project->agregateInvestors(); $avatars = array(); foreach ($this->investors as $i) { if ($i->avatar->id != 1 || $all_avatars) { $avatars[$i->user] = $i->amount; } } $this->avatars = self::pondera($avatars, $this->max_multiplier); //arsort($this->avatars); $keys = array_keys($this->avatars); shuffle($keys); $this->avatars = array_merge(array_flip($keys), $this->avatars); //print_r($this->project);die; } else { return false; } }
/** * Metodo para sacar las que hay en proyectos * @return array strings */ public static function getList() { $results = array(); // $sql = "SELECT distinct(project_location) as location // FROM project // WHERE status > 2 // 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'); // } $_locations = Project::yokohamaLocation(); foreach ($_locations as $_area) { $results[md5($_area)] = $_area; } return $results; }
public static function pay($invest, &$errors = array()) { if (\GOTEO_FREE) { $errors[] = Text::_('Bank not implemented. Contact us for development services or make it work somehow'); return false; } try { $project = Project::getMini($invest->project); // preparo codigo y cantidad $token = $invest->id . rand(0, 9) . rand(0, 9) . rand(0, 9) . rand(0, 9); $amount = $invest->amount * 100; // Guardar el codigo de preaproval en el registro de aporte (para confirmar o cancelar) $invest->setPreapproval($token); // mandarlo al tpv $urlTPV = TPV_REDIRECT_URL; $data = ''; $MsgStr = ''; foreach ($datos as $n => $v) { $data .= '<input name="' . $n . '" type="hidden" value="' . $v . '" />'; $MsgStr .= "{$n}:'{$v}'; "; } $conf = array('mode' => 0600, 'timeFormat' => '%X %x'); $logger =& \Log::singleton('file', 'logs/' . date('Ymd') . '_invest.log', 'caller', $conf); $logger->log('##### TPV [' . $invest->id . '] ' . date('d/m/Y') . ' User:'******'user']->id . '#####'); $logger->log("Charge request: {$MsgStr}"); $logger->close(); Invest::setDetail($invest->id, 'tpv-conection', 'Ha iniciado la comunicacion con el tpv, operacion numero ' . $token . '. Proceso libary/tpv::pay'); echo '<html><head><title>Goteo.org</title></head><body><form action="' . $urlTPV . '" method="post" id="form_tpv" enctype="application/x-www-form-urlencoded">' . $data . '</form><script type="text/javascript">document.getElementById("form_tpv").submit();</script></body></html>'; return true; } catch (Exception $ex) { Invest::setDetail($invest->id, 'tpv-conection-fail', 'Ha fallado la comunicacion con el tpv. Proceso libary/tpv::pay'); $errors[] = Text::_('Error fatal en la comunicacion con el TPV, se ha reportado la incidencia. Disculpe las molestias.'); @mail(\GOTEO_FAIL_MAIL, 'Error fatal en comunicacion TPV Sermepa', 'ERROR en ' . __FUNCTION__ . '<br />' . $ex->getMessage()); return false; } }
public static function getMesseged($user, $publicOnly = true) { $projects = array(); $sql = "SELECT project.id\n FROM project\n INNER JOIN message\n ON project.id = message.project\n AND message.user = ?\n WHERE project.status < 7\n "; if ($publicOnly) { $sql .= "AND project.status >= 3\n "; } $sql .= "GROUP BY project.id\n ORDER BY name ASC\n "; $query = self::query($sql, array($user)); foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $proj) { $projects[] = \Goteo\Model\Project::getMedium($proj->id); } return $projects; }
public static function process($action = 'list', $id = null, $filters = array()) { $errors = array(); // reubicando aporte, if ($action == 'move') { // el aporte original $original = Model\Invest::get($id); $userData = Model\User::getMini($original->user); $projectData = Model\Project::getMini($original->project); //el original tiene que ser de tpv o cash y estar como 'cargo ejecutado' if ($original->method == 'paypal' || $original->status != 1) { Message::Error('No se puede reubicar este aporte!'); throw new Redirection('/admin/accounts'); } // generar aporte manual y caducar el original if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['move'])) { // si falta proyecto, error $projectNew = $_POST['project']; // @TODO a saber si le toca dinero de alguna convocatoria $campaign = null; $invest = new Model\Invest(array('amount' => $original->amount, 'user' => $original->user, 'project' => $projectNew, 'account' => $userData->email, 'method' => 'cash', 'status' => '1', 'invested' => date('Y-m-d'), 'charged' => $original->charged, 'anonymous' => $original->anonymous, 'resign' => $original->resign, 'admin' => $_SESSION['user']->id, 'campaign' => $campaign)); //@TODO si el proyecto seleccionado if ($invest->save($errors)) { //recompensas que le tocan (si no era resign) if (!$original->resign) { // sacar recompensas $rewards = Model\Project\Reward::getAll($projectNew, 'individual'); foreach ($rewards as $rewId => $rewData) { $invest->setReward($rewId); //asignar } } // cambio estado del aporte original a 'Reubicado' (no aparece en cofinanciadores) // si tuviera que aparecer lo marcaríamos como caducado if ($original->setStatus('5')) { // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('Aporte reubicado', '/admin/accounts', \vsprintf("%s ha aportado %s al proyecto %s en nombre de %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('money', $_POST['amount'] . ' €'), Feed::item('project', $projectData->name, $projectData->id), Feed::item('user', $userData->name, $userData->id)))); $log->doAdmin('money'); unset($log); Message::Info('Aporte reubicado correctamente'); throw new Redirection('/admin/accounts'); } else { $errors[] = 'A fallado al cambiar el estado del aporte original (' . $original->id . ')'; } } else { $errors[] = 'Ha fallado algo al reubicar el aporte'; } } $viewData = array('folder' => 'accounts', 'file' => 'move', 'original' => $original, 'user' => $userData, 'project' => $projectData); return new View('view/admin/index.html.php', $viewData); // fin de la historia dereubicar } // cambiando estado del aporte aporte, if ($action == 'update') { // el aporte original $invest = Model\Invest::get($id); if (!$invest instanceof Model\Invest) { Message::Error('No tenemos registro del aporte ' . $id); throw new Redirection('/admin/accounts'); } $status = Model\Invest::status(); $new = isset($_POST['status']) ? $_POST['status'] : null; if ($invest->issue && $_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['update']) && $_POST['resolve'] == 1) { Model\Invest::unsetIssue($id); Model\Invest::setDetail($id, 'issue-solved', 'La incidencia se ha dado por resuelta por el usuario ' . $_SESSION['user']->name); Message::Info('La incidencia se ha dado por resuelta'); } if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['update']) && isset($new) && isset($status[$new])) { if ($new != $invest->status) { if (Model\Invest::query("UPDATE invest SET status=:status WHERE id=:id", array(':id' => $id, ':status' => $new))) { Model\Invest::setDetail($id, 'status-change' . rand(0, 9999), 'El admin ' . $_SESSION['user']->name . ' ha cambiado el estado del apote a ' . $status[$new]); Message::Info('Se ha actualizado el estado del aporte'); } else { Message::Error('Ha fallado al actualizar el estado del aporte'); } } else { Message::Error('No se ha cambiado el estado'); } throw new Redirection('/admin/accounts/details/' . $id); } return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'update', 'invest' => $invest, 'status' => $status)); // fin de la historia actualizar estado } // resolviendo incidencias if ($action == 'solve') { // el aporte original $invest = Model\Invest::get($id); if (!$invest instanceof Model\Invest) { Message::Error('No tenemos registro del aporte ' . $id); throw new Redirection('/admin/accounts'); } $projectData = Model\Project::getMini($invest->project); $errors = array(); // primero cancelar switch ($invest->method) { case 'paypal': $err = array(); if (Paypal::cancelPreapproval($invest, $err)) { $errors[] = 'Preaproval paypal cancelado.'; $log_text = "El admin %s ha cancelado aporte y preapproval de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s"; } else { $txt_errors = implode('; ', $err); $errors[] = 'Fallo al cancelar el preapproval en paypal: ' . $txt_errors; $log_text = "El admin %s 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}"; if ($invest->cancel()) { $errors[] = 'Aporte cancelado'; } else { $errors[] = 'Fallo al cancelar el aporte'; } } break; case 'tpv': $err = array(); if (Tpv::cancelPreapproval($invest, $err)) { $txt_errors = implode('; ', $err); $errors[] = 'Aporte cancelado correctamente. ' . $txt_errors; $log_text = "El admin %s ha anulado el cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s"; } else { $txt_errors = implode('; ', $err); $errors[] = 'Fallo en la operación. ' . $txt_errors; $log_text = "El admin %s ha fallado al solicitar la cancelación del 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()) { $log_text = "El admin %s ha cancelado aporte manual de %s de %s (id: %s) al proyecto %s del dia %s"; $errors[] = 'Aporte cancelado'; } else { $log_text = "El admin %s ha fallado al cancelar el aporte manual de %s de %s (id: %s) al proyecto %s del dia %s. "; $errors[] = 'Fallo al cancelar el aporte'; } break; } // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('Cargo cancelado manualmente (admin)', '/admin/accounts', \vsprintf($log_text, array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('user', $userData->name, $userData->id), Feed::item('money', $invest->amount . ' €'), Feed::item('system', $invest->id), Feed::item('project', $projectData->name, $projectData->id), Feed::item('system', date('d/m/Y', strtotime($invest->invested)))))); $log->doAdmin(); unset($log); // luego resolver if ($invest->solve($errors)) { // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('Incidencia resuelta (admin)', '/admin/accounts', \vsprintf("El admin %s ha dado por resuelta la incidencia con el botón \"Nos han hecho la transferencia\" para el aporte %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('system', $id, 'accounts/details/' . $id)))); $log->doAdmin('admin'); unset($log); Message::Info('La incidencia se ha dado por resuelta, el aporte se ha pasado a manual y cobrado'); throw new Redirection('/admin/accounts'); } else { // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('Fallo al resolver incidencia (admin)', '/admin/accounts', \vsprintf("Al admin %s le ha fallado el botón \"Nos han hecho la transferencia\" para el aporte %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('system', $id, 'accounts/details/' . $id)))); $log->doAdmin('admin'); unset($log); Message::Error('Ha fallado al resolver la incidencia: ' . implode(',', $errors)); throw new Redirection('/admin/accounts/details/' . $id); } } // aportes manuales, cargamos la lista completa de usuarios, proyectos y campañas if ($action == 'add') { // listado de proyectos en campaña $projects = Model\Project::active(false, true); // usuarios $users = Model\User::getAllMini(); // campañas //@CALLSYS $calls = array(); // generar aporte manual if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['add'])) { $userData = Model\User::getMini($_POST['user']); $projectData = Model\Project::getMini($_POST['project']); $invest = new Model\Invest(array('amount' => $_POST['amount'], 'user' => $userData->id, 'project' => $projectData->id, 'account' => $userData->email, 'method' => 'cash', 'status' => '1', 'invested' => date('Y-m-d'), 'charged' => date('Y-m-d'), 'anonymous' => $_POST['anonymous'], 'resign' => 1, 'admin' => $_SESSION['user']->id)); //@CALLSYS if ($invest->save($errors)) { // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('Aporte manual (admin)', '/admin/accounts', \vsprintf("%s ha aportado %s al proyecto %s en nombre de %s", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('money', $_POST['amount'] . ' €'), Feed::item('project', $projectData->name, $projectData->id), Feed::item('user', $userData->name, $userData->id)))); $log->doAdmin('money'); unset($log); Model\Invest::setDetail($invest->id, 'admin-created', 'Este aporte ha sido creado manualmente por el admin ' . $_SESSION['user']->name); Message::Info('Aporte manual creado correctamente, seleccionar recompensa y dirección de entrega.'); throw new Redirection('/admin/rewards/edit/' . $invest->id); } else { $errors[] = 'Ha fallado algo al crear el aporte manual'; } } $viewData = array('folder' => 'accounts', 'file' => 'add', 'autocomplete' => true, 'users' => $users, 'projects' => $projects, 'calls' => $calls); return new View('view/admin/index.html.php', $viewData); // fin de la historia } // Informe de la financiación de un proyecto if ($action == 'report') { // estados de aporte $project = Model\Project::get($id); if (!$project instanceof Model\Project) { Message::Error('Instancia de proyecto no valida'); throw new Redirection('/admin/accounts'); } $invests = Model\Invest::getAll($id); $project->investors = Model\Invest::investors($id, false, true); $users = $project->agregateInvestors(); $investStatus = Model\Invest::status(); // Datos para el informe de transacciones correctas $Data = Model\Invest::getReportData($project->id, $project->status, $project->round, $project->passed); return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'report', 'invests' => $invests, 'project' => $project, 'status' => $status, 'users' => $users, 'investStatus' => $investStatus, 'Data' => $Data)); } // cancelar aporte antes de ejecución, solo aportes no cargados if ($action == 'cancel') { $invest = Model\Invest::get($id); if (!$invest instanceof Model\Invest) { Message::Error('No tenemos objeto para el aporte ' . $id); throw new Redirection('/admin/accounts'); } $project = Model\Project::get($invest->project); $userData = Model\User::get($invest->user); if ($project->status > 3 && $project->status < 6) { $errors[] = 'No debería poderse cancelar un aporte cuando el proyecto ya está financiado. Si es imprescindible, hacerlo desde el panel de paypal o tpv'; break; } switch ($invest->method) { case 'paypal': $err = array(); if (Paypal::cancelPreapproval($invest, $err)) { $errors[] = 'Preaproval paypal cancelado.'; $log_text = "El admin %s ha cancelado aporte y preapproval de %s de %s mediante PayPal (id: %s) al proyecto %s del dia %s"; } else { $txt_errors = implode('; ', $err); $errors[] = 'Fallo al cancelar el preapproval en paypal: ' . $txt_errors; $log_text = "El admin %s 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}"; if ($invest->cancel()) { $errors[] = 'Aporte cancelado'; } else { $errors[] = 'Fallo al cancelar el aporte'; } } break; case 'tpv': $err = array(); if (Tpv::cancelPreapproval($invest, $err)) { $txt_errors = implode('; ', $err); $errors[] = 'Aporte cancelado correctamente. ' . $txt_errors; $log_text = "El admin %s ha anulado el cargo tpv de %s de %s mediante TPV (id: %s) al proyecto %s del dia %s"; } else { $txt_errors = implode('; ', $err); $errors[] = 'Fallo en la operación. ' . $txt_errors; $log_text = "El admin %s ha fallado al solicitar la cancelación del 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()) { $log_text = "El admin %s ha cancelado aporte manual de %s de %s (id: %s) al proyecto %s del dia %s"; $errors[] = 'Aporte cancelado'; } else { $log_text = "El admin %s ha fallado al cancelar el aporte manual de %s de %s (id: %s) al proyecto %s del dia %s. "; $errors[] = 'Fallo al cancelar el aporte'; } break; } // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate('Cargo cancelado manualmente (admin)', '/admin/accounts', \vsprintf($log_text, array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), 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(); Model\Invest::setDetail($invest->id, 'manually-canceled', $log->html); unset($log); } // ejecutar cargo ahora!!, solo aportes no ejecutados // si esta pendiente, ejecutar el cargo ahora (como si fuera final de ronda), deja pendiente el pago secundario if ($action == 'execute' && $invest->status == 0) { $invest = Model\Invest::get($id); if (!$invest instanceof Model\Invest) { Message::Error('No tenemos objeto para el aporte ' . $id); throw new Redirection('/admin/accounts'); } $project = Model\Project::get($invest->project); $userData = Model\User::get($invest->user); switch ($invest->method) { case 'paypal': // a ver si tiene cuenta paypal $projectAccount = Model\Project\Account::get($invest->project); if (empty($projectAccount->paypal)) { // Erroraco! $errors[] = 'El proyecto no tiene cuenta paypal!!, ponersela en la seccion Contrato del dashboard del autor'; $log_text = null; // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate('proyecto sin cuenta paypal (admin)', '/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); break; } $invest->account = $projectAccount->paypal; if (Paypal::pay($invest, $errors)) { $errors[] = 'Cargo paypal correcto'; $log_text = "El admin %s ha ejecutado el cargo a %s por su aporte de %s mediante PayPal (id: %s) al proyecto %s del dia %s"; $invest->status = 1; // 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 ejecutar el aporte manualmente por el admin ' . $_SESSION['user']->name); } } else { $txt_errors = implode('; ', $errors); $errors[] = 'Fallo al ejecutar cargo paypal: ' . $txt_errors . '<strong>POSIBLE INCIDENCIA NO COMUNICADA Y APORTE NO CANCELADO, HAY QUE TRATARLA MANUALMENTE</strong>'; $log_text = "El admin %s ha fallado al ejecutar el cargo a %s por su aporte de %s mediante PayPal (id: %s) al proyecto %s del dia %s. <br />Se han dado los siguientes errores: {$txt_errors}"; } break; case 'tpv': if (Tpv::pay($invest, $errors)) { $errors[] = 'Cargo sermepa correcto'; $log_text = "El admin %s ha ejecutado el cargo a %s por su aporte de %s mediante TPV (id: %s) al proyecto %s del dia %s"; $invest->status = 1; } else { $txt_errors = implode('; ', $errors); $errors[] = 'Fallo al ejecutar cargo sermepa: ' . $txt_errors; $log_text = "El admin %s 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': $invest->setStatus('1'); $errors[] = 'Aporte al contado, nada que ejecutar.'; $log_text = "El admin %s ha dado por ejecutado el aporte manual a nombre de %s por la cantidad de %s (id: %s) al proyecto %s del dia %s"; $invest->status = 1; break; } if (!empty($log_text)) { // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate('Cargo ejecutado manualmente (admin)', '/admin/accounts', \vsprintf($log_text, array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), 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(); Model\Invest::setDetail($invest->id, 'manually-executed', $log->html); unset($log); } } // visor de logs if ($action == 'viewer') { return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'viewer')); } if ($action == 'resign' && !empty($id) && $_GET['token'] == md5('resign')) { if ($invest->setResign(true)) { Model\Invest::setDetail($invest->id, 'manually-resigned', 'Se ha marcado como donativo independientemente de las recompensas'); throw new Redirection('/admin/accounts/detail/' . $invest->id); } else { $errors[] = 'Ha fallado al marcar donativo'; } } if (!empty($errors)) { Message::Error(implode('<br />', $errors)); } // tipos de aporte $methods = Model\Invest::methods(); // estados del proyecto $status = Model\Project::status(); $procStatus = Model\Project::procStatus(); // estados de aporte $investStatus = Model\Invest::status(); // listado de proyectos $projects = Model\Invest::projects(); // 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'); // filtros de revisión de proyecto $review = array('collect' => 'Recaudado', 'paypal' => 'Rev. PayPal', 'tpv' => 'Rev. TPV', 'online' => 'Pagos Online'); $issue = array('show' => 'Solamente las incidencias', 'hide' => 'Ocultar las incidencias'); /// detalles de una transaccion if ($action == 'details') { $invest = Model\Invest::get($id); $project = Model\Project::get($invest->project); $userData = Model\User::get($invest->user); return new View('view/admin/index.html.php', array('folder' => 'accounts', 'file' => 'details', 'invest' => $invest, 'project' => $project, 'user' => $userData, 'details' => $details, 'status' => $status, 'investStatus' => $investStatus)); } // listado de aportes if ($filters['filtered'] == 'yes') { $list = Model\Invest::getList($filters, null, 999); } else { $list = array(); } $viewData = array('folder' => 'accounts', 'file' => 'list', 'list' => $list, 'filters' => $filters, 'users' => $users, 'projects' => $projects, 'calls' => $calls, 'review' => $review, 'methods' => $methods, 'types' => $types, 'status' => $status, 'procStatus' => $procStatus, 'issue' => $issue, 'investStatus' => $investStatus); return new View('view/admin/index.html.php', $viewData); }
public static function invested($user, $publicOnly = true) { $projects = array(); $sql = "SELECT project.id\r\n FROM project\r\n INNER JOIN invest\r\n ON project.id = invest.project\r\n AND invest.user = ?\r\n AND invest.status IN ('0', '1', '3', '4')\r\n WHERE project.status < 7\r\n "; if ($publicOnly) { $sql .= "AND project.status >= 3\r\n "; } $sql .= "GROUP BY project.id\r\n ORDER BY name ASC\r\n "; /* * Restriccion de que no aparecen los que cofinancio que esten en edicion * solamente no sacamos los caducados * project.status > 1 AND */ $query = self::query($sql, array($user)); foreach ($query->fetchAll(\PDO::FETCH_CLASS) as $proj) { $projects[] = \Goteo\Model\Project::getMedium($proj->id); } return $projects; }
* Goteo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Goteo. If not, see <http://www.gnu.org/licenses/agpl.txt>. * */ use Goteo\Library\Text, Goteo\Model; $promo = $this['promo']; $node = isset($_SESSION['admin_node']) ? $_SESSION['admin_node'] : \GOTEO_NODE; // proyectos disponibles // si tenemos ya proyecto seleccionado lo incluimos $projects = Model\Promote::available($promo->project, $node); $status = Model\Project::status(); ?> <form method="post" action="/admin/promote"> <input type="hidden" name="action" value="<?php echo $this['action']; ?> " /> <input type="hidden" name="order" value="<?php echo $promo->order; ?> " /> <input type="hidden" name="id" value="<?php echo $promo->id; ?> " />
public static function doPay($invest, &$errors = array()) { try { $project = Project::getMini($invest->project); $userData = User::getMini($invest->user); // Create request object $payRequest = new \ExecutePaymentRequest(); $payRequest->payKey = $invest->payment; $payRequest->requestEnvelope = 'SOAP'; // Create service wrapper object $ap = new \AdaptivePayments(); // invoke business method on service wrapper passing in appropriate request params $response = $ap->ExecutePayment($payRequest); // Check response if (strtoupper($ap->isSuccess) == 'FAILURE') { $soapFault = $ap->getLastError(); if (is_array($soapFault->error)) { $errorId = $soapFault->error[0]->errorId; $errorMsg = $soapFault->error[0]->message; } else { $errorId = $soapFault->error->errorId; $errorMsg = $soapFault->error->message; } if (is_array($soapFault->payErrorList->payError)) { $errorId = $soapFault->payErrorList->payError[0]->error->errorId; $errorMsg = $soapFault->payErrorList->payError[0]->error->message; } // tratamiento de errores switch ($errorId) { case '569013': // preapproval cancelado por el usuario desde panel paypal // preapproval cancelado por el usuario desde panel paypal case '539012': // preapproval no se llegó a autorizar if ($invest->cancel()) { $action = 'Aporte cancelado'; // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate('Aporte cancelado por preaproval cancelado por el usuario paypal', '/admin/invests', \vsprintf('Se ha <span class="red">Cancelado</span> el aporte de %s de %s (id: %s) al proyecto %s del dia %s por preapproval cancelado', 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('system'); unset($log); } break; } if (empty($errorId)) { $errors[] = 'NO es soapFault pero no es Success: <pre>' . print_r($ap, 1) . '</pre>'; @mail(\GOTEO_FAIL_MAIL, 'Error en implementacion Paypal API', 'ERROR en ' . __FUNCTION__ . ' No es un soap fault pero no es un success.<br /><pre>' . print_r($ap, 1) . '</pre>'); } else { $errors[] = "{$action} {$errorMsg} [{$errorId}]"; } return false; } // verificar el campo paymentExecStatus if ($response->paymentExecStatus == 'COMPLETED') { if ($invest->setStatus('3')) { return true; } else { $errors[] = "Obtenido estatus de ejecución {$response->paymentExecStatus} pero no se ha actualizado el registro de aporte id {$invest->id}."; @mail(\GOTEO_FAIL_MAIL, 'Error al actualizar registro aporte (setStatus)', 'ERROR en ' . __FUNCTION__ . ' Metodo paypal::setStatus ha fallado.<br /><pre>' . print_r($response, 1) . '</pre>'); return false; } } else { $errors[] = 'No se ha completado el pago encadenado, no se ha pagado al proyecto.'; @mail(\GOTEO_FAIL_MAIL, 'Error fatal en comunicacion Paypal API', 'ERROR en ' . __FUNCTION__ . ' aporte id ' . $invest->id . '. No payment exec status completed.<br /><pre>' . print_r($response, 1) . '</pre>'); return false; } } catch (Exception $e) { $fault = new \FaultMessage(); $errorData = new \ErrorData(); $errorData->errorId = $ex->getFile(); $errorData->message = $ex->getMessage(); $fault->error = $errorData; $errors[] = 'No se ha podido inicializar la comunicación con Paypal, se ha reportado la incidencia.'; @mail(\GOTEO_FAIL_MAIL, 'Error fatal en comunicacion Paypal API', 'ERROR en ' . __FUNCTION__ . '<br />No se ha podido inicializar la comunicación con Paypal.<br /><pre>' . print_r($fault, 1) . '</pre>'); return false; } }
private function view($id, $show, $post = null) { $project = Model\Project::get($id, LANG); // recompensas foreach ($project->individual_rewards as &$reward) { $reward->none = false; $reward->taken = $reward->getTaken(); // cofinanciadores quehan optado por esta recompensas // si controla unidades de esta recompensa, mirar si quedan if ($reward->units > 0 && $reward->taken >= $reward->units) { $reward->none = true; } } // mensaje cuando, sin estar en campaña, tiene fecha de publicación, es que la campaña ha sido cancelada if ($project->status < 3 && !empty($project->published)) { Message::Info(Text::get('project-unpublished')); } elseif ($project->status < 3) { // mensaje de no publicado siempre que no esté en campaña Message::Info(Text::get('project-not_published')); } // solamente se puede ver publicamente si... $grant = false; if ($project->status > 2) { // está publicado $grant = true; } elseif ($project->owner == $_SESSION['user']->id) { // es el dueño $grant = true; } elseif (ACL::check('/project/edit/todos')) { // es un admin $grant = true; } elseif (ACL::check('/project/view/todos')) { // es un usuario con permiso $grant = true; } elseif (isset($_SESSION['user']->roles['checker']) && Model\User\Review::is_assigned($_SESSION['user']->id, $project->id)) { // es un revisor y lo tiene asignado $grant = true; } // (Callsys) // si lo puede ver if ($grant) { $viewData = array('project' => $project, 'show' => $show); // sus entradas de novedades $blog = Model\Blog::get($project->id); // si está en modo preview, ponemos todas las entradas, incluso las no publicadas if (isset($_GET['preview']) && $_GET['preview'] == $_SESSION['user']->id) { $blog->posts = Model\Blog\Post::getAll($blog->id, null, false); } $viewData['blog'] = $blog; // tenemos que tocar esto un poquito para motrar las necesitades no economicas if ($show == 'needs-non') { $viewData['show'] = 'needs'; $viewData['non-economic'] = true; } // -- Mensaje azul molesto para usuarios no registrados if (($show == 'messages' || $show == 'updates') && empty($_SESSION['user'])) { Message::Info(Text::html('user-login-required')); } //tenemos que tocar esto un poquito para gestionar los pasos al aportar if ($show == 'invest') { // si no está en campaña no pueden estar aqui ni de coña if ($project->status != 3) { Message::Info(Text::get('project-invest-closed')); throw new Redirection('/project/' . $id, Redirection::TEMPORARY); } $viewData['show'] = 'supporters'; /* pasos de proceso aporte * * 1, 'start': ver y seleccionar recompensa (y cantidad) * 2, 'login': loguear con usuario/contraseña o con email (que crea el usuario automáticamente) * 3, 'confirm': confirmar los datos y saltar a la pasarela de pago * 4, 'ok'/'fail': al volver de la pasarela de pago, la confirmación nos dice si todo bien o algo mal * 5, 'continue': recuperar aporte incompleto (variante de confirm) */ // usamos la variable de url $post para movernos entre los pasos $step = isset($post) && in_array($post, array('start', 'login', 'confirm', 'continue')) ? $post : 'start'; // si llega confirm ya ha terminado el proceso de aporte if (isset($_GET['confirm']) && \in_array($_GET['confirm'], array('ok', 'fail'))) { unset($_SESSION['invest-amount']); // confirmación $step = $_GET['confirm']; } else { // si no, a ver en que paso estamos if (isset($_GET['amount'])) { $_SESSION['invest-amount'] = $_GET['amount']; } // si el usuario está validado, recuperamos posible amount y mostramos if ($_SESSION['user'] instanceof Model\User) { $step = 'confirm'; } elseif ($step != 'start' && empty($_SESSION['user'])) { // si no está validado solo puede estar en start Message::Info(Text::get('user-login-required-to_invest')); $step = 'start'; } elseif ($step == 'start') { // para cuando salte $_SESSION['jumpto'] = SEC_URL . '/project/' . $id . '/invest/#continue'; } else { $step = 'start'; } } $viewData['step'] = $step; } if ($show == 'updates') { $viewData['post'] = $post; $viewData['owner'] = $project->owner; } if ($show == 'messages' && $project->status < 3) { Message::Info(Text::get('project-messages-closed')); } return new View('view/project/view.html.php', $viewData); } else { // no lo puede ver throw new Redirection("/"); } }
* Goteo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Goteo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Goteo. If not, see <http://www.gnu.org/licenses/agpl.txt>. * */ use Goteo\Core\View, Goteo\Model\Project, Goteo\Library\Text; $projects = Goteo\Model\Project::published("available"); // random y que solo pinte seis si hubiera más ?> <div class="widget projects"> <h2 class="title">プロジェクト<?php //echo Text::get('home-projects-header'); ?> </h2> <?php foreach ($projects as $project) { ?> <?php echo new View('view/project/widget/project.html.php', array('project' => $project));
public static function Projects($debug = false) { // proyectos a notificar $projects = Model\Project::review(); // para cada uno, foreach ($projects as $project) { // por ahora solo tratamos los de primera ronda y hasta 2 meses tras la financiación if ($project->days > 40 || $project->days > 360) { continue; } if ($debug) { echo "Proyecto {$project->name}, Impulsor: {$project->user->name}, email: {$project->user->email}, estado {$project->status}, lleva {$project->days} dias<br />"; } // primero los que no se bloquean // Recuerdo al autor proyecto, 2 meses despues de campaña finalizada if ($project->days == 140) { // si quedan recompensas/retornos pendientes por cumplir if (!Model\Project\Reward::areFulfilled($project->id) || !Model\Project\Reward::areFulfilled($project->id, 'social')) { if ($debug) { echo "Recompensas/Retornos pendientes<br />"; } Send::toOwner('2m_after', $project); } else { if ($debug) { echo "Recompensas/Retornos cumplidas, no se envía<br />"; } } } // Recuerdo al autor proyecto, 8 meses despues de campaña finalizada if ($project->days == 320) { // si quedan retornos pendientes por cumplir if (!Model\Project\Reward::areFulfilled($project->id, 'social')) { if ($debug) { echo "Retornos pendientes<br />"; } Send::toOwner('8m_after', $project); } else { if ($debug) { echo "Retornos cumplidos, no se envía<br />"; } } } // ahora checkeamos bloqueo de consejos $prefs = Model\User::getPreferences($project->owner); if ($prefs->tips) { if ($debug) { echo "Bloqueado por preferencias<hr />"; } continue; } // flag de aviso $avisado = false; // Consejos/avisos puntuales switch ($project->days) { // NO condicionales case 1: // Difunde, difunde, difunde // Difunde, difunde, difunde case 2: // Comienza por lo más próximo // Comienza por lo más próximo case 3: // Una acción a diario, por pequeña que sea // Una acción a diario, por pequeña que sea case 4: // Llama a todas las puertas // Llama a todas las puertas case 5: // Busca dónde está tu comunidad // Busca dónde está tu comunidad case 8: // Agradece en público e individualmente $template = 'tip_' . $project->days; if ($debug) { echo "Envío {$template}<br />"; } Send::toOwner($template, $project); break; // periodico condicional // periodico condicional case 6: // Publica novedades! // y se repite cada 6 días (fechas libres) mientras no haya posts // Publica novedades! // y se repite cada 6 días (fechas libres) mientras no haya posts case 12: case 18: case 24: case 30: case 36: // si ya hay novedades, nada if (Model\Blog::hasUpdates($project->id)) { if ($debug) { echo "Ya ha publicado novedades<br />"; } } else { if ($debug) { echo "Envío aviso de que no ha publicado novedades<br />"; } Send::toOwner('any_update', $project); $avisado = true; } break; // comprobación periódica pero solo un envío // comprobación periódica pero solo un envío case 7: // Apóyate en quienes te van apoyando , si más de 20 cofinanciadores // o en cuanto llegue a 20 backers (en fechas libres) // Apóyate en quienes te van apoyando , si más de 20 cofinanciadores // o en cuanto llegue a 20 backers (en fechas libres) case 14: case 17: case 21: case 24: case 27: // Si ya se mandó esta plantilla (al llegar a los 20 por primera vez) no se envía de nuevo $sql = "\n SELECT\n id\n FROM mail\n WHERE mail.email = :email\n AND mail.template = 46\n ORDER BY mail.date DESC\n LIMIT 1"; $query = Model\Project::query($sql, array(':email' => $project->user->email)); $sended = $query->fetchColumn(0); if (!$sended) { if ($project->num_investors >= 20) { if ($debug) { echo "Tiene 20 backers y no se le habia enviado aviso antes<br />"; } Send::toOwner('20_backers', $project); } else { if ($debug) { echo "No llega a los 20 backers<br />"; } } } else { if ($debug) { echo "Ya enviado<br />"; } } break; case 9: // Busca prescriptores e implícalos // si no tiene padrinos if ($project->patrons > 0) { if ($debug) { echo "Tiene padrino<br />"; } } else { if ($debug) { echo "No tiene padrino<br />"; } Send::toOwner('tip_9', $project); } break; case 10: // Luce tus recompensas y retornos // que no se envie a los que solo tienen recompensas de agradecimiento $thanksonly = true; // recompensas $rewards = Model\Project\Reward::getAll($project->id, 'individual', \LANG); foreach ($rewards as $rew) { if ($rew->icon != 'thanks') { $thanksonly = false; break; // ya salimos del bucle, no necesitamos más } } if ($thanksonly) { if ($debug) { echo "Solo tiene recompensas de agradecimiento<br />"; } } else { if ($debug) { echo "Tienen recompensas<br />"; } uasort($rewards, function ($a, $b) { if ($a->amount == $b->amount) { return 0; } return $a->amount > $b->amount ? 1 : -1; }); // sacar la primera y la última $lower = reset($rewards); $project->lower = $lower->reward; $higher = end($rewards); $project->higher = $higher->reward; Send::toOwner('tip_10', $project); } break; case 11: // Refresca tu mensaje de motivacion // si no tiene video motivacional if (empty($project->video)) { if ($debug) { echo "No tiene video motivacional<br />"; } Send::toOwner('tip_11', $project); } else { if ($debug) { echo "Tiene video motivacional<br />"; } } break; case 15: // Sigue los avances y calcula lo que falta // si no ha llegado al mínimo if ($project->invested < $project->mincost) { if ($debug) { echo "No ha llegado al mínimo<br />"; } Send::toOwner('tip_15', $project); } else { if ($debug) { echo "Ha llegado al mínimo<br />"; } } break; case 25: // No bajes la guardia! // si no ha llegado al mínimo if ($project->invested < $project->mincost) { if ($debug) { echo "No ha llegado al mínimo<br />"; } Send::toOwner('two_weeks', $project); } else { if ($debug) { echo "Ha llegado al mínimo<br />"; } } break; case 32: // Al proyecto le faltan 8 días para archivarse // si no ha llegado al mínimo if ($project->invested < $project->mincost) { if ($debug) { echo "No ha llegado al mínimo<br />"; } Send::toOwner('8_days', $project); } else { if ($debug) { echo "Ha llegado al mínimo<br />"; } } break; case 38: // Al proyecto le faltan 2 días para archivarse // si no ha llegado al mínimo pero está por encima del 70% if ($project->invested < $project->mincost && $project->percent >= 70) { if ($debug) { echo "No ha llegado al mínimo<br />"; } Send::toOwner('2_days', $project); } else { if ($debug) { echo "Ha llegado al mínimo o lleva menos de 70%<br />"; } } break; } // Avisos periodicos // si lleva más de 15 días: si no se han publicado novedades en la última semana // Ojo! que si no a enviado ninguna no lanza este sino la de cada 6 días if (!$avisado && $project->days > 15) { if ($debug) { echo "ya lleva una quincena de campaña, verificamos novedades<br />"; } // veamos si ya le avisamos hace una semana // Si ya se mandó esta plantilla (al llegar a los 20 por primera vez) no se envía de nuevo $sql = "\n SELECT\n id,\n DATE_FORMAT(\n from_unixtime(unix_timestamp(now()) - unix_timestamp(date))\n , '%j'\n ) as days\n FROM mail\n WHERE mail.email = :email\n AND mail.template = 23\n ORDER BY mail.date DESC\n LIMIT 1"; $query = Model\Project::query($sql, array(':email' => $project->user->email)); $lastsend = $query->fetchObject(); if (!$lastsend->id || $lastsend->days > 7) { // veamos cuanto hace de la última novedad $sql = "\n SELECT\n DATE_FORMAT(\n from_unixtime(unix_timestamp(now()) - unix_timestamp(date))\n , '%j'\n ) as days\n FROM post\n INNER JOIN blog\n ON post.blog = blog.id\n AND blog.type = 'project'\n AND blog.owner = :project\n WHERE post.publish = 1\n ORDER BY post.date DESC\n LIMIT 1"; $query = Model\Project::query($sql, array(':project' => $project->id)); $lastUpdate = $query->fetchColumn(0); if ($lastUpdate > 7) { if ($debug) { echo "Ultima novedad es de hace más de una semana<br />"; } Send::toOwner('no_updates', $project); } elseif (is_numeric($lastUpdate)) { if ($debug) { echo "Publicó novedad hace menos de una semana<br />"; } } else { if ($debug) { echo "No se ha publicado nada, recibirá el de cada 6 días<br />"; } } } else { if ($debug) { echo "Se le avisó por novedades hace menos de una semana<br />"; } } } if ($debug) { echo "<hr />"; } } if ($debug) { echo "<br />Auto-tips Listo!<hr />"; } return; }
public static function process($action = 'list', $id = null, $filters = array()) { $node = isset($_SESSION['admin_node']) ? $_SESSION['admin_node'] : \GOTEO_NODE; $errors = array(); switch ($action) { case 'add': // proyectos que están más allá de edición y con traducción deshabilitada $availables = Model\User\Translate::getAvailables('project', $_SESSION['admin_node']); if (empty($availables)) { Message::Error(Text::_('No hay más proyectos disponibles para traducir')); throw new Redirection('/admin/translates'); } case 'edit': case 'assign': case 'unassign': case 'send': // a ver si tenemos proyecto if (empty($id) && !empty($_POST['project'])) { $id = $_POST['project']; } if (!empty($id)) { $project = Model\Project::getMini($id); } elseif ($action != 'add') { Message::Error(Text::_('No hay proyecto sobre el que operar')); throw new Redirection('/admin/translates'); } // asignar o desasignar // la id de revision llega en $id // la id del usuario llega por get $user = $_GET['user']; if (!empty($user)) { $userData = Model\User::getMini($user); $assignation = new Model\User\Translate(array('item' => $project->id, 'type' => 'project', 'user' => $user)); switch ($action) { case 'assign': // se la ponemos $what = Text::_('Asignado'); if ($assignation->save($errors)) { Message::Info(Text::_('Traducción asignada correctamente')); throw new Redirection('/admin/translates/edit/' . $project->id); } else { Message::Error(Text::_('No se ha guardado correctamente. ') . implode(', ', $errors)); } break; case 'unassign': // se la quitamos $what = Text::_('Desasignado'); if ($assignation->remove($errors)) { Message::Info(Text::_('Traducción desasignada correctamente')); throw new Redirection('/admin/translates/edit/' . $project->id); } else { Message::Error(Text::_('No se ha guardado correctamente. ') . implode(', ', $errors)); } break; } if (empty($errors)) { // Evento Feed $log = new Feed(); $log->setTarget($userData->id, 'user'); $log->populate($what . ' traduccion (admin)', '/admin/translates', \vsprintf('El admin %s ha %s a %s la traducción del proyecto %s', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', $what), Feed::item('user', $userData->name, $userData->id), Feed::item('project', $project->name, $project->id)))); $log->doAdmin('admin'); unset($log); } $action = 'edit'; } // fin asignar o desasignar // añadir o actualizar // se guarda el idioma original y si la traducción está abierta o cerrada if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['save'])) { if (empty($id)) { Message::Error(Text::_('Hemos perdido de vista el proyecto')); throw new Redirection('/admin/translates'); } // ponemos los datos que llegan $sql = "UPDATE project SET lang = :lang, translate = 1 WHERE id = :id"; if (Model\Project::query($sql, array(':lang' => $_POST['lang'], ':id' => $id))) { if ($action == 'add') { Message::Info('El proyecto ' . $project->name . ' se ha habilitado para traducir'); } else { Message::Info(Text::_('Datos de traducción actualizados')); } if ($action == 'add') { // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate(Text::_('proyecto habilitado para traducirse (admin)'), '/admin/translates', \vsprintf('El admin %s ha %s la traducción del proyecto %s', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', 'Habilitado'), Feed::item('project', $project->name, $project->id)))); $log->doAdmin('admin'); unset($log); throw new Redirection('/admin/translates/edit/' . $project->id); } else { throw new Redirection('/admin/translates'); } } else { if ($action == 'add') { Message::Error(Text::_('Ha fallado al habilitar la traducción del proyecto ') . $project->name); } else { Message::Error(Text::_('Ha fallado al actualizar los datos de la traducción')); } } } if ($action == 'send') { // Informar al autor de que la traduccion está habilitada // Obtenemos la plantilla para asunto y contenido $template = Template::get(26); // Sustituimos los datos $subject = str_replace('%PROJECTNAME%', $project->name, $template->title); $search = array('%OWNERNAME%', '%PROJECTNAME%', '%SITEURL%'); $replace = array($project->user->name, $project->name, SITE_URL); $content = \str_replace($search, $replace, $template->text); // iniciamos mail $mailHandler = new Mail(); $mailHandler->to = $project->user->email; $mailHandler->toName = $project->user->name; // blind copy a goteo desactivado durante las verificaciones // $mailHandler->bcc = '*****@*****.**'; $mailHandler->subject = $subject; $mailHandler->content = $content; $mailHandler->html = true; $mailHandler->template = $template->id; if ($mailHandler->send()) { Message::Info('Se ha enviado un email a <strong>' . $project->user->name . '</strong> a la dirección <strong>' . $project->user->email . '</strong>'); } else { Message::Error('Ha fallado al enviar el mail a <strong>' . $project->user->name . '</strong> a la dirección <strong>' . $project->user->email . '</strong>'); } unset($mailHandler); $action = 'edit'; } $project->translators = Model\User\Translate::translators($id); $translators = Model\User::getAll(array('role' => 'translator')); // añadimos al dueño del proyecto en el array de traductores array_unshift($translators, $project->user); return new View('view/admin/index.html.php', array('folder' => 'translates', 'file' => 'edit', 'action' => $action, 'availables' => $availables, 'translators' => $translators, 'project' => $project)); break; case 'close': // la sentencia aqui mismo // el campo translate del proyecto $id a false $sql = "UPDATE project SET translate = 0 WHERE id = :id"; if (Model\Project::query($sql, array(':id' => $id))) { Message::Info('La traducción del proyecto ' . $project->name . ' se ha finalizado'); Model\Project::query("DELETE FROM user_translate WHERE type = 'project' AND item = :id", array(':id' => $id)); // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate(Text::_('traducción finalizada (admin)'), '/admin/translates', \vsprintf('El admin %s ha dado por %s la traducción del proyecto %s', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', 'Finalizada'), Feed::item('project', $project->name, $project->id)))); $log->doAdmin('admin'); unset($log); } else { Message::Error(Text::_('Falló al finalizar la traducción')); } break; } $projects = Model\Project::getTranslates($filters, $node); $owners = Model\User::getOwners(); $translators = Model\User::getAll(array('role' => 'translator')); return new View('view/admin/index.html.php', array('folder' => 'translates', 'file' => 'list', 'projects' => $projects, 'filters' => $filters, 'fields' => array('owner', 'translator'), 'owners' => $owners, 'translators' => $translators)); }
* the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Goteo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Goteo. If not, see <http://www.gnu.org/licenses/agpl.txt>. * */ use Goteo\Core\View, Goteo\Library\Text, Goteo\Library\SuperForm; $project = $this['project']; $errors = $this['errors']; $original = \Goteo\Model\Project::get($project->id); // media del proyecto if (!empty($project->media->url)) { $media = array('type' => 'media', 'title' => Text::get('overview-field-media_preview'), 'class' => 'inline media', 'type' => 'html', 'html' => !empty($project->media) ? $project->media->getEmbedCode() : ''); } else { $media = array('type' => 'hidden', 'class' => 'inline'); } // video de motivacion if (!empty($project->video->url)) { $video = array('type' => 'media', 'title' => Text::get('overview-field-media_preview'), 'class' => 'inline media', 'type' => 'html', 'html' => !empty($project->video) ? $project->video->getEmbedCode() : ''); } else { $video = array('type' => 'hidden', 'class' => 'inline'); } ?> <form method="post" action="/dashboard/translates/overview/save" class="project" enctype="multipart/form-data">
* Goteo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Goteo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Goteo. If not, see <http://www.gnu.org/licenses/agpl.txt>. * */ use Goteo\Core\View, Goteo\Model, Goteo\Library\Worth, Goteo\Library\Text; $waitfor = Model\Project::waitfor(); $worthcracy = Worth::getAll(); $user = $_SESSION['user']; $support = $user->support; $lsuf = LANG != 'es' ? '?lang=' . LANG : ''; ?> <script type="text/javascript"> jQuery(document).ready(function ($) { /* todo esto para cada lista de proyectos (flechitas navegacion) */ $("#discover-group-my_projects-1").show(); $("#navi-discover-group-my_projects-1").addClass('active'); $("#discover-group-invest_on-1").show(); $("#navi-discover-group-invest_on-1").addClass('active');
public function confirmed($project = null, $id = null, $reward = null) { if (empty($id)) { Message::Error(Text::get('invest-data-error')); throw new Redirection('/', Redirection::TEMPORARY); } // el aporte $invest = Model\Invest::get($id); $projectData = Model\Project::getMedium($invest->project); // para evitar las duplicaciones de feed y email if (isset($_SESSION['invest_' . $invest->id . '_completed'])) { Message::Info(Text::get('invest-process-completed')); throw new Redirection($retUrl); } // segun método if ($invest->method == 'tpv') { // si el aporte no está en estado "cobrado por goteo" (1) if ($invest->status != '1') { @mail('*****@*****.**', 'Aporte tpv no pagado ' . $invest->id, 'Ha llegado a invest/confirm el aporte ' . $invest->id . ' mediante tpv sin estado cobrado (llega con estado ' . $invest->status . ')'); // mandarlo a la pagina de aportar para que lo intente de nuevo // si es de Bazar, a la del producto del catálogo if ($project == 'bazargoteo') { throw new Redirection("/bazaar/{$reward}/fail"); } else { throw new Redirection("/project/{$invest->project}/invest/?confirm=fail"); } } } // Paypal solo disponible si activado if ($invest->method == 'paypal') { // hay que cambiarle el status a 0 $invest->setStatus('0'); // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('Aporte PayPal', '/admin/invests', \vsprintf("%s ha aportado %s al proyecto %s mediante PayPal", array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('money', $invest->amount . ' €'), Feed::item('project', $projectData->name, $projectData->id)))); $log->doAdmin('money'); // evento público $log_html = Text::html('feed-invest', Feed::item('money', $invest->amount . ' €'), Feed::item('project', $projectData->name, $projectData->id)); if ($invest->anonymous) { $log->populate(Text::get('regular-anonymous'), '/user/profile/anonymous', $log_html, 1); } else { $log->populate($_SESSION['user']->name, '/user/profile/' . $_SESSION['user']->id, $log_html, $_SESSION['user']->avatar->id); } $log->doPublic('community'); unset($log); } // fin segun metodo // Feed del aporte de la campaña if (!empty($invest->droped) && $drop instanceof Model\Invest && is_object($callData)) { // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('Aporte riego ' . $drop->method, '/admin/invests', \vsprintf("%s ha aportado %s de %s al proyecto %s a través de la campaña %s", array(Feed::item('user', $callData->user->name, $callData->user->id), Feed::item('money', $drop->amount . ' €'), Feed::item('drop', 'Capital Riego', '/service/resources'), Feed::item('project', $projectData->name, $projectData->id), Feed::item('call', $callData->name, $callData->id)))); $log->doAdmin('money'); // evento público $log->populate($callData->user->name, '/user/profile/' . $callData->user->id, Text::html('feed-invest', Feed::item('money', $drop->amount . ' €') . ' de ' . Feed::item('drop', 'Capital Riego', '/service/resources'), Feed::item('project', $projectData->name, $projectData->id) . ' a través de la campaña ' . Feed::item('call', $callData->name, $callData->id)), $callData->user->avatar->id); $log->doPublic('community'); unset($log); } // texto recompensa // @TODO quitar esta lacra de N recompensas porque ya es solo una recompensa siempre $rewards = $invest->rewards; array_walk($rewards, function (&$reward) { $reward = $reward->reward; }); $txt_rewards = implode(', ', $rewards); // recaudado y porcentaje $amount = $projectData->invested; $percent = floor($projectData->invested / $projectData->mincost * 100); // email de agradecimiento al cofinanciador // primero monto el texto de recompensas //@TODO el concepto principal sería 'renuncia' (porque todos los aportes son donativos) if ($invest->resign) { // Plantilla de donativo segun la ronda if ($projectData->round == 2) { $template = Template::get(36); // en segunda ronda } else { $template = Template::get(28); // en primera ronda } } else { // plantilla de agradecimiento segun la ronda if ($projectData->round == 2) { $template = Template::get(34); // en segunda ronda } else { $template = Template::get(10); // en primera ronda } } // Dirección en el mail (y version para regalo) $txt_address = Text::get('invest-address-address-field') . ' ' . $invest->address->address; $txt_address .= '<br> ' . Text::get('invest-address-zipcode-field') . ' ' . $invest->address->zipcode; $txt_address .= '<br> ' . Text::get('invest-address-location-field') . ' ' . $invest->address->location; $txt_address .= '<br> ' . Text::get('invest-address-country-field') . ' ' . $invest->address->country; $txt_destaddr = $txt_address; $txt_address = Text::get('invest-mail_info-address') . '<br>' . $txt_address; // Agradecimiento al cofinanciador // Sustituimos los datos $subject = str_replace('%PROJECTNAME%', $projectData->name, $template->title); // En el contenido: $search = array('%USERNAME%', '%PROJECTNAME%', '%PROJECTURL%', '%AMOUNT%', '%REWARDS%'); $replace = array($_SESSION['user']->name, $projectData->name, SITE_URL . '/project/' . $projectData->id, $confirm->amount, $txt_rewards); $content = \str_replace($search, $replace, $template->text); $mailHandler = new Mail(); $mailHandler->reply = GOTEO_CONTACT_MAIL; $mailHandler->replyName = GOTEO_MAIL_NAME; $mailHandler->to = $_SESSION['user']->email; $mailHandler->toName = $_SESSION['user']->name; $mailHandler->subject = $subject; $mailHandler->content = $content; $mailHandler->html = true; $mailHandler->template = $template->id; if ($mailHandler->send($errors)) { Message::Info(Text::get('project-invest-thanks_mail-success')); } else { Message::Error(Text::get('project-invest-thanks_mail-fail')); Message::Error(implode('<br />', $errors)); } unset($mailHandler); // Notificación al autor $template = Template::get(29); // Sustituimos los datos $subject = str_replace('%PROJECTNAME%', $projectData->name, $template->title); // En el contenido: $search = array('%OWNERNAME%', '%USERNAME%', '%PROJECTNAME%', '%SITEURL%', '%AMOUNT%', '%MESSAGEURL%'); $replace = array($projectData->user->name, $_SESSION['user']->name, $projectData->name, SITE_URL, $invest->amount, SITE_URL . '/user/profile/' . $_SESSION['user']->id . '/message'); $content = \str_replace($search, $replace, $template->text); $mailHandler = new Mail(); $mailHandler->to = $projectData->user->email; $mailHandler->toName = $projectData->user->name; $mailHandler->subject = $subject; $mailHandler->content = $content; $mailHandler->html = true; $mailHandler->template = $template->id; $mailHandler->send(); unset($mailHandler); // marcar que ya se ha completado el proceso de aportar $_SESSION['invest_' . $invest->id . '_completed'] = true; // log Model\Invest::setDetail($invest->id, 'confirmed', 'El usuario regresó a /invest/confirmed'); if ($confirm->method == 'paypal') { // hay que cambiarle el status a 0 $confirm->setStatus('0'); /* * Evento Feed */ $log = new Feed(); $log->title = 'Aporte PayPal'; $log->url = '/admin/invests'; $log->type = 'money'; $log_text = "%s ha aportado %s al proyecto %s mediante PayPal"; $items = array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('money', $confirm->amount . ' €'), Feed::item('project', $projectData->name, $projectData->id)); $log->html = \vsprintf($log_text, $items); $log->add($errors); // evento público if ($confirm->anonymous) { $log->title = Text::get('regular-anonymous'); $log->url = '/user/profile/anonymous'; $log->image = 1; } else { $log->title = $_SESSION['user']->name; $log->url = '/user/profile/' . $_SESSION['user']->id; $log->image = $_SESSION['user']->avatar->id; } $log->scope = 'public'; $log->type = 'community'; $log->html = Text::html('feed-invest', Feed::item('money', $confirm->amount . ' €'), Feed::item('project', $projectData->name, $projectData->id)); $log->add($errors); unset($log); } // mandarlo a la pagina de gracias throw new Redirection("/project/{$project}/invest/?confirm=ok", Redirection::TEMPORARY); }
public static function process($action = 'list', $id = null, $filters = array()) { $log_text = null; $errors = array(); // multiples usos $nodes = array(); if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['id'])) { $projData = Model\Project::get($_POST['id']); if (empty($projData->id)) { Message::Error('El proyecto ' . $_POST['id'] . ' no existe'); throw new Redirection('/admin/projects/images/' . $id); } if (isset($_POST['save-dates'])) { $fields = array('created', 'updated', 'published', 'success', 'closed', 'passed'); $set = ''; $values = array(':id' => $projData->id); foreach ($fields as $field) { if ($set != '') { $set .= ", "; } $set .= "`{$field}` = :{$field} "; if (empty($_POST[$field]) || $_POST[$field] == '0000-00-00') { $_POST[$field] = null; } $values[":{$field}"] = $_POST[$field]; } try { $sql = "UPDATE project SET " . $set . " WHERE id = :id"; if (Model\Project::query($sql, $values)) { $log_text = 'El admin %s ha <span class="red">tocado las fechas</span> del proyecto ' . $projData->name . ' %s'; } else { $log_text = 'Al admin %s le ha <span class="red">fallado al tocar las fechas</span> del proyecto ' . $projData->name . ' %s'; } } catch (\PDOException $e) { Message::Error(Text::_("No se ha guardado correctamente. ") . $e->getMessage()); } } elseif (isset($_POST['save-accounts'])) { $accounts = Model\Project\Account::get($projData->id); $accounts->bank = $_POST['bank']; $accounts->bank_owner = $_POST['bank_owner']; $accounts->paypal = $_POST['paypal']; $accounts->paypal_owner = $_POST['paypal_owner']; if ($accounts->save($errors)) { Message::Info(Text::_('Se han actualizado las cuentas del proyecto ') . $projData->name); } else { Message::Error(implode('<br />', $errors)); } } elseif ($action == 'images') { $todook = true; if (!empty($_POST['move'])) { $direction = $_POST['action']; Model\Project\Image::$direction($id, $_POST['move'], $_POST['section']); } foreach ($_POST as $key => $value) { $parts = explode('_', $key); if ($parts[1] == 'image' && in_array($parts[0], array('section', 'url'))) { if (Model\Project\Image::update($id, $parts[2], $parts[0], $value)) { // OK } else { $todook = false; Message::Error(Text::_('No se ha podido actualizar campo') . " {$parts[0]} -> {$value}"); } } } if ($todook) { Message::Info(Text::_('Se han actualizado los datos')); } throw new Redirection('/admin/projects/images/' . $id); } elseif ($action == 'rebase') { $todook = true; if ($_POST['proceed'] == 'rebase' && !empty($_POST['newid'])) { $newid = $_POST['newid']; // pimero miramos que no hay otro proyecto con esa id $test = Model\Project::getMini($newid); if ($test->id == $newid) { Message::Error(Text::_('Ya hay un proyecto con ese Id.')); throw new Redirection('/admin/projects/rebase/' . $id); } if ($projData->status >= 3 && $_POST['force'] != 1) { Message::Error(Text::_('El proyecto no está ni en Edición ni en Revisión, no se modifica nada.')); throw new Redirection('/admin/projects/rebase/' . $id); } if ($projData->rebase($newid)) { Message::Info(Text::_('Verificar el proyecto') . ' -> <a href="' . SITE_URL . '/project/' . $newid . '" target="_blank">' . $projData->name . '</a>'); throw new Redirection('/admin/projects'); } else { Message::Info(Text::_('Ha fallado algo en el rebase, verificar el proyecto') . ' -> <a href="' . SITE_URL . '/project/' . $projData->id . '" target="_blank">' . $projData->name . ' (' . $id . ')</a>'); throw new Redirection('/admin/projects/rebase/' . $id); } } } } /* * switch action, * proceso que sea, * redirect * */ if (isset($id)) { $project = Model\Project::get($id); } switch ($action) { case 'review': // pasar un proyecto a revision if ($project->ready($errors)) { $redir = '/admin/reviews/add/' . $project->id; $log_text = 'El admin %s ha pasado el proyecto %s al estado <span class="red">Revision</span>'; } else { $log_text = 'Al admin %s le ha fallado al pasar el proyecto %s al estado <span class="red">Revision</span>'; } break; case 'publish': // poner un proyecto en campa�a if ($project->publish($errors)) { $log_text = 'El admin %s ha pasado el proyecto %s al estado <span class="red">en Campa�a</span>'; } else { $log_text = 'Al admin %s le ha fallado al pasar el proyecto %s al estado <span class="red">en Campa�a</span>'; } break; case 'cancel': // descartar un proyecto por malo if ($project->cancel($errors)) { $log_text = 'El admin %s ha pasado el proyecto %s al estado <span class="red">Descartado</span>'; } else { $log_text = 'Al admin %s le ha fallado al pasar el proyecto %s al estado <span class="red">Descartado</span>'; } break; case 'enable': // si no esta en edicion, recuperarlo if ($project->enable($errors)) { $log_text = 'El admin %s ha pasado el proyecto %s al estado <span class="red">Edicion</span>'; } else { $log_text = 'Al admin %s le ha fallado al pasar el proyecto %s al estado <span class="red">Edicion</span>'; } break; case 'fulfill': // marcar que el proyecto ha cumplido con los retornos colectivos if ($project->satisfied($errors)) { $log_text = 'El admin %s ha pasado el proyecto %s al estado <span class="red">Retorno cumplido</span>'; } else { $log_text = 'Al admin %s le ha fallado al pasar el proyecto %s al estado <span class="red">Retorno cumplido</span>'; } break; case 'unfulfill': // dar un proyecto por financiado manualmente if ($project->rollback($errors)) { $log_text = 'El admin %s ha pasado el proyecto %s al estado <span class="red">Financiado</span>'; } else { $log_text = 'Al admin %s le ha fallado al pasar el proyecto %s al estado <span class="red">Financiado</span>'; } break; } if (isset($log_text)) { // Evento Feed $log = new Feed(); $log->setTarget($project->id); $log->populate(Text::_('Cambio estado/fechas/cuentas/nodo de un proyecto desde el admin'), '/admin/projects', \vsprintf($log_text, array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('project', $project->name, $project->id)))); $log->doAdmin('admin'); Message::Info($log->html); if (!empty($errors)) { Message::Error(implode('<br />', $errors)); } if ($action == 'publish') { // si es publicado, hay un evento publico $log->populate($project->name, '/project/' . $project->id, Text::html('feed-new_project'), $project->gallery[0]->id); $log->doPublic('projects'); } unset($log); if (empty($redir)) { throw new Redirection('/admin/projects/list'); } else { throw new Redirection($redir); } } if ($action == 'report') { // informe financiero // Datos para el informe de transacciones correctas $Data = Model\Invest::getReportData($project->id, $project->status, $project->round, $project->passed); return new View('view/admin/index.html.php', array('folder' => 'projects', 'file' => 'report', 'project' => $project, 'Data' => $Data)); } if ($action == 'dates') { // cambiar fechas return new View('view/admin/index.html.php', array('folder' => 'projects', 'file' => 'dates', 'project' => $project)); } if ($action == 'accounts') { $accounts = Model\Project\Account::get($project->id); // cambiar fechas return new View('view/admin/index.html.php', array('folder' => 'projects', 'file' => 'accounts', 'project' => $project, 'accounts' => $accounts)); } if ($action == 'images') { // imagenes $images = array(); // secciones $sections = Model\Project\Image::sections(); foreach ($sections as $sec => $secName) { $secImages = Model\Project\Image::get($project->id, $sec); foreach ($secImages as $img) { $images[$sec][] = $img; } } return new View('view/admin/index.html.php', array('folder' => 'projects', 'file' => 'images', 'project' => $project, 'images' => $images, 'sections' => $sections)); } if ($action == 'move') { // cambiar el nodo return new View('view/admin/index.html.php', array('folder' => 'projects', 'file' => 'move', 'project' => $project, 'nodes' => $nodes)); } if ($action == 'rebase') { // cambiar la id return new View('view/admin/index.html.php', array('folder' => 'projects', 'file' => 'rebase', 'project' => $project)); } // Rechazo express if ($action == 'reject') { if (empty($project)) { Message::Error(Text::_('No hay proyecto sobre el que operar')); } else { // Obtenemos la plantilla para asunto y contenido $template = Template::get(40); // Sustituimos los datos $subject = str_replace('%PROJECTNAME%', $project->name, $template->title); $search = array('%USERNAME%', '%PROJECTNAME%'); $replace = array($project->user->name, $project->name); $content = \str_replace($search, $replace, $template->text); // iniciamos mail $mailHandler = new Mail(); $mailHandler->to = $project->user->email; $mailHandler->toName = $project->user->name; $mailHandler->subject = $subject; $mailHandler->content = $content; $mailHandler->html = true; $mailHandler->template = $template->id; if ($mailHandler->send()) { Message::Info('Se ha enviado un email a <strong>' . $project->user->name . '</strong> a la dirección <strong>' . $project->user->email . '</strong>'); } else { Message::Error('Ha fallado al enviar el mail a <strong>' . $project->user->name . '</strong> a la dirección <strong>' . $project->user->email . '</strong>'); } unset($mailHandler); } throw new Redirection('/admin/projects/list'); } if (!empty($filters['filtered'])) { $projects = Model\Project::getList($filters, $_SESSION['admin_node']); } else { $projects = array(); } $status = Model\Project::status(); $categories = Model\Project\Category::getAll(); //@CONTRACTSYS $calls = array(); // la lista de nodos la hemos cargado arriba $orders = array('name' => Text::_('Nombre'), 'updated' => Text::_('Enviado a revision')); return new View('view/admin/index.html.php', array('folder' => 'projects', 'file' => 'list', 'projects' => $projects, 'filters' => $filters, 'status' => $status, 'categories' => $categories, 'calls' => $calls, 'nodes' => $nodes, 'orders' => $orders)); }
public static function getList($filters = array(), $published = true) { $values = array(':lang' => \LANG); $list = array(); $sql = "\n SELECT\n post.id as id,\n post.blog as blog,\n IFNULL(post_lang.title, post.title) as title,\n IFNULL(post_lang.text, post.text) as `text`,\n IFNULL(post_lang.legend, post.legend) as `legend`,\n post.image as `image`,\n post.media as `media`,\n DATE_FORMAT(post.date, '%d-%m-%Y') as fecha,\n post.publish as publish,\n post.home as home,\n post.footer as footer,\n post.author as author,\n blog.type as owner_type,\n blog.owner as owner_id\n FROM post\n INNER JOIN blog\n ON blog.id = post.blog\n LEFT JOIN post_lang\n ON post_lang.id = post.id\n AND post_lang.lang = :lang\n "; if (in_array($filters['show'], array('all', 'home', 'footer'))) { $sql .= " WHERE blog.id IS NOT NULL\n "; } elseif ($filters['show'] == 'updates') { $sql .= " WHERE blog.type = 'project'\n "; } else { $sql .= " WHERE blog.type = 'node'\n "; } if (!empty($filters['blog'])) { $sql .= " AND post.blog = :blog\n "; $values[':blog'] = $filters['blog']; } if (!empty($filters['tag'])) { $sql .= " AND post.id IN (SELECT post FROM post_tag WHERE tag = :tag)\n "; $values[':tag'] = $filters['tag']; } if (!empty($filters['author'])) { $sql .= " AND post.author = :author\n "; $values[':author'] = $filters['author']; } // solo las publicadas if ($published || $filters['show'] == 'published') { $sql .= " AND post.publish = 1\n "; if (empty($filters['blog'])) { $sql .= " AND blog.owner IN (SELECT id FROM node WHERE active = 1)\n AND blog.owner != 'testnode'\n "; } } // solo las del propio blog if ($filters['show'] == 'owned') { $sql .= " AND blog.owner = :node\n "; $values[':node'] = $filters['node']; } // solo las de la portada if ($filters['show'] == 'home') { if ($filters['node'] == \GOTEO_NODE) { $sql .= " AND post.home = 1\n "; } else { $sql .= " AND post.id IN (SELECT post FROM post_node WHERE node = :node)\n "; $values[':node'] = $filters['node']; } } if ($filters['show'] == 'footer') { if ($filters['node'] == \GOTEO_NODE) { $sql .= " AND post.footer = 1\n "; } } $sql .= "\n ORDER BY post.date DESC, post.id DESC\n "; $query = static::query($sql, $values); foreach ($query->fetchAll(\PDO::FETCH_CLASS, __CLASS__) as $post) { // galeria $post->gallery = Image::getAll($post->id, 'post'); $post->image = $post->gallery[0]; // video if (isset($post->media)) { $post->media = new Media($post->media); } $post->num_comments = Post\Comment::getCount($post->id); // datos del autor del post switch ($post->owner_type) { case 'project': $proj_blog = Project::getMini($post->owner_id); $post->author = $proj_blog->owner; $post->user = $proj_blog->user; $post->owner_name = $proj_blog->name; break; case 'node': $post->user = User::getMini($post->author); $node_blog = Node::get($post->owner_id); $post->owner_name = $node_blog->name; break; } $list[$post->id] = $post; } return $list; }
} ?> <div class="widget"> <p><strong><?php echo $project->name ?></strong></p> <a class="button red" href="/project/edit/<?php echo $project->id ?>"><?php echo Text::get('regular-edit') ?></a> <a class="button" href="/project/<?php echo $project->id ?>" target="_blank"><?php echo Text::get('dashboard-menu-projects-preview') ?></a> <?php if ($project->status == 1) : ?> <a class="button weak" href="/project/delete/<?php echo $project->id ?>" onclick="return confirm('<?php echo Text::get('dashboard-project-delete_alert') ?>')"><?php echo Text::get('regular-delete') ?></a> <?php endif ?> </div> <div class="status"> <div id="project-status"> <h3><?php echo Text::get('form-project-status-title'); ?></h3> <ul> <?php foreach (Project::status() as $i => $s): ?> <li><?php if ($i == $project->status) echo '<strong>' ?><?php echo htmlspecialchars($s) ?><?php if ($i == $project->status) echo '</strong>' ?></li> <?php endforeach ?> </ul> </div> </div> <div id="meter-big" class="widget collapsable"> <?php echo new View('view/m/project/meter_hor_big.html.php', $this) ?> </div>
public function post($post, $project = null) { if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST['message'])) { $comment = new Model\Blog\Post\Comment(array('user' => $_SESSION['user']->id, 'post' => $post, 'date' => date('Y-m-d H:i:s'), 'text' => $_POST['message'])); if ($comment->save($errors)) { // a ver los datos del post $postData = Model\Blog\Post::get($post); // Evento Feed $log = new Feed(); if (!empty($project)) { $projectData = Model\Project::getMini($project); $log->setTarget($projectData->id); $log_html = \vsprintf('%s ha escrito un %s en la entrada "%s" en las %s del proyecto %s', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('message', 'Comentario'), Feed::item('update-comment', $postData->title, $projectData->id . '/updates/' . $postData->id . '#comment' . $comment->id), Feed::item('update-comment', 'Novedades', $projectData->id . '/updates/'), Feed::item('project', $projectData->name, $projectData->id))); } else { $log->setTarget('goteo', 'blog'); $log_html = \vsprintf('%s ha escrito un %s en la entrada "%s" del blog de %s', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('message', 'Comentario'), Feed::item('blog', $postData->title, $postData->id . '#comment' . $comment->id), Feed::item('blog', 'Goteo', '/'))); } $log->populate('usuario escribe comentario en blog/novedades', '/admin/projects', $log_html); $log->doAdmin('user'); // Evento público if (!empty($project)) { $projectData = Model\Project::getMini($project); $log_html = Text::html('feed-updates-comment', Feed::item('update-comment', $postData->title, $projectData->id . '/updates/' . $postData->id . '#comment' . $comment->id), Feed::item('update-comment', 'Novedades', $projectData->id . '/updates/'), Feed::item('project', $projectData->name, $projectData->id)); } else { $log_html = Text::html('feed-blog-comment', Feed::item('blog', $postData->title, $postData->id . '#comment' . $comment->id), Feed::item('blog', 'Goteo', '/')); } $log->populate($_SESSION['user']->name, '/user/profile/' . $_SESSION['user']->id, $log_html, $_SESSION['user']->avatar->id); $log->doPublic('community'); unset($log); //Notificación al autor del proyecto // Obtenemos la plantilla para asunto y contenido $template = Template::get(31); // Sustituimos los datos $subject = str_replace('%PROJECTNAME%', $projectData->name, $template->title); $response_url = SITE_URL . '/user/profile/' . $_SESSION['user']->id . '/message'; $project_url = SITE_URL . '/project/' . $projectData->id . '/updates/' . $postData->id . '#comment' . $comment->id; $search = array('%MESSAGE%', '%OWNERNAME%', '%USERNAME%', '%PROJECTNAME%', '%PROJECTURL%', '%RESPONSEURL%'); $replace = array($_POST['message'], $projectData->user->name, $_SESSION['user']->name, $projectData->name, $project_url, $response_url); $content = \str_replace($search, $replace, $template->text); $mailHandler = new Mail(); $mailHandler->to = $projectData->user->email; $mailHandler->toName = $projectData->user->name; $mailHandler->subject = $subject; $mailHandler->content = $content; $mailHandler->html = true; $mailHandler->template = $template->id; $mailHandler->send($errors); unset($mailHandler); } else { // error } } if (!empty($project)) { throw new Redirection("/project/{$project}/updates/{$post}#comment" . $comment->id, Redirection::TEMPORARY); } else { throw new Redirection("/blog/{$post}#comment" . $comment->id, Redirection::TEMPORARY); } }
/** * Perfil público de usuario. * * @param string $id Nombre de usuario */ public function profile($id, $show = 'profile', $category = null) { if (!in_array($show, array('profile', 'investors', 'sharemates', 'message'))) { $show = 'profile'; } $user = Model\User::get($id, LANG); if (!$user instanceof Model\User || $user->hide) { throw new Error('404', Text::html('fatal-error-user')); } //--- para usuarios públicos--- if (empty($_SESSION['user'])) { // la subpágina de mensaje también está restringida if ($show == 'message') { $_SESSION['jumpto'] = '/user/profile/' . $id . '/message'; Message::Info(Text::get('user-login-required-to_message')); throw new Redirection(SEC_URL . "/user/login"); } // a menos que este perfil sea de un vip, no pueden verlo if (!isset($user->roles['vip'])) { $_SESSION['jumpto'] = '/user/profile/' . $id . '/' . $show; Message::Info(Text::get('user-login-required-to_see')); throw new Redirection(SEC_URL . "/user/login"); } /* // subpágina de cofinanciadores if ($show == 'investors') { Message::Info(Text::get('user-login-required-to_see-supporters')); throw new Redirection('/user/profile/' . $id); } */ } //--- el resto pueden seguir --- // impulsor y usuario solamente pueden comunicarse si: if ($show == 'message') { $is_author = false; // si es autor de un proyecto publicado $is_investor = false; // si es cofinanciador $is_messeger = false; // si es participante // si el usuario logueado es impulsor (autro de proyecto publicado $user_created = Model\Project::ofmine($_SESSION['user']->id, true); if (!empty($user_created)) { $is_author = true; } // si el usuario del perfil es cofin. o partic. // proyectos que es cofinanciador este usuario (el del perfil) $user_invested = Model\User::invested($id, true); foreach ($user_invested as $a_project) { if ($a_project->owner == $_SESSION['user']->id) { $is_investor = true; break; } } // proyectos que es participante este usuario (el del perfil) (que ha enviado algún mensaje) $user_messeged = Model\Message::getMesseged($id, true); foreach ($user_messeged as $a_project) { if ($a_project->owner == $_SESSION['user']->id) { $is_messeger = true; break; } } // si el usuario logueado es el usuario cofin./partic. // si el usuario del perfil es impulsor de un proyecto cofinanciado o en el que ha participado // proyectos que es cofinanciador el usuario logueado $user_invested = Model\User::invested($_SESSION['user']->id, true); foreach ($user_invested as $a_project) { if ($a_project->owner == $id) { $is_investor = true; break; } } // proyectos que es participante el usuario logueado (que ha enviado algún mensaje) $user_messeged = Model\Message::getMesseged($_SESSION['user']->id, true); foreach ($user_messeged as $a_project) { if ($a_project->owner == $id) { $is_messeger = true; break; } } if (!$is_investor && !$is_messeger && !$is_author) { Message::Info(Text::get('user-message-restricted')); throw new Redirection('/user/profile/' . $id); } else { $_SESSION['message_autorized'] = true; } } // vip profile $viewData = array(); $viewData['user'] = $user; $projects = Model\Project::ofmine($id, true); $viewData['projects'] = $projects; //mis cofinanciadores // array de usuarios con: // foto, nombre, nivel, cantidad a mis proyectos, fecha ultimo aporte, nº proyectos que cofinancia $investors = array(); foreach ($projects as $kay => $project) { // quitamos los caducados if ($project->status == 0) { unset($projects[$kay]); continue; } foreach (Model\Invest::investors($project->id) as $key => $investor) { // convocadores no, gracias if (!empty($investor->campaign)) { continue; } if (\array_key_exists($investor->user, $investors)) { // ya está en el array, quiere decir que cofinancia este otro proyecto // , añadir uno, sumar su aporte, actualizar la fecha ++$investors[$investor->user]->projects; $investors[$investor->user]->amount += $investor->amount; $investors[$investor->user]->date = $investor->date; } else { $investors[$investor->user] = (object) array('user' => $investor->user, 'name' => $investor->name, 'projects' => 1, 'avatar' => $investor->avatar, 'worth' => $investor->worth, 'amount' => $investor->amount, 'date' => $investor->date); } } } $viewData['investors'] = $investors; // comparten intereses $viewData['shares'] = Model\User\Interest::share($id, $category); if ($show == 'sharemates' && empty($viewData['shares'])) { $show = 'profile'; } if (!empty($category)) { $viewData['category'] = $category; } // proyectos que cofinancio $invested = Model\User::invested($id, true); // agrupacion de proyectos que cofinancia y proyectos suyos $viewData['lists'] = array(); if (!empty($invested)) { $viewData['lists']['invest_on'] = Listing::get($invested, 2); } if (!empty($projects)) { $viewData['lists']['my_projects'] = Listing::get($projects, 2); } return new View('view/user/' . $show . '.html.php', $viewData); }
public static function process($action = 'list', $id = null, $filters = array()) { switch ($action) { case 'fulfill': $sql = "UPDATE invest_reward SET fulfilled = 1 WHERE invest = ?"; if (Model\Invest::query($sql, array($id))) { Message::Info(Text::get('admin-rewards-info-status-completed')); } else { Message::Error(Text::get('admin-rewards-error-statuschage-fail')); } throw new Redirection('/admin/rewards'); break; case 'unfill': $sql = "UPDATE invest_reward SET fulfilled = 0 WHERE invest = ?"; if (Model\Invest::query($sql, array($id))) { Message::Info(Text::get('admin-rewards-info-status-completed-pending')); } else { message::Error('Ha fallado al desmarcar'); } throw new Redirection('/admin/rewards'); break; } // edicion if ($action == 'edit' && !empty($id)) { $invest = Model\Invest::get($id); $projectData = Model\Project::get($invest->project); $userData = Model\User::getMini($invest->user); $status = Model\Project::status(); // si tratando post if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['update'])) { $errors = array(); // la recompensa: $chosen = $_POST['selected_reward']; if (empty($chosen)) { // renuncia a las recompensas, bien por el/ella! $invest->rewards = array(); } else { $invest->rewards = array($chosen); } $invest->anonymous = $_POST['anonymous']; // dirección de envio para la recompensa // y datos fiscales por si fuera donativo $invest->address = (object) array('name' => $_POST['name'], 'nif' => $_POST['nif'], 'address' => $_POST['address'], 'zipcode' => $_POST['zipcode'], 'location' => $_POST['location'], 'country' => $_POST['country']); if ($invest->update($errors)) { Message::Info(Text::get('admin-rewards-info-update')); throw new Redirection('/admin/rewards'); } else { Message::Error('No se han actualizado correctamente los datos del aporte. ERROR: ' . implode(', ', $errors)); } } return new View('view/admin/index.html.php', array('folder' => 'rewards', 'file' => 'edit', 'invest' => $invest, 'project' => $projectData, 'user' => $userData, 'status' => $status)); } // listado de proyectos $projects = Model\Invest::projects(); $status = array('nok' => Text::_("Pendiente"), 'ok' => Text::_("Cumplida")); // listado de aportes if ($filters['filtered'] == 'yes') { $list = Model\Project\Reward::getChossen($filters); } else { $list = array(); } return new View('view/admin/index.html.php', array('folder' => 'rewards', 'file' => 'list', 'list' => $list, 'filters' => $filters, 'projects' => $projects, 'status' => $status)); }
public static function process($action = 'list', $id = null, $filters = array(), $flag = null) { $errors = array(); $node = isset($_SESSION['admin_node']) ? $_SESSION['admin_node'] : \GOTEO_NODE; if ($_SERVER['REQUEST_METHOD'] == 'POST') { // objeto $promo = new Model\Promote(array('id' => $id, 'node' => $node, 'project' => $_POST['project'], 'title' => $_POST['title'], 'description' => $_POST['description'], 'order' => $_POST['order'], 'active' => $_POST['active'])); if ($promo->save($errors)) { switch ($_POST['action']) { case 'add': Message::Info('Proyecto destacado correctamente'); $projectData = Model\Project::getMini($_POST['project']); if ($node == \GOTEO_NODE) { // Evento Feed $log = new Feed(); $log->setTarget($projectData->id); $log->populate('nuevo proyecto destacado en portada (admin)', '/admin/promote', \vsprintf('El admin %s ha %s el proyecto %s', array(Feed::item('user', $_SESSION['user']->name, $_SESSION['user']->id), Feed::item('relevant', 'Destacado en portada', '/'), Feed::item('project', $projectData->name, $projectData->id)))); $log->doAdmin('admin'); unset($log); } break; case 'edit': Message::Info('Destacado actualizado correctamente'); break; } throw new Redirection('/admin/promote'); } else { Message::Error(implode(', ', $errors)); switch ($_POST['action']) { case 'add': return new View('view/admin/index.html.php', array('folder' => 'promote', 'file' => 'edit', 'action' => 'add', 'promo' => $promo)); break; case 'edit': return new View('view/admin/index.html.php', array('folder' => 'promote', 'file' => 'edit', 'action' => 'edit', 'promo' => $promo)); break; } } } switch ($action) { case 'active': $set = $flag == 'on' ? true : false; Model\Promote::setActive($id, $set); throw new Redirection('/admin/promote'); break; case 'up': Model\Promote::up($id, $node); throw new Redirection('/admin/promote'); break; case 'down': Model\Promote::down($id, $node); throw new Redirection('/admin/promote'); break; case 'remove': if (Model\Promote::delete($id)) { Message::Info('Destacado quitado correctamente'); } else { Message::Error('No se ha podido quitar el destacado'); } throw new Redirection('/admin/promote'); break; case 'add': // siguiente orden $next = Model\Promote::next($node); return new View('view/admin/index.html.php', array('folder' => 'promote', 'file' => 'edit', 'action' => 'add', 'promo' => (object) array('order' => $next, 'node' => $node))); break; case 'edit': $promo = Model\Promote::get($id); return new View('view/admin/index.html.php', array('folder' => 'promote', 'file' => 'edit', 'action' => 'edit', 'promo' => $promo)); break; } $promoted = Model\Promote::getAll(false, $node); return new View('view/admin/index.html.php', array('folder' => 'promote', 'file' => 'list', 'promoted' => $promoted)); }