public function adminHome($req, $res)
 {
     if (!$this->app['user']->isAdmin()) {
         return $res->redirect('/login?redir=' . urlencode($req->basePath() . $req->path()));
     }
     $metrics = [];
     $chartData = [];
     $chartGranularities = [];
     $chartLoadedIntervals = [];
     $start = -7;
     $end = 0;
     $dashboard = (array) $this->app['config']->get('statistics.dashboard');
     foreach ($dashboard as $section => $metricClasses) {
         foreach ($metricClasses as $className) {
             $className = '\\app\\statistics\\metrics\\' . $className . 'Metric';
             $metric = new $className($this->app);
             $k = $metric->key();
             U::array_set($metrics, $section . '.' . $k, $metric->toArray());
             if ($metric->hasChart()) {
                 $chartData[$k] = $metric->values();
                 $gName = $metric::$granularityNames[$metric->granularity()];
                 $chartGranularities[$k] = $gName;
                 $chartLoadedIntervals[$k] = 'last-7-' . $gName . 's';
             }
         }
     }
     return new View('admin/index', ['metrics' => $metrics, 'chartNames' => array_keys($chartData), 'chartData' => $chartData, 'chartGranularities' => $chartGranularities, 'chartLoadedIntervals' => $chartLoadedIntervals, 'title' => 'Statistics']);
 }
 public function __invoke(Request $req, Response $res, callable $next)
 {
     $config = $this->app['config'];
     if (!$config->get('sessions.enabled') || $req->isApi()) {
         return $next($req, $res);
     }
     $lifetime = $config->get('sessions.lifetime');
     $hostname = $config->get('app.hostname');
     ini_set('session.use_trans_sid', false);
     ini_set('session.use_only_cookies', true);
     ini_set('url_rewriter.tags', '');
     ini_set('session.gc_maxlifetime', $lifetime);
     // set the session name
     $defaultSessionTitle = $config->get('app.title') . '-' . $hostname;
     $sessionTitle = $config->get('sessions.name', $defaultSessionTitle);
     $safeSessionTitle = str_replace(['.', ' ', "'", '"'], ['', '_', '', ''], $sessionTitle);
     session_name($safeSessionTitle);
     // set the session cookie parameters
     session_set_cookie_params($lifetime, '/', '.' . $hostname, $req->isSecure(), true);
     // register session_write_close as a shutdown function
     session_register_shutdown();
     // install any custom session handlers
     $class = $config->get('sessions.driver');
     if ($class) {
         $handler = new $class($this->app);
         $handler::registerHandler($handler);
     }
     session_start();
     // fix the session cookie
     Utility::setCookieFixDomain(session_name(), session_id(), time() + $lifetime, '/', $hostname, $req->isSecure(), true);
     // make the newly started session in our request
     $req->setSession($_SESSION);
     return $next($req, $res);
 }
Beispiel #3
0
 public function submitVolunteerApplication($req, $res)
 {
     $currentUser = $this->app['user'];
     // make sure the user is logged in
     if (!$currentUser->isLoggedIn()) {
         setcookie('redirect', '/volunteers/application', time() + 3600, '/');
         return $res->redirect('/login');
     }
     if (!$req->request('accept')) {
         $req->setParams(['accept_error' => true]);
         return $this->volunteerApplication($req, $res);
     }
     $input = $req->request();
     $input['uid'] = $currentUser->id();
     $input['birth_date'] = mktime(0, 0, 0, $input['month'] + 1, $input['day'], $input['year']);
     $input['first_time_volunteer'] = !U::array_value($input, 'volunteered_before');
     $application = $currentUser->volunteerApplication();
     if (!$application->exists()) {
         $application = new VolunteerApplication();
         if ($application->create($input)) {
             return $res->redirect('/volunteers/application/thanks');
         }
     } else {
         if ($application->set($input)) {
             return $res->redirect('/volunteers/application/thanks');
         }
     }
     return $this->volunteerApplication($req, $res);
 }
 public function send(array $message)
 {
     $result = [];
     $to = (array) array_value($message, 'to');
     foreach ($to as $item) {
         $result[] = ['_id' => Utility::guid(false), 'email' => $item['email'], 'status' => 'sent'];
     }
     return $result;
 }
 public function getFriendsCount()
 {
     $facebook = $this->app['facebook_service'];
     $facebook->setAccessTokenFromProfile($this);
     $friends = $facebook->api('me/friends', 'get');
     if (is_array($friends)) {
         return count((array) U::array_value($friends, 'data'));
     }
     return -1;
 }
 /**
  * The first step in the forgot password sequence.
  *
  * @param string $email     email address
  * @param string $ip        ip address making the request
  * @param string $userAgent user agent used to make the request
  *
  * @throws AuthException when the step cannot be completed.
  *
  * @return bool
  */
 public function step1($email, $ip, $userAgent)
 {
     $email = trim(strtolower($email));
     if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
         throw new AuthException('Please enter a valid email address.');
     }
     $userClass = $this->auth->getUserClass();
     $user = $userClass::where('email', $email)->first();
     if (!$user || $user->isTemporary()) {
         throw new AuthException('We could not find a match for that email address.');
     }
     // can only issue a single active forgot token at a time
     $expiration = U::unixToDb(time() - UserLink::$forgotLinkTimeframe);
     $nExisting = UserLink::totalRecords(['user_id' => $user->id(), 'type' => UserLink::FORGOT_PASSWORD, 'created_at > "' . $expiration . '"']);
     if ($nExisting > 0) {
         return true;
     }
     // generate a reset password link
     $link = $this->buildLink($user->id(), $ip, $userAgent);
     // and send it
     return $user->sendEmail('forgot-password', ['ip' => $ip, 'forgot' => $link->link]);
 }
 /**
  * Performs an API call on the facebook API (if available) or
  * returns a mock response.
  *
  * @param string $endpoint
  * @param string $method   HTTP method
  * @param array  $params   optional params
  *
  * @return object
  */
 public function api($endpoint, $method = null, $params = null)
 {
     $response = false;
     try {
         return $this->app['facebook']->api($endpoint, $method, $params);
     } catch (\FacebookApiException $e) {
         // access token has expired
         $result = $e->getResult();
         $code = U::array_value($result, 'error.code');
         if ($code == 190) {
             // clear the access token of the user's profile
             if ($this->profile) {
                 $this->profile->grantAllPermissions();
                 $this->profile->set('access_token', '');
                 $this->profile->enforcePermissions();
             }
         } else {
             $this->app['logger']->error($e);
         }
         return false;
     }
 }
 public function send(array $message)
 {
     // build recipients
     $to = [];
     $bcc = [];
     $toIncoming = (array) array_value($message, 'to');
     foreach ($toIncoming as $item) {
         $type = array_value($item, 'type');
         if ($type == 'bcc') {
             $bcc[$item['email']] = $item['name'];
         } else {
             $to[$item['email']] = $item['name'];
         }
     }
     if (count($to) === 0) {
         return [];
     }
     $fromEmail = array_value($message, 'from_email');
     $fromName = array_value($message, 'from_name');
     $swiftMessage = Swift_Message::newInstance()->setFrom([$fromEmail => $fromName])->setTo($to)->setBcc($bcc)->setSubject($message['subject'])->setBody($message['html'], 'text/html');
     if (isset($message['text'])) {
         $swiftMessage->addPart($message['text'], 'text/plain');
     }
     if (isset($message['headers']) && is_array($message['headers'])) {
         $headers = $swiftMessage->getHeaders();
         foreach ($message['headers'] as $k => $v) {
             $headers->addTextHeader($k, $v);
         }
     }
     $sent = $this->swift->send($swiftMessage);
     $result = [];
     foreach ($message['to'] as $item) {
         $result[] = ['_id' => Utility::guid(false), 'email' => $item['email'], 'status' => $sent ? 'sent' : 'rejected'];
     }
     return $result;
 }
 public function value($start, $end)
 {
     return (int) $this->app['db']->select('COUNT(uid)')->from('Users')->where([['created_at', U::unixToDb($end), '<='], ['created_at', U::unixToDb($start), '>=']])->scalar();
 }
 /**
  * Generates the output of a report for a given type.
  *
  * @param string   $type   html|pdf|csv
  * @param bool     $stream when true, streams the resulting file to the client (pdf, csv only)
  * @param Response $res    when streaming, response object to use
  *
  * @return string|array|false
  */
 public function output($type, $stream = false, Response $res = null)
 {
     // $this->organization->useTimezone();
     $type = strtolower($type);
     if ($type == 'html') {
         $this->htmlOutput = true;
         // NOTE host name has the development port number stripped,
         // otherwise the css is not loaded
         $data = ['css' => 'file://' . INFUSE_PUBLIC_DIR . '/css/report.css', 'header' => $this->getHeader(), 'sections' => $this->getSections()];
         $this->htmlOutput = false;
         $view = new View('report', $data);
         return $view->render();
     } elseif ($type == 'pdf') {
         $html = $this->output('html');
         // Run wkhtmltopdf
         $descriptorspec = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
         $process = proc_open(WKHTMLTOPDF_CMD, $descriptorspec, $pipes);
         // Send the HTML on stdin
         fwrite($pipes[0], $html);
         fclose($pipes[0]);
         // Read the outputs
         $pdf = stream_get_contents($pipes[1]);
         $errors = stream_get_contents($pipes[2]);
         // Close the process
         fclose($pipes[1]);
         $return_value = proc_close($process);
         // Handle errors
         if ($errors) {
             error_log($errors);
         }
         // Output the results
         if ($stream) {
             $res->setContentType('application/pdf')->setHeader('Cache-Control', 'public, must-revalidate, max-age=0')->setHeader('Pragma', 'public')->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT')->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT')->setHeader('Content-Length', strlen($pdf))->setHeader('Content-Disposition', 'attachment; filename="' . $this->baseFilename() . '.pdf";')->setBody($pdf);
         } else {
             return $pdf;
         }
     } elseif ($type == 'csv') {
         $output = [];
         $header = $this->getHeader();
         foreach ($header as $key => $value) {
             $output[] = [$key, $value];
         }
         $output[] = [];
         $sections = $this->getSections();
         foreach ($sections as $section) {
             if (isset($section['title'])) {
                 $output[] = [$section['title']];
             }
             if (isset($section['keyvalue'])) {
                 foreach ($section['keyvalue'] as $key => $value) {
                     $output[] = [$key, $value];
                 }
                 $output[] = [];
             }
             $entireTable = array_merge([(array) U::array_value($section, 'header')], (array) U::array_value($section, 'rows'), [(array) U::array_value($section, 'footer')]);
             foreach ($entireTable as $row) {
                 $output[] = $row;
             }
             $output[] = [];
         }
         $csv = fopen('php://output', 'w');
         ob_start();
         foreach ($output as $row) {
             fputcsv($csv, $row);
         }
         fclose($csv);
         $output = ob_get_clean();
         if ($stream) {
             $res->setContentType('text/csv')->setHeader('Cache-Control', 'public, must-revalidate, max-age=0')->setHeader('Pragma', 'public')->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT')->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT')->setHeader('Content-Length', strlen($output))->setHeader('Content-Disposition', 'attachment; filename="' . $this->baseFilename() . '".csv')->setBody($output);
         } else {
             return $output;
         }
     }
     return false;
 }
 private function loginOrRegister($fbid, $user_profile, $req, $res)
 {
     $currentUser = $this->app['user'];
     $facebook = $this->app['facebook'];
     // get friend count
     $friendCount = 0;
     try {
         $friends = $facebook->api('me/friends');
         $friendCount = count((array) U::array_value($friends, 'data'));
     } catch (\FacebookApiException $e) {
         $this->app['logger']->error($e);
     }
     // generate parameters to update profile
     $profileUpdateArray = ['id' => $fbid, 'access_token' => $facebook->getAccessToken(), 'friends_count' => $friendCount];
     // fbid matches existing user?
     $user = User::findOne(['where' => ['facebook_id' => $fbid]]);
     if ($user) {
         // check if we are dealing with a temporary user
         if (!$user->isTemporary()) {
             if ($user->id() != $currentUser->id()) {
                 if ($req->query('forceLogin') || !$currentUser->isLoggedIn()) {
                     // log the user in
                     $this->app['auth']->signInUser($user->id(), 'facebook');
                 } else {
                     $logoutNextUrl = $this->app['base_url'] . 'facebook/connect?logout=t';
                     // inform the user that the facebook account they are trying to connect
                     // belongs to someone else
                     return new View('switchingAccounts/facebook', ['title' => 'Switch accounts?', 'otherUser' => $user, 'otherProfile' => $user->facebookProfile(), 'logoutUrl' => $facebook->getLogoutUrl(['next' => $logoutNextUrl])]);
                 }
             }
             $profile = new FacebookProfile($fbid);
             // create or update the profile
             if ($profile->exists()) {
                 $profile->set($profileUpdateArray);
             } else {
                 $profile = new FacebookProfile();
                 $profile->create($profileUpdateArray);
             }
             // refresh profile from API
             $profile->refreshProfile($user_profile);
             return $this->finalRedirect($req, $res);
         } else {
             // show finish signup screen
             $req->setSessoin('fbid', $fbid);
             return $res->redirect('/signup/finish');
         }
     }
     if ($currentUser->isLoggedIn()) {
         // add to current user's account
         $currentUser->set('facebook_id', $fbid);
     } else {
         // save this for later
         $req->setSession('fbid', $fbid);
     }
     $profile = new FacebookProfile($fbid);
     // create or update the profile
     if ($profile->exists()) {
         $profile->set($profileUpdateArray);
     } else {
         $profile = new FacebookProfile();
         $profile->create($profileUpdateArray);
     }
     // refresh profile from API
     $profile->refreshProfile($user_profile);
     // get outta here
     if ($currentUser->isLoggedIn()) {
         $this->finalRedirect($req, $res);
     } else {
         $res->redirect('/signup/finish');
     }
 }
Beispiel #12
0
 private function getModelForAdmin($req, $res)
 {
     // lookup model class
     // index derived from /organizations/:username/admin/SECTION/....
     $section = $req->paths(3);
     $modelClass = U::array_value(self::$sectionModels, $section);
     if (!$modelClass) {
         $res->setCode(404);
         return false;
     }
     // lookup org
     $org = $this->getOrgForAdmin($req, $res);
     if (!is_object($org)) {
         return false;
     }
     $model = new $modelClass($req->params('id'));
     if ($section == 'volunteers') {
         $model = new $modelClass([$req->params('id'), $org->id()]);
     }
     if (!$model->exists()) {
         $res->setCode(404);
         return false;
     }
     if (!$model->can('view', $this->app['user'])) {
         $res->setCode(401);
         return false;
     }
     return [$org, $model, $section];
 }
Beispiel #13
0
 /**
  * Increments the keys in an input array by some delta.
  * NOTE stats cannot be less than 0.
  *
  * @param array $source values to be incremented
  * @param array $delta  values to be added
  *
  * @return array incremented source
  */
 public static function increment(array $source, array $delta)
 {
     $return = [];
     foreach ($source as $k => $v) {
         $return[$k] = max(0, (int) $v + (int) U::array_value($delta, $k));
     }
     return $return;
 }
 /**
  * Upgrades the user from temporary to a fully registered account.
  *
  * @param array $data user data
  *
  * @throws InvalidArgumentException when trying to upgrade a non-temporary account.
  *
  * @return bool true if successful
  */
 public function upgradeTemporaryAccount($data)
 {
     if (!$this->isTemporary()) {
         throw new InvalidArgumentException('Cannot upgrade a non-temporary account');
     }
     $updateArray = array_replace($data, ['created_at' => U::unixToDb(time()), 'enabled' => true]);
     $success = false;
     $this->grantAllPermissions();
     $this->_isUpgrade = true;
     if ($this->set($updateArray)) {
         // remove temporary and unverified links
         $app = $this->getApp();
         $app['db']->delete('UserLinks')->where('user_id', $this->id())->where(function ($query) {
             return $query->where('type', UserLink::TEMPORARY)->orWhere('type', UserLink::VERIFY_EMAIL);
         })->execute();
         // send the user a welcome message
         $this->sendEmail('welcome');
         $success = true;
     }
     $this->_isUpgrade = false;
     $this->enforcePermissions();
     return $success;
 }
 /**
  * Maps the properties of the user profile from the API
  * to the properties in our model.
  *
  * @param array $user_profile user profile from API
  *
  * @return array
  */
 protected function mapPropertiesFromApi(array $user_profile)
 {
     $info = [];
     foreach ($this->apiPropertyMapping() as $modelProperty => $apiProperty) {
         $info[$modelProperty] = U::array_value($user_profile, $apiProperty);
     }
     return $info;
 }
 /**
  * Clears out expired user links.
  *
  * @return bool
  */
 private function gcUserLinks()
 {
     return (bool) $this->app['db']->delete('UserLinks')->where('type', UserLink::FORGOT_PASSWORD)->where('created_at', U::unixToDb(time() - UserLink::$forgotLinkTimeframe), '<')->execute();
 }
 /**
  * Verifies the cookie against an incoming request.
  *
  * @param Request     $req
  * @param AuthManager $auth
  *
  * @return bool
  */
 public function verify(Request $req, AuthManager $auth)
 {
     if (!$this->isValid()) {
         return false;
     }
     // verify the user agent matches the one in the request
     if ($this->userAgent != $req->agent()) {
         return false;
     }
     // look up the user with a matching email address
     $userClass = $auth->getUserClass();
     $user = $userClass::where('email', $this->email)->first();
     if (!$user) {
         return false;
     }
     // hash series for matching with the db
     $seriesHash = $this->hash($this->series);
     // First, make sure all of the parameters match, except the token.
     // We match the token separately to detect if an older session is
     // being used, in which case we cowardly run away.
     $expiration = time() - $this->getExpires();
     $db = $auth->getApp()['db'];
     $query = $db->select('token,two_factor_verified')->from('PersistentSessions')->where('email', $this->email)->where('created_at', U::unixToDb($expiration), '>')->where('series', $seriesHash);
     $persistentSession = $query->one();
     if ($query->rowCount() !== 1) {
         return false;
     }
     // if there is a match, sign the user in
     $tokenHash = $this->hash($this->token);
     // Same series, but different token, meaning the user is trying
     // to use an older token. It's most likely an attack, so flush
     // all sessions.
     if (!hash_equals($persistentSession['token'], $tokenHash)) {
         $db->delete('PersistentSessions')->where('email', $this->email)->execute();
         return false;
     }
     // remove the token once used
     $db->delete('PersistentSessions')->where('email', $this->email)->where('series', $seriesHash)->where('token', $tokenHash)->execute();
     // mark the user as 2fa verified
     if ($persistentSession['two_factor_verified']) {
         $user->markTwoFactorVerified();
     }
     return $user;
 }
 /**
  * Fetches the models for a given controller.
  *
  * @param object $controller
  *
  * @return array
  */
 private function models($controller)
 {
     $properties = $controller::$properties;
     $module = $this->name($controller);
     $models = [];
     foreach ((array) U::array_value($properties, 'models') as $model) {
         $modelClassName = '\\app\\' . $module . '\\models\\' . $model;
         $info = $modelClassName::metadata();
         $models[$model] = array_replace($info, ['route_base' => '/' . $module . '/' . $info['plural_key']]);
     }
     return $models;
 }
Beispiel #19
0
 public function preSetHook(&$data)
 {
     $organization = $this->relation('organization');
     $currentUser = $this->app['user'];
     $currentRole = $organization->getRoleOfUser($currentUser);
     $isAdmin = $currentUser->isAdmin() || $currentRole == self::ROLE_ADMIN;
     // volunteers can only be promoted if current user is admin
     $maxLevel = $isAdmin ? self::ROLE_ADMIN : self::ROLE_AWAITING_APPROVAL;
     $role = U::array_value($data, 'role');
     if ($role > $maxLevel) {
         $this->app['errors']->push(['error' => ERROR_NO_PERMISSION]);
         return false;
     }
     // email user if going from not approved to approved
     if ($role >= self::ROLE_VOLUNTEER && $this->role == self::ROLE_AWAITING_APPROVAL) {
         $data['approval_link'] = null;
         $this->needsApproveEmail = true;
     }
     return true;
 }
Beispiel #20
0
 /**
  * Validates a password and hashes the value.
  * OPTIONAL password:10 sets the minimum length.
  *
  * @param mixed $value
  * @param array $parameters
  *
  * @return bool
  */
 private function password(&$value, array $parameters)
 {
     $minimumPasswordLength = isset($parameters[0]) ? $parameters[0] : 8;
     if (strlen($value) < $minimumPasswordLength) {
         return false;
     }
     $value = Utility::encryptPassword($value, self::$config['salt']);
     return true;
 }
 protected function preSetHook(&$data)
 {
     // make sure the place name is unique
     $name = U::array_value($data, 'name');
     if (!empty($name) && $name != $this->name && self::totalRecords(['organization' => $this->organization, 'name' => $name]) > 0) {
         $errorStack = $this->app['errors'];
         $errorStack->push(['error' => ERROR_VOLUNTEER_PLACE_NAME_TAKEN, 'params' => ['place_name' => $name]]);
         return false;
     }
     // geocode
     if (isset($data['address'])) {
         $data['coordinates'] = $this->geocode($data['address']);
     }
     $this->justApproved = isset($data['verify_approved']) && $data['verify_approved'] && !$this->verify_approved;
     return true;
 }
 protected function preCreateHook(&$data)
 {
     $org = new Organization(U::array_value($data, 'organization'));
     // check creator permission
     $requester = $this->app['user'];
     $role = $org->getRoleOfUser($requester);
     if ($role < Volunteer::ROLE_VOLUNTEER && !$requester->isAdmin()) {
         $this->app['errors']->push(['error' => ERROR_NO_PERMISSION]);
         return false;
     }
     // volunteers cannot approve own hours
     if ($role < Volunteer::ROLE_ADMIN && !$requester->isAdmin()) {
         $data['approved'] = false;
     }
     // validate number of hours
     $hours = $data['hours'] = floor($data['hours']);
     if ($hours <= 0 || $hours >= 13) {
         $this->app['errors']->push(['error' => 'invalid_num_volunteer_hours']);
         return false;
     }
     // convert day timestamp to beginning of day
     $data['timestamp'] = self::timestampToStartOfDay($data['timestamp']);
     // the timestamp on hours cannot be more than 1 day in the future
     if ($data['timestamp'] - 86400 > time()) {
         $this->app['errors']->push(['error' => 'invalid_hours_timestamp']);
         return false;
     }
     // approval link
     if (!U::array_value($data, 'approved')) {
         $data['approval_link'] = U::guid(false);
     }
     if (isset($data['tags'])) {
         self::$createTags = $data['tags'];
         if (!is_array(self::$createTags)) {
             self::$createTags = explode(' ', self::$createTags);
         }
     }
     return true;
 }
 /**
  * Bundles up some useful properties of the statistic for convenience.
  *
  * @return array
  */
 public function toArray()
 {
     $name = $this->name();
     $value = $this->computeValue();
     $delta = $this->computeDelta();
     return ['name' => $name, 'key' => $this->key(), 'granularity' => $this->granularity(), 'prefix' => $this->prefix(), 'suffix' => $this->suffix(), 'hasChart' => $this->hasChart(), 'span' => $this->span(), 'value' => $value, 'abbreviated_value' => is_numeric($value) ? U::number_abbreviate(round($value, 2), 1) : $value, 'delta' => $delta, 'abbreviated_delta' => is_numeric($delta) ? U::number_abbreviate(round($delta, 2), 1) : $delta];
 }