- &$profiles: Profiles that were pre-filled
- $avatarSize: The avatar size for the list
+OtherAccountProfiles: Hook to add account profiles to a user account profile block
+- $profile: the Profile being shown
+- &$others: Modifiable array of profile info arrays. Each one has the following fields:
+ href: link to the profile
+ text: text for the profile
+ image: mini image for the profile
$this->since_id = $this->trimmed('since_id');
$this->geocode = $this->trimmed('geocode');
+ if (!empty($this->auth_user)) {
+ $this->auth_profile = $this->auth_user->getProfile();
+ } else {
+ $this->auth_profile = null;
+ }
+
return true;
}
*/
function showResults()
{
- // TODO: Support search operators like from: and to:, boolean, etc.
+ $q = strtolower($this->query);
- $notice = new Notice();
+ // TODO: Support search operators like from: and to:, boolean, etc.
- // lcase it for comparison
- $q = strtolower($this->query);
+ if (preg_match('/^#([\pL\pN_\-\.]{1,64})$/ue', $q)) {
+ $stream = new TagNoticeStream(substr($q, 1), $this->auth_profile);
+ } else if ($this->isAnURL($q)) {
+ $canon = File_redirection::_canonUrl($q);
+ $file = File::staticGet('url', $canon);
+ if (!empty($file)) {
+ $stream = new FileNoticeStream($file, $this->auth_profile);
+ }
+ } else {
+ $stream = new SearchNoticeStream($q, $this->auth_profile);
+ }
- $search_engine = $notice->getSearchEngine('notice');
- $search_engine->set_sort_mode('chron');
- $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true);
- if (false === $search_engine->query($q)) {
- $cnt = 0;
+ if (empty($stream)) {
+ // XXX: This is hackish, but need some simple way to say "There's no results"
+ $notice = new ArrayWrapper(array());
} else {
- $cnt = $notice->find();
+ $notice = $stream->getNotices(($this->page - 1) * $this->rpp, $this->rpp + 1);
}
// TODO: max_id, lang, geocode
$this->endDocument('json');
}
+ function isAnURL($q) {
+ $regex = '#^'.
+ '(?:^|[\s\<\>\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'.
+ '('.
+ '(?:'.
+ '(?:'. //Known protocols
+ '(?:'.
+ '(?:(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|irc)://)'.
+ '|'.
+ '(?:(?:mailto|aim|tel|xmpp):)'.
+ ')'.
+ '(?:[\pN\pL\-\_\+\%\~]+(?::[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
+ '(?:'.
+ '(?:'.
+ '\[[\pN\pL\-\_\:\.]+(?<![\.\:])\]'. //[dns]
+ ')|(?:'.
+ '[\pN\pL\-\_\:\.]+(?<![\.\:])'. //dns
+ ')'.
+ ')'.
+ ')'.
+ '|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4
+ '|(?:'. //IPv6
+ '\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?<!:)'.
+ ')|(?:'. //DNS
+ '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
+ '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
+ //tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
+ '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZW|local|loc|onion)'.
+ ')(?![\pN\pL\-\_])'.
+ ')'.
+ '(?:'.
+ '(?:\:\d+)?'. //:port
+ '(?:/[\pN\pL$\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'@]*)?'. // /path
+ '(?:\?[\pN\pL\$\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'@\/]*)?'. // ?query string
+ '(?:\#[\pN\pL$\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'\@/\?\#]*)?'. // #fragment
+ ')(?<![\?\.\,\#\,])'.
+ ')'.
+ '$#ixu';
+ return preg_match($regex, $q);
+ }
+
/**
* Do we need to write to the database?
*
$cnt = $member_list->show();
}
- $members->free();
-
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
$this->page, 'groupmembers',
array('nickname' => $this->group->nickname));
function asActivity()
{
$member = $this->getMember();
+
+ if (!$member) {
+ throw new Exception("No such member: " . $this->profile_id);
+ }
+
$group = $this->getGroup();
+ if (!$group) {
+ throw new Exception("No such group: " . $this->group_id);
+ }
+
$act = new Activity();
$act->id = $this->getURI();
}
$act->actor = ActivityObject::fromProfile($profile);
- $act->actor->extra[] = $profile->profileInfo();
+ $act->actor->extra[] = $profile->profileInfo(null);
$act->verb = ActivityVerb::POST;
}
foreach ($ni as $id => $source) {
- $user = User::staticGet('id', $id);
- if (empty($user) || $user->hasBlocked($profile) ||
- ($originalProfile && $user->hasBlocked($originalProfile))) {
+ try {
+ $user = User::staticGet('id', $id);
+ if (empty($user) ||
+ $user->hasBlocked($profile) ||
+ ($originalProfile && $user->hasBlocked($originalProfile))) {
+ unset($ni[$id]);
+ }
+ } catch (UserNoProfileException $e) {
+ // User doesn't have a profile; invalid; skip them.
unset($ni[$id]);
}
}
* @return Activity activity object representing this Notice.
*/
- function asActivity($cur)
+ function asActivity($cur=null)
{
$act = self::cacheGet(Cache::codeKey('notice:as-activity:'.$this->id));
if (Event::handle('StartJoinGroup', array($group, $this))) {
$join = Group_member::join($group->id, $this->id);
self::blow('profile:groups:%d', $this->id);
+ self::blow('group:member_ids:%d', $group->id);
+ self::blow('group:member_count:%d', $group->id);
Event::handle('EndJoinGroup', array($group, $this));
}
}
if (Event::handle('StartLeaveGroup', array($group, $this))) {
Group_member::leave($group->id, $this->id);
self::blow('profile:groups:%d', $this->id);
+ self::blow('group:member_ids:%d', $group->id);
+ self::blow('group:member_count:%d', $group->id);
Event::handle('EndLeaveGroup', array($group, $this));
}
}
'subscription_token_idx' => array('token'),
),
);
- }
+ }
/* Static get */
function staticGet($k,$v=null)
$subscriber = Profile::staticGet('id', $this->subscriber);
$subscribed = Profile::staticGet('id', $this->subscribed);
+ if (empty($subscriber)) {
+ throw new Exception(sprintf(_('No profile for the subscriber: %d'), $this->subscriber));
+ }
+
+ if (empty($subscribed)) {
+ throw new Exception(sprintf(_('No profile for the subscribed: %d'), $this->subscribed));
+ }
+
$act = new Activity();
$act->verb = ActivityVerb::FOLLOW;
{
const JOIN_POLICY_OPEN = 0;
const JOIN_POLICY_MODERATE = 1;
+ const CACHE_WINDOW = 201;
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
return !in_array($nickname, $blacklist);
}
- function getMembers($offset=0, $limit=null)
+ function getMembers($offset=0, $limit=null) {
+ $ids = null;
+ if (is_null($limit) || $offset + $limit > User_group::CACHE_WINDOW) {
+ $ids = $this->getMemberIDs($offset,
+ $limit);
+ } else {
+ $key = sprintf('group:member_ids:%d', $this->id);
+ $window = self::cacheGet($key);
+ if ($window === false) {
+ $window = $this->getMemberIDs(0,
+ User_group::CACHE_WINDOW);
+ self::cacheSet($key, $window);
+ }
+
+ $ids = array_slice($window,
+ $offset,
+ $limit);
+ }
+
+ return Profile::multiGet('id', $ids);
+ }
+
+ function getMemberIDs($offset=0, $limit=null)
{
- $qry =
- 'SELECT profile.* ' .
- 'FROM profile JOIN group_member '.
- 'ON profile.id = group_member.profile_id ' .
- 'WHERE group_member.group_id = %d ' .
- 'ORDER BY group_member.created DESC ';
+ $gm = new Group_member();
- if ($limit != null) {
- if (common_config('db','type') == 'pgsql') {
- $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
- } else {
- $qry .= ' LIMIT ' . $offset . ', ' . $limit;
- }
+ $gm->selectAdd();
+ $gm->selectAdd('profile_id');
+
+ $gm->group_id = $this->id;
+
+ $gm->orderBy('created DESC');
+
+ if (!is_null($limit)) {
+ $gm->limit($offset, $limit);
}
- $members = new Profile();
+ $ids = array();
- $members->query(sprintf($qry, $this->id));
- return $members;
+ if ($gm->find()) {
+ while ($gm->fetch()) {
+ $ids[] = $gm->profile_id;
+ }
+ }
+
+ return $ids;
}
/**
function getMemberCount()
{
- // XXX: WORM cache this
+ $key = sprintf("group:member_count:%d", $this->id);
- $members = $this->getMembers();
- $member_count = 0;
+ $cnt = self::cacheGet($key);
- /** $member->count() doesn't work. */
- while ($members->fetch()) {
- $member_count++;
+ if (is_integer($cnt)) {
+ return (int) $cnt;
}
- return $member_count;
+ $mem = new Group_member();
+ $mem->group_id = $this->id;
+
+ // XXX: why 'distinct'?
+
+ $cnt = (int) $mem->count('distinct profile_id');
+
+ self::cacheSet($key, $cnt);
+
+ return $cnt;
}
function getBlockedCount()
return $this->profile->bio;
}
+ function otherProfiles()
+ {
+ $others = array();
+
+ Event::handle('OtherAccountProfiles', array($this->profile, &$others));
+
+ return $others;
+ }
+
function showTags()
{
$cur = common_current_user();
if ($object instanceof Activity) {
// Sharing a post activity is more like sharing the original object
- if ($this->verb == 'share' && $object->verb == 'post') {
+ if (ActivityVerb::canonical($this->verb) == ActivityVerb::canonical(ActivityVerb::SHARE) &&
+ ActivityVerb::canonical($object->verb) == ActivityVerb::canonical(ActivityVerb::POST)) {
// XXX: Here's one for the obfuscation record books
$object = $object->objects[0];
}
list($lat, $lon) = explode(' ', $this->geopoint);
- $object['location'] = array(
- 'objectType' => 'place',
- 'position' => sprintf("%+02.5F%+03.5F/", $lat, $lon),
- 'lat' => $lat,
- 'lon' => $lon
- );
+ if (!empty($lat) && !empty($lon)) {
+ $object['location'] = array(
+ 'objectType' => 'place',
+ 'position' => sprintf("%+02.5F%+03.5F/", $lat, $lon),
+ 'lat' => $lat,
+ 'lon' => $lon
+ );
- $loc = Location::fromLatLon($lat, $lon);
+ $loc = Location::fromLatLon((float)$lat, (float)$lon);
- if ($loc) {
- $name = $loc->getName();
+ if ($loc) {
+ $name = $loc->getName();
- if ($name) {
- $object['location']['displayName'] = $name;
- }
- $url = $loc->getURL();
+ if ($name) {
+ $object['location']['displayName'] = $name;
+ }
+ $url = $loc->getURL();
- if ($url) {
- $object['location']['url'] = $url;
+ if ($url) {
+ $object['location']['url'] = $url;
+ }
}
}
}
{
return null;
}
+
+ function otherProfiles()
+ {
+ return array();
+ }
}
\ No newline at end of file
$profile = Profile::current();
}
parent::__construct(new CachingNoticeStream(new RawFileNoticeStream($file),
- 'file:notice-ids:'.$this->url),
+ 'file:notice-ids:'.$file->id),
$profile);
}
}
return $this->group->description;
}
+ function otherProfiles()
+ {
+ return array();
+ }
+
function showActions()
{
$cur = common_current_user();
$this->id = $this->notice->id;
$this->from_user_id = $this->profile->id;
- $user = User::staticGet('id', $this->profile->id);
-
- $this->iso_language_code = $user->language;
+ $user = $this->profile->getUser();
+ if (empty($user)) {
+ // Gonna have to do till we can detect it
+ $this->iso_language_code = common_config('site', 'language');
+ } else {
+ $this->iso_language_code = $user->language;
+ }
+
$this->source = $this->getSourceLink($this->notice->source);
$avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE);
$this->showName();
$this->showLocation();
$this->showHomepage();
+ $this->showOtherProfiles();
$this->showDescription();
$this->showTags();
}
}
}
+ function showOtherProfiles()
+ {
+ $otherProfiles = $this->otherProfiles();
+
+ if (!empty($otherProfiles)) {
+
+ $this->out->elementStart('ul',
+ array('class' => 'profile_block_otherprofile_list'));
+
+ foreach ($otherProfiles as $otherProfile) {
+ $this->out->elementStart('li');
+ $this->out->elementStart('a',
+ array('href' => $otherProfile['href'],
+ 'rel' => 'me',
+ 'class' => 'profile_block_otherprofile',
+ 'title' => $otherProfile['text']));
+ $this->out->element('img',
+ array('src' => $otherProfile['image'],
+ 'class' => 'profile_block_otherprofile_icon'));
+ $this->out->elementEnd('a');
+ $this->out->elementEnd('li');
+ }
+
+ $this->out->elementEnd('ul');
+ }
+ }
+
function avatarSize()
{
return AVATAR_PROFILE_SIZE;
),
'plugins' => array(
'default' => array(
- 'Activity' => null,
'Bookmark' => null,
'ClientSideShorten' => null,
'Directory' => null,
),
'plugins' => array(
'default' => array(
- 'Activity' => null,
'Bookmark' => null,
'ClientSideShorten' => null,
'Directory' => null,
),
'plugins' => array(
'default' => array(
- 'Activity' => null,
'Bookmark' => null,
'ClientSideShorten' => null,
'Directory' => null,
),
'plugins' => array(
'default' => array(
- 'Activity' => null,
'Bookmark' => null,
'ClientSideShorten' => null,
'Event' => null,
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2013 StatusNet, Inc.
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
+
+$shortoptions = 'i:n:a';
+$longoptions = array('id=', 'nickname=', 'all');
+
+$helptext = <<<END_OF_SILENCESPAMMER_HELP
+silencespammer.php [options]
+Users who post a lot of spam get silenced
+
+ -i --id ID of user to test and silence
+ -n --nickname nickname of the user to test and silence
+ -a --all All users
+END_OF_SILENCESPAMMER_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+function testAllUsers($filter, $minimum, $percent) {
+ $found = false;
+ $offset = 0;
+ $limit = 1000;
+
+ do {
+
+ $user = new User();
+ $user->orderBy('created');
+ $user->limit($offset, $limit);
+
+ $found = $user->find();
+
+ if ($found) {
+ while ($user->fetch()) {
+ try {
+ silencespammer($filter, $user, $minimum, $percent);
+ } catch (Exception $e) {
+ printfnq("ERROR testing user %s\n: %s", $user->nickname, $e->getMessage());
+ }
+ }
+ $offset += $found;
+ }
+
+ } while ($found > 0);
+}
+
+function silencespammer($filter, $user, $minimum, $percent) {
+
+ printfnq("Testing user %s\n", $user->nickname);
+
+ $profile = Profile::staticGet('id', $user->id);
+
+ if ($profile->isSilenced()) {
+ printfnq("Already silenced %s\n", $user->nickname);
+ return;
+ }
+
+ $cnt = $profile->noticeCount();
+
+ if ($cnt < $minimum) {
+ printfnq("Only %d notices posted (minimum %d); skipping\n", $cnt, $minimum);
+ return;
+ }
+
+ $ss = new Spam_score();
+
+ $ss->query(sprintf("SELECT count(*) as spam_count ".
+ "FROM notice join spam_score on notice.id = spam_score.notice_id ".
+ "WHERE notice.profile_id = %d AND spam_score.is_spam = 1", $profile->id));
+
+ while ($ss->fetch()) {
+ $spam_count = $ss->spam_count;
+ }
+
+ $spam_percent = ($spam_count * 100.0 / $cnt);
+
+ if ($spam_percent > $percent) {
+ printfnq("Silencing user %s (%d/%d = %0.2f%% spam)\n", $user->nickname, $spam_count, $cnt, $spam_percent);
+ try {
+ $profile->silence();
+ } catch(Exception $e) {
+ printfnq("Error: %s", $e->getMessage());
+ }
+ }
+}
+
+try {
+ $filter = null;
+ $minimum = 5;
+ $percent = 80;
+ Event::handle('GetSpamFilter', array(&$filter));
+ if (empty($filter)) {
+ throw new Exception(_("No spam filter."));
+ }
+ if (have_option('a', 'all')) {
+ testAllUsers($filter, $minimum, $percent);
+ } else {
+ $user = getUser();
+ silencespammer($filter, $user, $minimum, $percent);
+ }
+} catch (Exception $e) {
+ print $e->getMessage()."\n";
+ exit(1);
+}
return true;
}
+ /**
+ * Add links in the user's profile block to their Facebook profile URL.
+ *
+ * @param Profile $profile The profile being shown
+ * @param Array &$links Writeable array of arrays (href, text, image).
+ *
+ * @return boolean hook value (true)
+ */
+
+ function onOtherAccountProfiles($profile, &$links)
+ {
+ $fuser = null;
+
+ $flink = Foreign_link::getByUserID($profile->id, FACEBOOK_SERVICE);
+
+ if (!empty($flink)) {
+
+ $fuser = $this->getFacebookUser($flink->foreign_id);
+
+ if (!empty($fuser)) {
+ $links[] = array("href" => $fuser->link,
+ "text" => sprintf(_("%s on Facebook"), $fuser->name),
+ "image" => $this->path("images/f_logo.png"));
+ }
+ }
+
+ return true;
+ }
+
+ function getFacebookUser($id) {
+
+ $key = Cache::key(sprintf("FacebookBridgePlugin:userdata:%s", $id));
+
+ $c = Cache::instance();
+
+ if ($c) {
+ $obj = $c->get($key);
+ if ($obj) {
+ return $obj;
+ }
+ }
+
+ $url = sprintf("https://graph.facebook.com/%s", $id);
+ $client = new HTTPClient();
+ $resp = $client->get($url);
+
+ if (!$resp->isOK()) {
+ return null;
+ }
+
+ $user = json_decode($resp->getBody());
+
+ if ($user->error) {
+ return null;
+ }
+
+ if ($c) {
+ $c->set($key, $user);
+ }
+
+ return $user;
+ }
+
/*
* Add version info for this plugin
*
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * ModLog.php -- data object to store moderation logs
+ *
+ * PHP version 5
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Moderation
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Class comment here
+ *
+ * @category Category here
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class ModLog extends Managed_DataObject
+{
+ public $__table = 'mod_log'; // table name
+
+ public $id; // UUID
+ public $profile_id; // profile id
+ public $moderator_id; // profile id
+ public $role; // the role
+ public $grant; // 1 = grant, 0 = revoke
+ public $created; // datetime
+
+ /**
+ * Get an instance by key
+ *
+ * @param string $k Key to use to lookup (usually 'user_id' for this class)
+ * @param mixed $v Value to lookup
+ *
+ * @return TagSub object found, or null for no hits
+ *
+ */
+ function staticGet($k, $v=null)
+ {
+ return Managed_DataObject::staticGet('ModLog', $k, $v);
+ }
+
+ /**
+ * Get an instance by compound key
+ *
+ * @param array $kv array of key-value mappings
+ *
+ * @return TagSub object found, or null for no hits
+ *
+ */
+ function pkeyGet($kv)
+ {
+ return Managed_DataObject::pkeyGet('ModLog', $kv);
+ }
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array('description' => 'Log of moderation events',
+ 'fields' => array(
+ 'id' => array('type' => 'varchar',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'unique event ID'),
+ 'profile_id' => array('type' => 'int',
+ 'not null' => true,
+ 'description' => 'profile getting the role'),
+ 'moderator_id' => array('type' => 'int',
+ 'description' => 'profile granting or revoking the role'),
+ 'role' => array('type' => 'varchar',
+ 'length' => 32,
+ 'not null' => true,
+ 'description' => 'role granted or revoked'),
+ 'is_grant' => array('type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 1,
+ 'description' => 'Was this a grant or revocation of a role'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created')
+ ),
+ 'primary key' => array('id'),
+ 'foreign keys' => array(
+ 'mod_log_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
+ 'mod_log_moderator_id_fkey' => array('user', array('user_id' => 'id'))
+ ),
+ 'indexes' => array(
+ 'mod_log_profile_id_created_idx' => array('profile_id', 'created'),
+ ),
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * ModLogPlugin.php
+ *
+ * PHP version 5
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Moderation
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Moderation logging
+ *
+ * Shows a history of moderation for this user in the sidebar
+ *
+ * @category Moderation
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class ModLogPlugin extends Plugin
+{
+ const VIEWMODLOG = 'ModLogPlugin::VIEWMODLOG';
+
+ /**
+ * Database schema setup
+ *
+ * We keep a moderation log table
+ *
+ * @see Schema
+ * @see ColumnDef
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ */
+
+ function onCheckSchema()
+ {
+ $schema = Schema::get();
+
+ $schema->ensureTable('mod_log', ModLog::schemaDef());
+
+ return true;
+ }
+
+ /**
+ * Load related modules when needed
+ *
+ * @param string $cls Name of the class to be loaded
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ */
+
+ function onAutoload($cls)
+ {
+ $dir = dirname(__FILE__);
+
+ switch ($cls)
+ {
+ case 'ModLog':
+ include_once $dir . '/'.$cls.'.php';
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ function onEndGrantRole($profile, $role)
+ {
+ $modlog = new ModLog();
+
+ $modlog->id = UUID::gen();
+ $modlog->profile_id = $profile->id;
+
+ $cur = common_current_user();
+
+ if (!empty($cur)) {
+ $modlog->moderator_id = $cur->id;
+ }
+
+ $modlog->role = $role;
+ $modlog->is_grant = 1;
+ $modlog->created = common_sql_now();
+
+ $modlog->insert();
+
+ return true;
+ }
+
+ function onEndRevokeRole($profile, $role)
+ {
+ $modlog = new ModLog();
+
+ $modlog->id = UUID::gen();
+
+ $modlog->profile_id = $profile->id;
+
+ $cur = common_current_user();
+
+ if (!empty($cur)) {
+ $modlog->moderator_id = $cur->id;
+ }
+
+ $modlog->role = $role;
+ $modlog->is_grant = 0;
+ $modlog->created = common_sql_now();
+
+ $modlog->insert();
+
+ return true;
+ }
+
+ function onEndShowSections($action)
+ {
+ if ($action->arg('action') != 'showstream') {
+ return true;
+ }
+
+ $cur = common_current_user();
+
+ if (empty($cur) || !$cur->hasRight(self::VIEWMODLOG)) {
+ return true;
+ }
+
+ $profile = $action->profile;
+
+ $ml = new ModLog();
+
+ $ml->profile_id = $profile->id;
+ $ml->orderBy("created");
+
+ $cnt = $ml->find();
+
+ if ($cnt > 0) {
+
+ $action->elementStart('div', array('id' => 'entity_mod_log',
+ 'class' => 'section'));
+
+ $action->element('h2', null, _('Moderation'));
+
+ $action->elementStart('table');
+
+ while ($ml->fetch()) {
+ $action->elementStart('tr');
+ $action->element('td', null, strftime('%y-%m-%d', strtotime($ml->created)));
+ $action->element('td', null, sprintf(($ml->is_grant) ? _('+%s') : _('-%s'), $ml->role));
+ $action->elementStart('td');
+ if ($ml->moderator_id) {
+ $mod = Profile::staticGet('id', $ml->moderator_id);
+ if (empty($mod)) {
+ $action->text(_('[unknown]'));
+ } else {
+ $action->element('a', array('href' => $mod->profileurl,
+ 'title' => $mod->fullname),
+ $mod->nickname);
+ }
+ } else {
+ $action->text(_('[unknown]'));
+ }
+ $action->elementEnd('td');
+ $action->elementEnd('tr');
+ }
+
+ $action->elementEnd('table');
+
+ $action->elementEnd('div');
+ }
+ }
+
+ function onUserRightsCheck($profile, $right, &$result) {
+ switch ($right) {
+ case self::VIEWMODLOG:
+ $result = ($profile->hasRole(Profile_role::MODERATOR) || $profile->hasRole('modhelper'));
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ function onPluginVersion(&$versions)
+ {
+ $versions[] = array('name' => 'ModLog',
+ 'version' => STATUSNET_VERSION,
+ 'author' => 'Evan Prodromou',
+ 'homepage' => 'http://status.net/wiki/Plugin:ModLog',
+ 'description' =>
+ _m('Show the moderation history for a profile in the sidebar'));
+ return true;
+ }
+}
try {
$user->joinGroup($group);
} catch (Exception $e) {
+ common_log(LOG_ERR, "Exception on remote group join: " . $e->getMessage());
+ common_log(LOG_ERR, $e->getTraceAsString());
// TRANS: OStatus remote group subscription dialog error.
$this->showForm(_m('Remote group join failed!'));
return;
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
$shortoptions = 'u:a';
$longoptions = array('uri=', 'all');
* @category Plugin
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
- * @author Craig Andrews <candrews@integralblue.com>
+ * @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009-2010 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
require_once dirname(__FILE__) . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
return false;
case 'User_openid':
- require_once dirname(__FILE__) . '/User_openid.php';
- return false;
+ case 'User_openid_prefs':
case 'User_openid_trustroot':
- require_once dirname(__FILE__) . '/User_openid_trustroot.php';
+ require_once dirname(__FILE__) . '/' . $cls . '.php';
return false;
case 'Auth_OpenID_TeamsExtension':
case 'Auth_OpenID_TeamsRequest':
null, false),
new ColumnDef('modified', 'timestamp')));
+ $schema->ensureTable('user_openid_prefs', User_openid_prefs::schemaDef());
+
/* These are used by JanRain OpenID library */
$schema->ensureTable('oid_associations',
return true;
}
+
+ /**
+ * Add links in the user's profile block to their OpenID URLs.
+ *
+ * @param Profile $profile The profile being shown
+ * @param Array &$links Writeable array of arrays (href, text, image).
+ *
+ * @return boolean hook value (true)
+ */
+
+ function onOtherAccountProfiles($profile, &$links)
+ {
+ $prefs = User_openid_prefs::staticGet('user_id', $profile->id);
+
+ if (empty($prefs) || !$prefs->hide_profile_link) {
+
+ $oid = new User_openid();
+
+ $oid->user_id = $profile->id;
+
+ if ($oid->find()) {
+ while ($oid->fetch()) {
+ $links[] = array('href' => $oid->display,
+ 'text' => _('OpenID'),
+ 'image' => $this->path("icons/openid-16x16.gif"));
+ }
+ }
+ }
+
+ return true;
+ }
}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * User_openid_prefs.php
+ *
+ * PHP version 5
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category OpenID
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Store preferences for OpenID use in StatusNet
+ *
+ * @category OpenID
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class User_openid_prefs extends Managed_DataObject
+{
+ public $__table = 'user_openid_prefs'; // table name
+
+ public $user_id; // The User with the prefs
+ public $hide_profile_link; // Hide the link on the profile block?
+ public $created; // datetime
+ public $modified; // datetime
+
+ /**
+ * Get an instance by key
+ *
+ * This is a utility method to get a single instance with a given key value.
+ *
+ * @param string $k Key to use to lookup (usually 'user_id' for this class)
+ * @param mixed $v Value to lookup
+ *
+ * @return TagSub object found, or null for no hits
+ *
+ */
+ function staticGet($k, $v=null)
+ {
+ return Managed_DataObject::staticGet('User_openid_prefs', $k, $v);
+ }
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Per-user preferences for OpenID display',
+ 'fields' => array('user_id' => array('type' => 'integer',
+ 'not null' => true,
+ 'description' => 'User whose prefs we are saving'),
+ 'hide_profile_link' => array('type' => 'int',
+ 'not null' => true,
+ 'default' => 0,
+ 'description' => 'Whether to hide profile links from profile block'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id'),
+ 'foreign keys' => array('user_openid_prefs_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ 'indexes' => array(),
+ );
+ }
+}
// TRANS: Button text to remove an OpenID trustroot.
'value' => _m('BUTTON','Remove')));
$this->elementEnd('fieldset');
+
+ $prefs = User_openid_prefs::staticGet('user_id', $user->id);
+
+ $this->elementStart('fieldset');
+ $this->element('legend', null, _m('LEGEND','Preferences'));
+ $this->elementStart('ul', 'form_data');
+ $this->checkBox('hide_profile_link', "Hide OpenID links from my profile", !empty($prefs) && $prefs->hide_profile_link);
+ $this->element('input', array('type' => 'submit',
+ 'id' => 'settings_openid_prefs_save',
+ 'name' => 'save_prefs',
+ 'class' => 'submit',
+ // TRANS: Button text to save OpenID prefs
+ 'value' => _m('BUTTON','Save')));
+ $this->elementEnd('ul');
+ $this->elementEnd('fieldset');
+
$this->elementEnd('form');
}
$this->removeOpenid();
} else if($this->arg('remove_trustroots')) {
$this->removeTrustroots();
+ } else if($this->arg('save_prefs')) {
+ $this->savePrefs();
} else {
// TRANS: Unexpected form validation error.
$this->showForm(_m('Something weird happened.'));
$this->showForm(_m('OpenID removed.'), true);
return;
}
+
+ /**
+ * Handles a request to save preferences
+ *
+ * Validates input and, if everything is OK, deletes the OpenID.
+ * Reloads the form with a success or error notification.
+ *
+ * @return void
+ */
+ function savePrefs()
+ {
+ $cur = common_current_user();
+
+ if (empty($cur)) {
+ throw new ClientException(_("Not logged in."));
+ }
+
+ $orig = null;
+ $prefs = User_openid_prefs::staticGet('user_id', $cur->id);
+
+ if (empty($prefs)) {
+ $prefs = new User_openid_prefs();
+ $prefs->user_id = $cur->id;
+ $prefs->created = common_sql_now();
+ } else {
+ $orig = clone($prefs);
+ }
+
+ $prefs->hide_profile_link = $this->boolean('hide_profile_link');
+
+ if (empty($orig)) {
+ $prefs->insert();
+ } else {
+ $prefs->update($orig);
+ }
+
+ $this->showForm(_m('OpenID preferences saved.'), true);
+ return;
+ }
}
$schema = Schema::get();
$schema->ensureTable('poll', Poll::schemaDef());
$schema->ensureTable('poll_response', Poll_response::schemaDef());
+ $schema->ensureTable('user_poll_prefs', User_poll_prefs::schemaDef());
return true;
}
case 'ShowpollAction':
case 'NewpollAction':
case 'RespondpollAction':
+ case 'PollsettingsAction':
include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
return false;
case 'Poll':
case 'Poll_response':
+ case 'User_poll_prefs':
include_once $dir.'/'.$cls.'.php';
return false;
case 'NewPollForm':
array('action' => 'respondpoll'),
array('id' => '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'));
+ $m->connect('settings/poll',
+ array('action' => 'pollsettings'));
+
return true;
}
}
return true;
}
+
+ // Hide poll responses for @chuck
+
+ function onEndNoticeWhoGets($notice, &$ni) {
+ if ($notice->object_type == self::POLL_RESPONSE_OBJECT) {
+ foreach ($ni as $id => $source) {
+ $user = User::staticGet('id', $id);
+ if (!empty($user)) {
+ $pollPrefs = User_poll_prefs::staticGet('user_id', $user->id);
+ if (!empty($pollPrefs) && ($pollPrefs->hide_responses)) {
+ unset($ni[$id]);
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Menu item for personal subscriptions/groups area
+ *
+ * @param Action $action action being executed
+ *
+ * @return boolean hook return
+ */
+
+ function onEndAccountSettingsNav($action)
+ {
+ $action_name = $action->trimmed('action');
+
+ $action->menuItem(common_local_url('pollsettings'),
+ // TRANS: Poll plugin menu item on user settings page.
+ _m('MENU', 'Polls'),
+ // TRANS: Poll plugin tooltip for user settings menu item.
+ _m('Configure poll behavior'),
+ $action_name === 'pollsettings');
+
+ return true;
+ }
}
--- /dev/null
+<?php
+/**
+ * Data class to record user prefs for polls
+ *
+ * PHP version 5
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * For storing the poll prefs
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class User_poll_prefs extends Managed_DataObject
+{
+ public $__table = 'user_poll_prefs'; // table name
+ public $user_id; // int id
+ public $hide_responses; // boolean
+ public $created; // datetime
+ public $modified; // datetime
+
+ /**
+ * Get an instance by key
+ *
+ * This is a utility method to get a single instance with a given key value.
+ *
+ * @param string $k Key to use to lookup (usually 'user_id' for this class)
+ * @param mixed $v Value to lookup
+ *
+ * @return User_greeting_count object found, or null for no hits
+ *
+ */
+ function staticGet($k, $v=null)
+ {
+ return Memcached_DataObject::staticGet('User_poll_prefs', $k, $v);
+ }
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Record of user preferences for polls',
+ 'fields' => array(
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
+ 'hide_responses' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'Hide all poll responses'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id')
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Form to set your personal poll settings
+ *
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugins
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class PollSettingsAction extends SettingsAction
+{
+ /**
+ * Title of the page
+ *
+ * @return string Page title
+ */
+ function title()
+ {
+ // TRANS: Page title.
+ return _m('Poll settings');
+ }
+
+ /**
+ * Instructions for use
+ *
+ * @return string Instructions for use
+ */
+
+ function getInstructions()
+ {
+ // TRANS: Page instructions.
+ return _m('Set your poll preferences');
+ }
+
+ /**
+ * Show the form for Poll
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $user = common_current_user();
+
+ $prefs = User_poll_prefs::staticGet('user_id', $user->id);
+
+ $form = new PollPrefsForm($this, $prefs);
+
+ $form->show();
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handlePost()
+ {
+ $user = common_current_user();
+
+ $upp = User_poll_prefs::staticGet('user_id', $user->id);
+ $orig = null;
+
+ if (!empty($upp)) {
+ $orig = clone($upp);
+ } else {
+ $upp = new User_poll_prefs();
+ $upp->user_id = $user->id;
+ $upp->created = common_sql_now();
+ }
+
+ $upp->hide_responses = $this->boolean('hide_responses');
+ $upp->modified = common_sql_now();
+
+ if (!empty($orig)) {
+ $upp->update($orig);
+ } else {
+ $upp->insert();
+ }
+
+ // TRANS: Confirmation shown when user profile settings are saved.
+ $this->showForm(_('Settings saved.'), true);
+
+ return;
+ }
+}
+
+class PollPrefsForm extends Form
+{
+ var $prefs;
+
+ function __construct($out, $prefs)
+ {
+ parent::__construct($out);
+ $this->prefs = $prefs;
+ }
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->elementStart('fieldset');
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->checkbox('hide_responses',
+ _('Do not deliver poll responses to my home timeline'),
+ (!empty($this->prefs) && $this->prefs->hide_responses));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->elementEnd('fieldset');
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->submit('submit', _('Save'));
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'form_poll_prefs';
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+
+ function action()
+ {
+ return common_local_url('pollsettings');
+ }
+
+ /**
+ * Class of the form. May include space-separated list of multiple classes.
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form_settings';
+ }
+}
list($action, $arg1, $arg2) = $path;
$channels = Realtime_channel::getAllChannels($action, $arg1, $arg2);
+ $this->log(LOG_INFO, sprintf(_("%d candidate channels for notice %d"),
+ count($channels),
+ $notice->id));
foreach ($channels as $channel) {
$profile = Profile::staticGet('id', $channel->user_id);
}
if ($notice->inScope($profile)) {
+ $this->log(LOG_INFO,
+ sprintf(_("Delivering notice %d to channel (%s, %s, %s) for user '%s'"),
+ $notice->id,
+ $channel->action,
+ $channel->arg1,
+ $channel->arg2,
+ ($profile) ? ($profile->nickname) : "<public>"));
$timeline = $this->_pathToChannel(array($channel->channel_key));
$this->_publish($timeline, $json);
}
}
return true;
}
+
+ /**
+ * Add links in the user's profile block to their Twitter profile URL.
+ *
+ * @param Profile $profile The profile being shown
+ * @param Array &$links Writeable array of arrays (href, text, image).
+ *
+ * @return boolean hook value (true)
+ */
+
+ function onOtherAccountProfiles($profile, &$links)
+ {
+ $fuser = null;
+
+ $flink = Foreign_link::getByUserID($profile->id, TWITTER_SERVICE);
+
+ if (!empty($flink)) {
+ $fuser = $flink->getForeignUser();
+
+ if (!empty($fuser)) {
+ $links[] = array("href" => $fuser->uri,
+ "text" => sprintf(_("@%s on Twitter"), $fuser->nickname),
+ "image" => $this->path("icons/twitter-bird-white-on-blue.png"));
+ }
+ }
+
+ return true;
+ }
}
{
protected $userIds;
- public function __construct(TwitterOAuthClient $auth, $baseUrl='http://betastream.twitter.com')
+ public function __construct(TwitterOAuthClient $auth, $baseUrl='https://sitestream.twitter.com')
{
parent::__construct($auth, $baseUrl);
}
'users=',
'words=',
'prefix=',
- 'groupprefix'
+ 'groupprefix=',
+ 'faves='
);
$helptext = <<<END_OF_CREATESIM_HELP
-b --subscriptions Average subscriptions per user (default no. users/20)
-g --groups Number of groups (default 20)
-j --joins Number of groups per user (default 5)
+ -f --faves Number of faves per user (default notices/10)
-n --notices Average notices per user (default 100)
-t --tags Number of distinct hash tags (default 10000)
-u --users Number of users (default 100)
$options['scope'] |= Notice::ADDRESSEE_SCOPE;
}
}
+ } else {
+ $is_directed = rand(0, 4);
+
+ if ($is_directed == 0) {
+ $subs = $user->getSubscriptions(0, 100)->fetchAll();
+ if (count($subs) > 0) {
+ $seen = array();
+ $f = rand(0, 9);
+ if ($f <= 6) {
+ $addrs = 1;
+ } else if ($f <= 8) {
+ $addrs = 2;
+ } else {
+ $addrs = 3;
+ }
+ for ($m = 0; $m < $addrs; $m++) {
+ $x = rand(0, count($subs) - 1);
+ if ($seen[$x]) {
+ continue;
+ }
+ if ($subs[$x]->id == $user->id) {
+ continue;
+ }
+ $seen[$x] = true;
+ $rprofile = $subs[$x];
+ $content = "@".$rprofile->nickname." ".$content;
+ }
+ $private_to_addressees = rand(0, 4);
+ if ($private_to_addressees == 0) {
+ $options['scope'] |= Notice::ADDRESSEE_SCOPE;
+ }
+ }
+ }
}
$has_hash = rand(0, 2);
$notice = Notice::saveNew($user->id, $content, 'createsim', $options);
}
+function newMessage($i)
+{
+ global $userprefix;
+
+ $n = rand(0, $i - 1);
+ $user = User::staticGet('nickname', sprintf('%s%d', $userprefix, $n));
+
+ $content = testNoticeContent();
+
+ $friends = $user->mutuallySubscribedUsers()->fetchAll();
+
+ if (count($friends) == 0) {
+ return;
+ }
+
+ $j = rand(0, count($friends) - 1);
+
+ $other = $friends[$j];
+
+ $message = Message::saveNew($user->id, $other->id, $content, 'createsim');
+}
+
function newSub($i)
{
global $userprefix;
}
}
+function newFave($u)
+{
+ global $userprefix;
+ global $groupprefix;
+
+ $userNumber = rand(0, $u - 1);
+
+ $userNick = sprintf('%s%d', $userprefix, $userNumber);
+
+ $user = User::staticGet('nickname', $userNick);
+
+ if (empty($user)) {
+ throw new Exception("Can't find user '$userNick'.");
+ }
+
+ // NB: it's OK to like your own stuff!
+
+ $otherNumber = rand(0, $u - 1);
+
+ $otherNick = sprintf('%s%d', $userprefix, $otherNumber);
+
+ $other = User::staticGet('nickname', $otherNick);
+
+ if (empty($other)) {
+ throw new Exception("Can't find user '$otherNick'.");
+ }
+
+ $notices = $other->getNotices()->fetchAll();
+
+ if (count($notices) == 0) {
+ return;
+ }
+
+ $idx = rand(0, count($notices) - 1);
+
+ $notice = $notices[$idx];
+
+ if ($user->hasFave($notice)) {
+ return;
+ }
+
+ Fave::addNew($user->getProfile(), $notice);
+}
+
function testNoticeContent()
{
global $words;
return $text;
}
-function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $tagmax)
+function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $favesavg, $messageavg, $tagmax)
{
global $config;
$config['site']['dupelimit'] = -1;
// # registrations + # notices + # subs
- $events = $usercount + $groupcount + ($usercount * ($noticeavg + $subsavg + $joinsavg));
+ $events = $usercount + $groupcount + ($usercount * ($noticeavg + $subsavg + $joinsavg + $favesavg + $messageavg));
$events -= $preuser;
$events -= $pregroup;
$nt = $gt + ($usercount * $noticeavg);
$st = $nt + ($usercount * $subsavg);
$jt = $st + ($usercount * $joinsavg);
+ $ft = $jt + ($usercount * $favesavg);
+ $mt = $ft + ($usercount * $messageavg);
- printfv("$events events ($ut, $gt, $nt, $st, $jt)\n");
+ printfv("$events events ($ut, $gt, $nt, $st, $jt, $ft, $mt)\n");
for ($i = 0; $i < $events; $i++)
{
} else if ($e > $st && $e <= $jt) {
printfv("$i Making a new group join\n");
newJoin($n, $g);
+ } else if ($e > $jt && $e <= $ft) {
+ printfv("$i Making a new fave\n");
+ newFave($n);
+ } else if ($e > $ft && $e <= $mt) {
+ printfv("$i Making a new message\n");
+ newMessage($n);
} else {
printfv("No event for $i!");
}
$noticeavg = (have_option('n', 'notices')) ? get_option_value('n', 'notices') : 100;
$subsavg = (have_option('b', 'subscriptions')) ? get_option_value('b', 'subscriptions') : max($usercount/20, 10);
$joinsavg = (have_option('j', 'joins')) ? get_option_value('j', 'joins') : 5;
+$favesavg = (have_option('f', 'faves')) ? get_option_value('f', 'faves') : max($noticeavg/10, 5);
+$messageavg = (have_option('m', 'messages')) ? get_option_value('m', 'messages') : max($noticeavg/10, 5);
$tagmax = (have_option('t', 'tags')) ? get_option_value('t', 'tags') : 10000;
$userprefix = (have_option('x', 'prefix')) ? get_option_value('x', 'prefix') : 'testuser';
$groupprefix = (have_option('z', 'groupprefix')) ? get_option_value('z', 'groupprefix') : 'testgroup';
}
try {
- main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $tagmax);
+ main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $favesavg, $messageavg, $tagmax);
} catch (Exception $e) {
printfv("Got an exception: ".$e->getMessage());
}
'--admin-nick' => 'adminNick',
'--admin-pass' => 'adminPass',
'--admin-email' => 'adminEmail',
- '--admin-updates' => 'adminUpdates'
+ '--admin-updates' => 'adminUpdates',
+
+ '--site-profile' => 'siteProfile'
);
foreach ($map as $arg => $target) {
if (substr($arg, 0, 2) == '--') {
--admin-updates 'yes' (default) or 'no', whether to subscribe
admin to update@status.net (default yes)
+ --site-profile site profile ['public', 'private' (default), 'community', 'singleuser']
+
--skip-config Don't write a config.php -- use with caution,
requires a global configuration file.
display:none;
}
+.profile_block_otherprofile_list li {
+ display: inline;
+ list-style-type: none;
+}
+
/*end of @media screen, projection, tv*/