function Users_0_9_2_Users_mysql() { $app = Q_Config::expect('Q', 'app'); $communityId = Users::communityId(); $rows = Users_Session::select('COUNT(1)')->where($criteria)->fetchAll(PDO::FETCH_NUM); $count = $rows[0][0]; $limit = 100; $offset = 0; $sessions = Users_Session::select('*')->orderBy('id')->limit($limit, $offset)->caching(false)->fetchDbRows(); echo "Adding userId to sessions..."; while ($sessions) { foreach ($sessions as $s) { $parsed = Q::json_decode($s->content, true); if (empty($parsed['Users']['loggedInUser']['id'])) { continue; } $s->userId = $parsed['Users']['loggedInUser']['id']; } Users_Session::insertManyAndExecute($sessions, array('onDuplicateKeyUpdate' => array('userId' => new Db_Expression("VALUES(userId)")))); $min = min($offset + $limit, $count); echo "[100D"; echo "Updated {$min} of {$count} sessions"; $offset += $limit; if ($offset > $count) { break; } $sessions = Users_Session::select('*')->orderBy('id')->limit($limit, $offset)->caching(false)->fetchDbRows(); } echo "\n"; }
/** * Call this in your helpers to parse the args into a useful array * @method parseArgs * @static * @param {Handlebars_Template} $template * @param {Handlebars_Context} $context * @param {string|array} $args * @return {array} */ static function parseArgs($template, $context, $args) { if (is_array($args)) { return $args; } $parsed = array_merge($template->parseArguments($args), $template->parseNamedArguments($args)); $results = array(); foreach ($parsed as $k => $arg) { $result = $context->get($arg); if (!isset($result)) { try { $result = Q::json_decode($arg); } catch (Exception $e) { } } $results[$k] = $result; } return $results; }
function Users_sessions_delete() { if (empty($_REQUEST["sessionId"])) { throw new Q_Exceptions_RequiredField(array('field' => 'sessionId')); } $session = new Users_Session(); $session->id = $_REQUEST['sessionId']; $session->retrieve(true); $content = Q::json_decode($session->content); $userId = Q::ifset($content, 'Users', 'loggedInUser', 'id', null); $loggedInUserId = Users::loggedInUser(true)->id; if ($userId == $loggedInUserId) { $authorized = true; } else { $app = Q::app(); $roles = Users::roles(); $authorized = !empty($roles["{$app}/admins"]); } if (!$authorized) { throw new Users_Exception_NotAuthorized(); } $session->remove(); Q_Response::setSlot('success', true); }
function Streams_form_post($params = array()) { if (empty($_REQUEST['inputs'])) { throw new Q_Exception_RequiredField(array('field' => 'inputs')); } $inputs = Q::json_decode($_REQUEST['inputs'], true); $user = Users::loggedInUser(true); $r = array_merge($_REQUEST, $params); $streams = array(); foreach ($inputs as $name => $info) { $inputName = "input_{$name}"; if (!isset($r[$inputName])) { continue; } if (!is_array($info) or count($info) < 4) { throw new Q_Exception_WrongValue(array('field' => 'inputs', 'range' => 'array of name => (streamExists, publisherId, streamName, fieldName)')); } list($streamExists, $publisherId, $streamName, $fieldName) = $info; $stream = Streams::fetchOne(null, $publisherId, $streamName); if (!$stream) { if ($user->id !== $publisherId or !Q_Config::get('Streams', 'possibleUserStreams', $streamName, false)) { throw new Users_Exception_NotAuthorized(); } $stream = Streams::create(null, $publisherId, null, array('name' => $streamName)); } $attribute = substr($fieldName, 0, 10) === 'attribute:' ? substr($fieldName, 10) : null; if ($attribute) { $stream->setAttribute($attribute, $r[$inputName]); } else { $stream->{$fieldName} = $r[$inputName]; } $stream->save(); $streams[$stream->name] = $stream; } Q_Response::setSlot('streams', Db::exportArray($streams)); }
/** * Get autocomplete results * @method autocomplete * @static * @param {string} $input The text (typically typed by a user) to find completions for * @param {boolean} [$throwIfBadValue=false] * Whether to throw Q_Exception if the result contains a bad value * @param {array} [$types=array("establishment")] Can include "establishment", "locality", "sublocality", "postal_code", "country", "administrative_area_level_1", "administrative_area_level_2". Set to true to include all types. * @param {double} [$latitude=userLocation] Override the latitude of the coordinates to search around * @param {double} [$longitude=userLocation] Override the longitude of the coordinates to search around * @param {double} [$miles=25] Override the radius, in miles, to search around * @return {Streams_Stream|null} * @throws {Q_Exception} if a bad value is encountered and $throwIfBadValue is true */ static function autocomplete($input, $throwIfBadValue = false, $types = null, $latitude = null, $longitude = null, $miles = 25) { $supportedTypes = array("establishment", "locality", "sublocality", "postal_code", "country", "administrative_area_level_1", "administrative_area_level_2"); $input = strtolower($input); if (is_string($types)) { $types = explode(',', $types); } else { if ($types === true) { $types = null; } } if ($types) { foreach ($types as $type) { if (!in_array($type, $supportedTypes)) { throw new Q_Exception_BadValue(array('internal' => '$types', 'problem' => "{$type} is not supported")); } } } if (empty($input)) { if ($throwIfBadValue) { throw new Q_Exception_RequiredField(array('field' => 'input')); } return null; } if (!isset($latitude) or !isset($longitude)) { if ($uls = Places_Location::userStream()) { $latitude = $uls->getAttribute('latitude', null); $longitude = $uls->getAttribute('longitude', null); if (!isset($miles)) { $miles = $uls->getAttribute('miles', 25); } } else { // put some defaults $latitude = 40.5806032; $longitude = -73.9755244; $miles = 25; } } $pa = null; if (Q_Config::get('Places', 'cache', 'autocomplete', true)) { $pa = new Places_Autocomplete(); $pa->query = $input; $pa->types = $types ? implode(',', $types) : ''; $pa->latitude = $latitude; $pa->longitude = $longitude; $pa->miles = $miles; if ($pa->retrieve()) { $ut = $pa->updatedTime; if (isset($ut)) { $db = $pa->db(); $ut = $db->fromDateTime($ut); $ct = $db->getCurrentTimestamp(); $cd = Q_Config::get('Places', 'cache', 'duration', 60 * 60 * 24 * 30); if ($ct - $ut < $cd) { // there are cached autocomplete results that are still viable return Q::json_decode($pa->results, true); } } } } $key = Q_Config::expect('Places', 'google', 'keys', 'server'); $location = "{$latitude},{$longitude}"; $radius = ceil(1609.34 * $miles); if ($types === null) { unset($types); } $query = http_build_query(compact('key', 'input', 'types', 'location', 'radius')); $url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?{$query}"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $json = curl_exec($ch); curl_close($ch); $response = json_decode($json, true); if (empty($response['predictions'])) { throw new Q_Exception("Places::autocomplete: Couldn't obtain predictions for {$input}"); } if (!empty($response['error_message'])) { throw new Q_Exception("Places::autocomplete: " . $response['error_message']); } $results = $response['predictions']; if ($pa) { $pa->results = json_encode($results); $pa->save(); } return $results; }
/** * @method decode * @static * @protected * @param {string} $tail This can either be JSON, or something that looks like a=b c=d where a, b, c, d are urlencoded * @return {array} */ protected static function decode($tail) { if ($tail[0] === '{' and $result = Q::json_decode($tail, true)) { return $result; } $clauses = explode(' ', $tail); $result = array(); foreach ($clauses as $clause) { list($left, $right) = explode('=', $clause); $right_parts = explode('/', $right); if (count($right_parts) === 1) { $result[urldecode($left)] = urldecode($right); } else { $left_parts = array(); foreach ($right_parts as $rp) { $left_parts[] = urldecode($rp); } $result[urldecode($left)] = $left_parts; } } return $result; }
/** * Download an image from pixabay * @param {string} $keywords Specify some string to search images on pixabay * @param {array} [$options=array()] Any additional options for pixabay api as per its documentation * @param {boolean} [$returnFirstImage=false] If true, downloads and returns the first image as data * @return {string} JSON according to pixabay api documentation */ static function pixabay($keywords, $options = array(), $returnFirstImage = false) { $info = Q_Config::get('Q', 'images', 'pixabay', null); if (!$info['username']) { throw new Q_Exception_MissingConfig(array('fieldpath' => 'Q/images/pixabay/username')); } if (!$info['key']) { throw new Q_Exception_MissingConfig(array('fieldpath' => 'Q/images/pixabay/key')); } $username = $info['username']; $key = $info['key']; $defaults = array(); $options = array_merge($defaults, $options); $optionString = http_build_query($options, '', '&'); $keywords = urlencode(strtolower($keywords)); $url = "http://pixabay.com/api/?username={$username}&key={$key}&q={$keywords}&{$optionString}"; $json = @file_get_contents($url); $data = Q::json_decode($json, true); if (!$returnFirstImage) { return $data; } if (empty($data['hits'][0]['webformatURL'])) { return null; } $webformatUrl = $data['hits'][0]['webformatURL']; $data = @file_get_contents($webformatUrl); return $data; }
/** * Get the names of the possible states * @method states * @static * @return {array} */ static function states() { $column = Base_Streams_Participant::column_state(); return Q::json_decode(str_replace("'", '"', '[' . $column[0][1] . ']')); }
/** * Subscribe to one or more streams, to start receiving notifications. * Posts "Streams/subscribe" message to the streams. * Also posts "Streams/subscribed" messages to user's "Streams/participating" stream. * If options are not given check the subscription templates: * 1. generic publisher id and generic user * 2. exact publisher id and generic user * 3. generic publisher id and exact user * default is to subscribe to ALL messages. * If options are supplied - skip templates and use options. * Using subscribe if subscription is already active will modify existing * subscription - change type(s) or modify notifications * @method subscribe * @static * @param {string} $asUserId The id of the user that is joining. Pass null here to use the logged-in user's id. * @param {string} $publisherId The id of the user publishing all the streams * @param {array} $streams An array of Streams_Stream objects or stream names * @param {array} [$options=array()] * @param {array} [$options.filter] optional array with two keys * @param {array} [$options.filter.types] array of message types, if this is empty then subscribes to all types * @param {array} [$options.filter.notifications=0] limit number of notifications, 0 means no limit * @param {datetime} [$options.untilTime=null] time limit, if any for subscription * @param {array} [$options.rule=array()] optionally override the rule for new subscriptions * @param {array} [$options.rule.deliver=array('to'=>'default')] under "to" key, * named the field under Streams/rules/deliver config, which will contain the names of destinations, * which can include "email", "mobile", "email+pending", "mobile+pending" * @param {datetime} [$options.rule.readyTime] time from which user is ready to receive notifications again * @param {array} [$options.rule.filter] optionally set a filter for the rules to add * @param {boolean} [$options.skipRules] if true, do not attempt to create rules for new subscriptions * @param {boolean} [$options.skipAccess] if true, skip access check for whether user can join and subscribe * @return {array} An array of Streams_Participant rows from the database. */ static function subscribe($asUserId, $publisherId, $streams, $options = array()) { $streams2 = self::_getStreams($asUserId, $publisherId, $streams); $streamNames = array(); foreach ($streams2 as $s) { $streamNames[] = $s->name; } if (empty($options['skipAccess'])) { self::_accessExceptions($streams2, $streamNames, 'join'); } $participants = Streams::join($asUserId, $publisherId, $streams2, array('subscribed' => true, 'noVisit' => true, 'skipAccess' => Q::ifset($options, 'skipAccess', false))); $shouldUpdate = false; if (isset($options['filter'])) { $filter = Q::json_encode($options['filter']); $shouldUpdate = true; } $db = Streams_Subscription::db(); if (isset($options['untilTime'])) { $untilTime = $db->toDateTime($options['untilTime']); $shouldUpdate = true; } $subscriptions = array(); $rows = Streams_Subscription::select('*')->where(array('publisherId' => $publisherId, 'streamName' => $streamNames, 'ofUserId' => $asUserId))->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as $row) { $sn = $row['streamName']; $subscriptions[$sn] = $row; } $messages = array(); $pMessages = array(); $streamNamesMissing = array(); $streamNamesUpdate = array(); foreach ($streamNames as $sn) { $messages[$publisherId][$sn] = array('type' => 'Streams/subscribe'); $pMessages[] = array('type' => 'Streams/subscribed', 'instructions' => array('publisherId' => $publisherId, 'streamName' => $sn)); if (empty($subscriptions[$sn])) { $streamNamesMissing[] = $sn; continue; } if ($shouldUpdate) { $streamNamesUpdate[] = $sn; } } if ($streamNamesUpdate) { Streams_Subscription::update()->set(compact('filter', 'untilTime'))->where(array('publisherId' => $publisherId, 'streamName' => $streamNamesUpdate, 'ofUserId' => $asUserId))->execute(); } $rules = array(); if ($streamNamesMissing) { $types = array(); foreach ($streamNamesMissing as $sn) { $stream = $streams2[$sn]; $types[$stream->type][] = $sn; } $subscriptionRows = array(); $ruleRows = array(); foreach ($types as $type => $sns) { // insert subscriptions if (!isset($filter) or !isset($untilTime)) { $templates = Streams_Subscription::select('*')->where(array('publisherId' => array('', $publisherId), 'streamName' => $type . '/', 'ofUserId' => array('', $asUserId)))->fetchAll(PDO::FETCH_ASSOC); $template = null; foreach ($templates as $t) { if (!$template or $template['publisherId'] == '' and $t['publisherId'] !== '' or $template['userId'] == '' and $t['userId'] !== '') { $template = $t; } } } if (!isset($filter)) { $filter = Q::json_encode($template ? Q::json_decode($template['filter']) : Streams_Stream::getConfigField($type, array('subscriptions', 'filter'), array("types" => array("^(?!(Users/)|(Streams/)).*/", "Streams/relatedTo", "Streams/chat/message"), "notifications" => 0))); } if (!isset($untilTime)) { $untilTime = ($template and $template['duration'] > 0) ? new Db_Expression("CURRENT_TIMESTAMP + INTERVAL {$template['duration']} SECOND") : null; } foreach ($sns as $sn) { $subscriptions[$sn] = $subscriptionRows[] = new Streams_Subscription(array('publisherId' => $publisherId, 'streamName' => $sn, 'ofUserId' => $asUserId, 'untilTime' => $untilTime, 'filter' => $filter)); } if (!empty($options['skipRules'])) { continue; } // insert up to one rule per subscription $rule = null; if (isset($options['rule'])) { $rule = $options['rule']; if (isset($rule['readyTime'])) { $rule['readyTime'] = $db->toDateTime($rule['readyTime']); } if (isset($rule['filter']) and is_array($rule['filter'])) { $rule['filter'] = Q::json_encode($rule['filter']); } if (isset($rule['deliver']) and is_array($rule['deliver'])) { $rule['deliver'] = Q::json_encode($rule['deliver']); } } if (!isset($rule)) { $templates = Streams_Rule::select('*')->where(array('ofUserId' => array('', $asUserId), 'publisherId' => array('', $publisherId), 'streamName' => $type . '/', 'ordinal' => 1))->fetchAll(PDO::FETCH_ASSOC); foreach ($templates as $t) { if (!$rule or $rule['userId'] == '' and $t['userId'] !== '' or $rule['publisherId'] == '' and $t['publisherId'] !== '') { $rule = $t; } } } if (!isset($rule)) { $rule = array('deliver' => '{"to": "default"}', 'filter' => '{"types": [], "labels": []}'); } if ($rule) { $rule['ofUserId'] = $asUserId; $rule['publisherId'] = $publisherId; if (empty($rule['readyTime'])) { $rule['readyTime'] = new Db_Expression("CURRENT_TIMESTAMP"); } foreach ($sns as $sn) { $row = $rule; $row['streamName'] = $sn; $row['ordinal'] = 1; $row['filter'] = ''; $rules[$sn] = $ruleRows[] = $row; $messages[$publisherId][$sn]['instructions'] = Q::json_encode(array('rule' => $row)); } } } Streams_Subscription::insertManyAndExecute($subscriptionRows); Streams_Rule::insertManyAndExecute($ruleRows); } foreach ($streamNames as $sn) { $subscription = $subscriptions[$sn]; $stream = $streams2[$sn]; // skip error testing for rule save BUT inform node. // Node can notify user to check the rules Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/subscribe", "subscription" => Q::json_encode($subscription), "stream" => Q::json_encode($stream->toArray()), "rule" => isset($rules[$sn]) ? Q::json_encode($rules[$sn]) : null)); } Streams_Message::postMessages($asUserId, $messages, true); Streams_Message::postMessages($asUserId, array($asUserId => array('Streams/participating' => $pMessages)), true); return $participants; }
/** * Method is called before setting the field and verifies that, if it is a string, * it contains a JSON array. * @method beforeSet_permissions * @param {string} $value * @return {array} An array of field name and value * @throws {Exception} An exception is thrown if $value is not string or is exceedingly long */ function beforeSet_permissions($value) { if (is_string($value)) { $decoded = Q::json_decode($value, true); if (!is_array($decoded) or Q::isAssociative($decoded)) { throw new Q_Exception_WrongValue(array('field' => 'permissions', 'range' => 'JSON array')); } } return parent::beforeSet_permissions($value); }
/** * Loads data from JSON found in a file * @method load * @param {string} $filename The filename of the file to load. * @param {boolean} $ignoreCache=false * Defaults to false. If true, then this function ignores * the cached value, if any, and attempts to search * for the file. It will cache the new value. * @return {boolean} Returns true if loaded, otherwise false. * @throws {Q_Exception_InvalidInput} */ function load($filename, $ignoreCache = false) { $filename2 = Q::realPath($filename, $ignoreCache); if (!$filename2) { return false; } $this->filename = $filename2; // if class cache is set - use it if (isset(self::$cache[$filename2])) { $this->merge(self::$cache[$filename2]); return true; } // check Q_Cache and if set - use it // update class cache as it is not set $arr = Q_Cache::get("Q_Tree\t{$filename2}"); if (isset($arr)) { self::$cache[$filename2] = $arr; $this->merge($arr); return true; } /** * @event Q/tree/load {before} * @param {string} filename * @return {array} */ $arr = Q::event('Q/tree/load', compact('filename'), 'before'); if (!isset($arr)) { try { // get file contents, remove comments and parse $json = file_get_contents($filename2); $json = preg_replace('/\\s*(?!<\\")\\/\\*[^\\*]+\\*\\/(?!\\")\\s*/', '', $json); $arr = Q::json_decode($json, true); } catch (Exception $e) { $arr = null; } } if (!isset($arr)) { throw new Q_Exception_InvalidInput(array('source' => $filename)); } if (!is_array($arr)) { return false; } // $arr was loaded from $filename2 or by Q/tree/load before event $this->merge($arr); self::$cache[$filename2] = $arr; Q_Cache::set("Q_Tree\t{$filename2}", $arr); // no need to check result - on failure Q_Cache is disabled return true; }
function Assets_after_Assets_charge($params) { $user = $payments = $amount = $currency = $charge = $adapter = $options = null; extract($params, EXTR_OVERWRITE); $description = 'a product or service'; $stream = Q::ifset($options, 'stream', null); if ($stream) { $publisherId = $stream->publisherId; $publisher = Users_User::fetch($publisherId, true); if ($stream->type === 'Assets/subscription') { $plan = Streams::fetchOne($stream->getAttribute('planPublisherId'), $stream->getAttribute('planPublisherId'), $stream->getAttribute('planStreamName'), true); $months = $stream->getAttribute('months'); $startDate = $stream->getAttribute('startDate'); $endDate = $stream->getAttribute('endDate'); } $description = $stream->title; } else { $publisherId = Users::communityId(); $publisher = Users_User::fetch($publisherId, true); } if (isset($options['description'])) { $description = $options['description']; } $currencies = Q::json_decode(file_get_contents(ASSETS_PLUGIN_CONFIG_DIR . DS . 'currencies.json'), true); if (!isset($currencies['symbols'][$currency])) { throw new Q_Exception_BadValue(array('internal' => 'currency', 'problem' => 'no symbol found'), 'currency'); } if (!isset($currencies['names'][$currency])) { throw new Q_Exception_BadValue(array('internal' => 'currency', 'problem' => 'no name found'), 'currency'); } $symbol = $currencies['symbols'][$currency]; $currencyName = $currencies['names'][$currency]; $communityId = Users::communityId(); $communityName = Users::communityName(); $communitySuffix = Users::communitySuffix(); $link = Q_Request::baseUrl('action.php') . "/Assets/payment?publisherId={$publisherId}&userId=" . $user->id; $fields = compact('user', 'publisher', 'publisherId', 'communityId', 'communityName', 'communitySuffix', 'description', 'subscription', 'stream', 'plan', 'currency', 'name', 'symbol', 'currencyName', 'amount', 'months', 'startDate', 'endDate', 'link'); if ($user->emailAddress) { $email = new Users_Email(); $email->address = $user->emailAddress; $email->retrieve(true); $emailSubject = Q_Config::get('Assets', 'transactional', 'charged', 'subject', false); $emailView = Q_Config::get('Assets', 'transactional', 'charged', 'body', false); if ($emailSubject !== false and $emailView) { $email->sendMessage($emailSubject, $emailView, $fields); } } else { if ($user->mobileNumber) { $mobile = new Users_Mobile(); $mobile->number = $user->mobileNumber; $mobile->retrieve(true); if ($mobileView = Q_Config::get('Assets', 'transactional', 'charged', 'sms', false)) { $mobile->sendMessage($mobileView, $fields); } } } if ($publisher->emailAddress) { $email = new Users_Email(); $email->address = $publisher->emailAddress; $email->retrieve(true); $emailSubject = Q_Config::get('Assets', 'transactional', 'charge', 'subject', false); $emailView = Q_Config::get('Assets', 'transactional', 'charge', 'body', false); if ($emailSubject !== false and $emailView) { $email->sendMessage($emailSubject, $emailView, $fields); } } else { if ($publisher->mobileNumber) { $mobile = new Users_Mobile(); $mobile->number = $publisher->mobileNumber; $mobile->retrieve(true); if ($mobileView = Q_Config::get('Assets', 'transactional', 'charge', 'sms', false)) { $mobile->sendMessage($mobileView, $fields); } } } }