function getTags() { $profile = Profile::current(); $keypart = sprintf('Inbox:notice_tag:%d:%d', $this->user->id, $profile->id); $tag = Memcached_DataObject::cacheGet($keypart); if ($tag === false) { $stream = new InboxNoticeStream($this->user, $profile); $ids = $stream->getNoticeIds(0, Inbox::MAX_NOTICES, null, null); if (empty($ids)) { $tag = array(); } else { $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); // @fixme should we use the cutoff too? Doesn't help with indexing per-user. $qry = 'SELECT notice_tag.tag, ' . $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'WHERE notice.id in (' . implode(',', $ids) . ')' . 'GROUP BY notice_tag.tag ' . 'ORDER BY weight DESC '; $limit = TAGS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $t = new Notice_tag(); $t->query($qry); $tag = array(); while ($t->fetch()) { $tag[] = clone $t; } } Memcached_DataObject::cacheSet($keypart, $tag, 3600); } return new ArrayWrapper($tag); }
function getTags() { $notice_tag = new Notice_tag(); $query = 'select tag,count(tag) as weight from notice_tag join file_to_post on (notice_tag.notice_id=post_id) join notice on notice_id = notice.id where file_id=' . $notice_tag->escape($this->out->attachment->id) . ' group by tag order by weight desc'; $notice_tag->query($query); return $notice_tag; }
function getTags($lst, $usr) { $profile_tag = new Notice_tag(); $profile_tag->query('SELECT DISTINCT(tag) ' . 'FROM profile_tag, subscription ' . 'WHERE tagger = ' . $this->target->id . ' ' . 'AND ' . $usr . ' = ' . $this->target->id . ' ' . 'AND ' . $lst . ' = tagged ' . 'AND tagger != tagged'); $tags = array(); while ($profile_tag->fetch()) { $tags[] = $profile_tag->tag; } $profile_tag->free(); return $tags; }
function ping_notice_tags($notice) { $tag = new Notice_tag(); $tag->notice_id = $notice->id; $tags = array(); if ($tag->find()) { while ($tag->fetch()) { $tags[] = $tag->tag; } $tag->free(); unset($tag); return implode('|', $tags); } return NULL; }
function showContent() { $notice = Notice_tag::getStream($this->tag, ($this->page - 1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); $nl = new NoticeList($notice, $this); $cnt = $nl->show(); $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, $this->page, 'tag', array('tag' => $this->tag)); }
function getNotices($limit = 0) { $tag = $this->tag; if (is_null($tag)) { return null; } $notice = Notice_tag::getStream($tag->tag)->getNotices(0, $limit == 0 ? NOTICES_PER_PAGE : $limit); return $notice->fetchAll(); }
function showContent() { # This should probably be cached rather than recalculated $tags = new Notice_tag(); #Need to clear the selection and then only re-add the field #we are grouping by, otherwise it's not a valid 'group by' #even though MySQL seems to let it slide... $tags->selectAdd(); $tags->selectAdd('tag'); #Add the aggregated columns... $tags->selectAdd('max(notice_id) as last_notice_id'); if (common_config('db', 'type') == 'pgsql') { $calc = 'sum(exp(-extract(epoch from (now()-created))/%s)) as weight'; } else { $calc = 'sum(exp(-(now() - created)/%s)) as weight'; } $tags->selectAdd(sprintf($calc, common_config('tag', 'dropoff'))); $tags->groupBy('tag'); $tags->orderBy('weight DESC'); $tags->limit(TAGS_PER_PAGE); $cnt = $tags->find(); if ($cnt > 0) { $this->elementStart('div', array('id' => 'tagcloud', 'class' => 'section')); $tw = array(); $sum = 0; while ($tags->fetch()) { $tw[$tags->tag] = $tags->weight; $sum += $tags->weight; } ksort($tw); $this->elementStart('dl'); $this->element('dt', null, _('Tag cloud')); $this->elementStart('dd'); $this->elementStart('ul', 'tags xoxo tag-cloud'); foreach ($tw as $tag => $weight) { $this->showTag($tag, $weight, $weight / $sum); } $this->elementEnd('ul'); $this->elementEnd('dd'); $this->elementEnd('dl'); $this->elementEnd('div'); } }
function _streamDirect($tag, $offset, $limit, $since_id, $max_id) { $nt = new Notice_tag(); $nt->tag = $tag; $nt->selectAdd(); $nt->selectAdd('notice_id'); Notice::addWhereSinceId($nt, $since_id, 'notice_id'); Notice::addWhereMaxId($nt, $max_id, 'notice_id'); $nt->orderBy('created DESC, notice_id DESC'); if (!is_null($offset)) { $nt->limit($offset, $limit); } $ids = array(); if ($nt->find()) { while ($nt->fetch()) { $ids[] = $nt->notice_id; } } return $ids; }
function getNotices($limit = 0) { $tag = $this->tag; if (is_null($tag)) { return null; } $notice = Notice_tag::getStream($tag->tag, 0, $limit == 0 ? NOTICES_PER_PAGE : $limit); while ($notice->fetch()) { $notices[] = clone $notice; } return $notices; }
function showContent() { # This should probably be cached rather than recalculated $tags = new Notice_tag(); #Need to clear the selection and then only re-add the field #we are grouping by, otherwise it's not a valid 'group by' #even though MySQL seems to let it slide... $tags->selectAdd(); $tags->selectAdd('tag'); #Add the aggregated columns... $tags->selectAdd('max(notice_id) as last_notice_id'); $calc = common_sql_weight('created', common_config('tag', 'dropoff')); $cutoff = sprintf("notice_tag.created > '%s'", common_sql_date(time() - common_config('tag', 'cutoff'))); $tags->selectAdd($calc . ' as weight'); $tags->whereAdd($cutoff); $tags->groupBy('tag'); $tags->orderBy('weight DESC'); $tags->limit(TAGS_PER_PAGE); $cnt = $tags->find(); if ($cnt > 0) { $this->elementStart('div', array('id' => 'tagcloud', 'class' => 'section')); $tw = array(); $sum = 0; while ($tags->fetch()) { $tw[$tags->tag] = $tags->weight; $sum += $tags->weight; } ksort($tw); $this->elementStart('dl'); $this->element('dt', null, _('Tag cloud')); $this->elementStart('dd'); $this->elementStart('ul', 'tags xoxo tag-cloud'); foreach ($tw as $tag => $weight) { if ($sum) { $weightedSum = $weight / $sum; } else { $weightedSum = 0.5; } $this->showTag($tag, $weight, $weightedSum); } $this->elementEnd('ul'); $this->elementEnd('dd'); $this->elementEnd('dl'); $this->elementEnd('div'); } else { $this->showEmptyList(); } }
function timeline($args, $apidata) { parent::handle($args); common_debug("in tags api action"); $this->auth_user = $apidata['user']; $tag = $apidata['api_arg']; if (empty($tag)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } $sitename = common_config('site', 'name'); $title = sprintf(_("Notices tagged with %s"), $tag); $taguribase = common_config('integration', 'taguri'); $id = "tag:{$taguribase}:TagTimeline:" . $tag; $link = common_local_url('tag', array('tag' => $tag)); $subtitle = sprintf(_('Updates tagged with %1$s on %2$s!'), $tag, $sitename); $page = (int) $this->arg('page', 1); $count = (int) $this->arg('count', 20); $max_id = (int) $this->arg('max_id', 0); $since_id = (int) $this->arg('since_id', 0); $since = $this->arg('since'); # XXX: support max_id, since_id, and since arguments $notice = Notice_tag::getStream($tag, ($page - 1) * $count, $count + 1); switch ($apidata['content-type']) { case 'xml': $this->show_xml_timeline($notice); break; case 'rss': $this->show_rss_timeline($notice, $title, $link, $subtitle, $suplink); break; case 'atom': if (isset($apidata['api_arg'])) { $selfuri = common_root_url() . 'api/laconica/tags/timeline/' . $apidata['api_arg'] . '.atom'; } else { $selfuri = common_root_url() . 'api/laconica/tags/timeline.atom'; } $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri); break; case 'json': $this->show_json_timeline($notice); break; default: $this->clientError(_('API method not found!'), $code = 404); } }
function _streamDirect($tag, $offset, $limit, $since_id, $max_id) { $nt = new Notice_tag(); $nt->tag = $tag; $nt->selectAdd(); $nt->selectAdd('notice_id'); if ($since_id != 0) { $nt->whereAdd('notice_id > ' . $since_id); } if ($max_id != 0) { $nt->whereAdd('notice_id < ' . $max_id); } $nt->orderBy('notice_id DESC'); if (!is_null($offset)) { $nt->limit($offset, $limit); } $ids = array(); if ($nt->find()) { while ($nt->fetch()) { $ids[] = $nt->notice_id; } } return $ids; }
protected function prepare(array $args = array()) { parent::prepare($args); $taginput = $this->trimmed('tag'); $this->tag = common_canonical_tag($taginput); if (empty($this->tag)) { common_redirect(common_local_url('publictagcloud'), 301); } // after common_canonical_tag we have a lowercase, no-specials tag string if ($this->tag !== $taginput) { common_redirect(common_local_url('tag', array('tag' => $this->tag)), 301); } $this->page = $this->arg('page') ? $this->arg('page') + 0 : 1; common_set_returnto($this->selfUrl()); $this->notice = Notice_tag::getStream($this->tag)->getNotices(($this->page - 1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); if ($this->page > 1 && $this->notice->N == 0) { // TRANS: Client error when page not found (404). $this->clientError(_('No such page.'), 404); } return true; }
function prepare($args) { parent::prepare($args); $taginput = $this->trimmed('tag'); $this->tag = common_canonical_tag($taginput); if (!$this->tag) { common_redirect(common_local_url('publictagcloud'), 301); return false; } if ($this->tag != $taginput) { common_redirect(common_local_url('tag', array('tag' => $this->tag)), 301); return false; } $this->page = $this->arg('page') ? $this->arg('page') + 0 : 1; common_set_returnto($this->selfUrl()); $this->notice = Notice_tag::getStream($this->tag, ($this->page - 1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); if ($this->page > 1 && $this->notice->N == 0) { // TRANS: Server error when page not found (404) $this->serverError(_('您访问的网页不存在'), $code = 404); } return true; }
public function getTags() { $tags = array(); $tag = new Notice_tag(); $tag->notice_id = $this->id; if ($tag->find()) { while ($tag->fetch()) { $tags[] = $tag->tag; } } $tag->free(); return $tags; }
function twitterRssEntryArray($notice) { $entry = array(); if (Event::handle('StartRssEntryArray', array($notice, &$entry))) { $profile = $notice->getProfile(); // We trim() to avoid extraneous whitespace in the output $entry['content'] = common_xml_safe_str(trim($notice->rendered)); $entry['title'] = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content)); $entry['link'] = common_local_url('shownotice', array('notice' => $notice->id)); $entry['published'] = common_date_iso8601($notice->created); $taguribase = TagURI::base(); $entry['id'] = "tag:{$taguribase}:{$entry['link']}"; $entry['updated'] = $entry['published']; $entry['author'] = $profile->getBestName(); // Enclosures $attachments = $notice->attachments(); $enclosures = array(); foreach ($attachments as $attachment) { $enclosure_o = $attachment->getEnclosure(); if ($enclosure_o) { $enclosure = array(); $enclosure['url'] = $enclosure_o->url; $enclosure['mimetype'] = $enclosure_o->mimetype; $enclosure['size'] = $enclosure_o->size; $enclosures[] = $enclosure; } } if (!empty($enclosures)) { $entry['enclosures'] = $enclosures; } // Tags/Categories $tag = new Notice_tag(); $tag->notice_id = $notice->id; if ($tag->find()) { $entry['tags'] = array(); while ($tag->fetch()) { $entry['tags'][] = $tag->tag; } } $tag->free(); // RSS Item specific $entry['description'] = $entry['content']; $entry['pubDate'] = common_date_rfc2822($notice->created); $entry['guid'] = $entry['link']; if (isset($notice->lat) && isset($notice->lon)) { // This is the format that GeoJSON expects stuff to be in. // showGeoRSS() below uses it for XML output, so we reuse it $entry['geo'] = array('type' => 'Point', 'coordinates' => array((double) $notice->lat, (double) $notice->lon)); } else { $entry['geo'] = null; } Event::handle('EndRssEntryArray', array($notice, &$entry)); } return $entry; }
/** * Save a new notice bookmark * * @param Profile $profile To save the bookmark for * @param string $title Title of the bookmark * @param string $url URL of the bookmark * @param array $rawtags array of tags * @param string $description Description of the bookmark * @param array $options Options for the Notice::saveNew() * * @return Notice saved notice */ static function addNew(Profile $actor, $title, $url, array $rawtags, $description, array $options = array()) { $act = new Activity(); $act->verb = ActivityVerb::POST; $act->time = time(); $act->actor = $actor->asActivityObject(); $actobj = new ActivityObject(); $actobj->type = ActivityObject::BOOKMARK; $actobj->title = $title; $actobj->summary = $description; $actobj->extra[] = array('link', array('rel' => 'related', 'href' => $url), null); $act->objects[] = $actobj; $act->enclosures[] = $url; $tags = array(); $replies = array(); // filter "for:nickname" tags foreach ($rawtags as $tag) { if (strtolower(mb_substr($tag, 0, 4)) == 'for:') { // skip if done by caller if (!array_key_exists('replies', $options)) { $nickname = mb_substr($tag, 4); $other = common_relative_profile($actor, $nickname); if (!empty($other)) { $replies[] = $other->getUri(); } } } else { $tags[] = common_canonical_tag($tag); } } $hashtags = array(); $taglinks = array(); foreach ($tags as $tag) { $hashtags[] = '#' . $tag; $attrs = array('href' => Notice_tag::url($tag), 'rel' => $tag, 'class' => 'tag'); $taglinks[] = XMLStringer::estring('a', $attrs, $tag); } // Use user's preferences for short URLs, if possible // FIXME: Should be possible to with the Profile object... try { $user = $actor->getUser(); $shortUrl = File_redirection::makeShort($url, empty($user) ? null : $user); } catch (Exception $e) { // Don't let this stop us. $shortUrl = $url; } // TRANS: Rendered bookmark content. // TRANS: %1$s is a URL, %2$s the bookmark title, %3$s is the bookmark description, // TRANS: %4$s is space separated list of hash tags. $actobj->content = sprintf(_m('<span class="xfolkentry">' . '<a class="taggedlink" href="%1$s">%2$s</a> ' . '<span class="description">%3$s</span> ' . '<span class="meta">%4$s</span>' . '</span>'), htmlspecialchars($url), htmlspecialchars($title), htmlspecialchars($description), implode(' ', $taglinks)); foreach ($tags as $term) { $catEl = new AtomCategory(); $catEl->term = $term; $activity->categories[] = $catEl; } $options = array_merge(array('urls' => array($url), 'rendered' => $rendered, 'tags' => $tags, 'replies' => $replies, 'object_type' => ActivityObject::BOOKMARK), $options); return Notice::saveActivity($act, $actor, $options); }
/** * Get the list of hash tags saved with this notice. * * @return array of strings */ public function getTags() { $tags = array(); $keypart = sprintf('notice:tags:%d', $this->id); $tagstr = self::cacheGet($keypart); if ($tagstr !== false) { $tags = explode(',', $tagstr); } else { $tag = new Notice_tag(); $tag->notice_id = $this->id; if ($tag->find()) { while ($tag->fetch()) { $tags[] = $tag->tag; } } self::cacheSet($keypart, implode(',', $tags)); } return $tags; }
protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped = null) { $nb = Bookmark::fromStored($stored); // Whether to nofollow $attrs = array('href' => $nb->getUrl(), 'class' => 'bookmark-title'); $nf = common_config('nofollow', 'external'); if ($nf == 'never' || ($nf == 'sometimes' and $out instanceof ShowstreamAction)) { $attrs['rel'] = 'external'; } else { $attrs['rel'] = 'nofollow external'; } $out->elementStart('h3'); $out->element('a', $attrs, $nb->getTitle()); $out->elementEnd('h3'); // Replies look like "for:" tags $replies = $stored->getReplies(); $tags = $stored->getTags(); if (!empty($nb->description)) { $out->element('p', array('class' => 'bookmark-description'), $nb->description); } if (!empty($replies) || !empty($tags)) { $out->elementStart('ul', array('class' => 'bookmark-tags')); foreach ($replies as $reply) { $other = Profile::getByPK($reply); $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => $other->getUrl(), 'title' => $other->getBestName()), sprintf('for:%s', $other->getNickname())); $out->elementEnd('li'); $out->text(' '); } foreach ($tags as $tag) { $tag = trim($tag); if (!empty($tag)) { $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => Notice_tag::url($tag)), $tag); $out->elementEnd('li'); $out->text(' '); } } $out->elementEnd('ul'); } }
/** * Get notices * * @return array notices */ function getNotices() { $notice = Notice_tag::getStream($this->tag)->getNotices(($this->page - 1) * $this->count, $this->count + 1, $this->since_id, $this->max_id); return $notice->fetchAll(); }
function getNoticeTags($notice) { $tags = null; $nt = new Notice_tag(); $nt->notice_id = $notice->id; if ($nt->find()) { $tags = array(); while ($nt->fetch()) { $tags[] = $nt->tag; } } $nt->free(); $nt = null; return $tags; }
protected function getNotices() { $stream = Notice_tag::getStream($this->tag->tag)->getNotices(0, $this->limit); return $stream->fetchAll(); }
function showContent() { $notice = $this->nli->notice; $out = $this->nli->out; $out->elementStart('p', array('class' => 'entry-content')); $nb = Bookmark::getByNotice($notice); $profile = $notice->getProfile(); $atts = $notice->attachments(); if (count($atts) < 1) { // Something wrong; let default code deal with it. // TRANS: Exception thrown when a bookmark has no attachments. // TRANS: %1$s is a bookmark ID, %2$s is a notice ID (number). throw new Exception(sprintf(_m('Bookmark %1$s (notice %2$d) has no attachments.'), $nb->id, $notice->id)); } $att = $atts[0]; $out->elementStart('h3'); $out->element('a', array('href' => $att->url, 'class' => 'bookmark-title'), $nb->title); $out->elementEnd('h3'); // Replies look like "for:" tags $replies = $notice->getReplies(); $tags = $notice->getTags(); if (!empty($replies) || !empty($tags)) { $out->elementStart('ul', array('class' => 'bookmark-tags')); foreach ($replies as $reply) { $other = Profile::staticGet('id', $reply); if (!empty($other)) { $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => $other->profileurl, 'title' => $other->getBestName()), sprintf('for:%s', $other->nickname)); $out->elementEnd('li'); $out->text(' '); } } foreach ($tags as $tag) { $tag = trim($tag); if (!empty($tag)) { $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => Notice_tag::url($tag)), $tag); $out->elementEnd('li'); $out->text(' '); } } $out->elementEnd('ul'); } if (!empty($nb->description)) { $out->element('p', array('class' => 'bookmark-description'), $nb->description); } $out->elementEnd('p'); }
/** * Get notices * * @return array notices */ function getNotices() { $notices = array(); $notice = Notice_tag::getStream($this->tag, ($this->page - 1) * $this->count, $this->count + 1); while ($notice->fetch()) { $notices[] = clone $notice; } return $notices; }
/** * Output the HTML for a bookmark in a list * * @param NoticeListItem $nli The list item being shown. * * @return boolean hook value */ function onStartShowNoticeItem($nli) { $nb = Bookmark::getByNotice($nli->notice); if (!empty($nb)) { $out = $nli->out; $notice = $nli->notice; $profile = $nli->profile; $atts = $notice->attachments(); if (count($atts) < 1) { // Something wrong; let default code deal with it. return true; } $att = $atts[0]; // XXX: only show the bookmark URL for non-single-page stuff if ($out instanceof ShowbookmarkAction) { } else { $out->elementStart('h3'); $out->element('a', array('href' => $att->url, 'class' => 'bookmark-title entry-title'), $nb->title); $out->elementEnd('h3'); $countUrl = common_local_url('noticebyurl', array('id' => $att->id)); $out->element('a', array('class' => 'bookmark-notice-count', 'href' => $countUrl), $att->noticeCount()); } // Replies look like "for:" tags $replies = $nli->notice->getReplies(); $tags = $nli->notice->getTags(); if (!empty($replies) || !empty($tags)) { $out->elementStart('ul', array('class' => 'bookmark-tags')); foreach ($replies as $reply) { $other = Profile::staticGet('id', $reply); $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => $other->profileurl, 'title' => $other->getBestName()), sprintf('for:%s', $other->nickname)); $out->elementEnd('li'); $out->text(' '); } foreach ($tags as $tag) { $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => Notice_tag::url($tag)), $tag); $out->elementEnd('li'); $out->text(' '); } $out->elementEnd('ul'); } if (!empty($nb->description)) { $out->element('p', array('class' => 'bookmark-description'), $nb->description); } if (common_config('attachments', 'show_thumbs')) { $haveThumbs = false; foreach ($atts as $check) { $thumbnail = File_thumbnail::staticGet('file_id', $check->id); if (!empty($thumbnail)) { $haveThumbs = true; break; } } if ($haveThumbs) { $al = new InlineAttachmentList($notice, $out); $al->show(); } } $out->elementStart('div', array('class' => 'bookmark-info entry-content')); $avatar = $profile->getAvatar(AVATAR_MINI_SIZE); $out->element('img', array('src' => $avatar ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_MINI_SIZE), 'class' => 'avatar photo bookmark-avatar', 'width' => AVATAR_MINI_SIZE, 'height' => AVATAR_MINI_SIZE, 'alt' => $profile->getBestName())); $out->raw(' '); $out->element('a', array('href' => $profile->profileurl, 'title' => $profile->getBestName()), $profile->nickname); $nli->showNoticeLink(); $nli->showNoticeSource(); $nli->showNoticeLocation(); $nli->showContext(); $nli->showRepeat(); $out->elementEnd('div'); $nli->showNoticeOptions(); return false; } return true; }
function showItem($notice) { $profile = Profile::staticGet($notice->profile_id); $nurl = common_local_url('shownotice', array('notice' => $notice->id)); $creator_uri = common_profile_uri($profile); $this->elementStart('item', array('rdf:about' => $notice->uri, 'rdf:type' => 'http://rdfs.org/sioc/types#MicroblogPost')); $title = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content)); $this->element('title', null, $title); $this->element('link', null, $nurl); $this->element('description', null, $profile->nickname . "'s status on " . common_exact_date($notice->created)); if ($notice->rendered) { $this->element('content:encoded', null, common_xml_safe_str($notice->rendered)); } $this->element('dc:date', null, common_date_w3dtf($notice->created)); $this->element('dc:creator', null, $profile->fullname ? $profile->fullname : $profile->nickname); $this->element('foaf:maker', array('rdf:resource' => $creator_uri)); $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri . '#acct')); $location = $notice->getLocation(); if ($location && isset($location->lat) && isset($location->lon)) { $location_uri = $location->getRdfURL(); $attrs = array('geo:lat' => $location->lat, 'geo:long' => $location->lon); if (strlen($location_uri)) { $attrs['rdf:resource'] = $location_uri; } $this->element('statusnet:origin', $attrs); } $this->element('statusnet:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); if ($notice->reply_to) { $replyurl = common_local_url('shownotice', array('notice' => $notice->reply_to)); $this->element('sioc:reply_of', array('rdf:resource' => $replyurl)); } if (!empty($notice->conversation)) { $conversationurl = common_local_url('conversation', array('id' => $notice->conversation)); $this->element('sioc:has_discussion', array('rdf:resource' => $conversationurl)); } $attachments = $notice->attachments(); if ($attachments) { foreach ($attachments as $attachment) { $enclosure = $attachment->getEnclosure(); if ($enclosure) { $attribs = array('rdf:resource' => $enclosure->url); if ($enclosure->title) { $attribs['dc:title'] = $enclosure->title; } if ($enclosure->modified) { $attribs['dc:date'] = common_date_w3dtf($enclosure->modified); } if ($enclosure->size) { $attribs['enc:length'] = $enclosure->size; } if ($enclosure->mimetype) { $attribs['enc:type'] = $enclosure->mimetype; } $this->element('enc:enclosure', $attribs); } $this->element('sioc:links_to', array('rdf:resource' => $attachment->url)); } } $tag = new Notice_tag(); $tag->notice_id = $notice->id; if ($tag->find()) { $entry['tags'] = array(); while ($tag->fetch()) { $tagpage = common_local_url('tag', array('tag' => $tag->tag)); if (in_array($tag, $this->tags_already_output)) { $this->element('ctag:tagged', array('rdf:resource' => $tagpage . '#concept')); continue; } $tagrss = common_local_url('tagrss', array('tag' => $tag->tag)); $this->elementStart('ctag:tagged'); $this->elementStart('ctag:Tag', array('rdf:about' => $tagpage . '#concept', 'ctag:label' => $tag->tag)); $this->element('foaf:page', array('rdf:resource' => $tagpage)); $this->element('rdfs:seeAlso', array('rdf:resource' => $tagrss)); $this->elementEnd('ctag:Tag'); $this->elementEnd('ctag:tagged'); $this->tags_already_output[] = $tag->tag; } } $this->elementEnd('item'); $this->creators[$creator_uri] = $profile; }
function clearTags() { $tag = new Notice_tag(); $tag->notice_id = $this->id; if ($tag->find()) { while ($tag->fetch()) { self::blow('profile:notice_ids_tagged:%d:%s', $this->profile_id, common_keyize($tag->tag)); self::blow('profile:notice_ids_tagged:%d:%s;last', $this->profile_id, common_keyize($tag->tag)); self::blow('notice_tag:notice_ids:%s', common_keyize($tag->tag)); self::blow('notice_tag:notice_ids:%s;last', common_keyize($tag->tag)); $tag->delete(); } } $tag->free(); }
protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped = null) { $nb = Bookmark::getByNotice($stored); if (empty($nb)) { common_log(LOG_ERR, "No bookmark for notice {$stored->id}"); parent::showContent(); return; } else { if (empty($nb->url)) { common_log(LOG_ERR, "No url for bookmark {$nb->id} for notice {$stored->id}"); parent::showContent(); return; } } $profile = $stored->getProfile(); // Whether to nofollow $attrs = array('href' => $nb->url, 'class' => 'bookmark-title'); $nf = common_config('nofollow', 'external'); if ($nf == 'never' || ($nf == 'sometimes' and $out instanceof ShowstreamAction)) { $attrs['rel'] = 'external'; } else { $attrs['rel'] = 'nofollow external'; } $out->elementStart('h3'); $out->element('a', $attrs, $nb->title); $out->elementEnd('h3'); // Replies look like "for:" tags $replies = $stored->getReplies(); $tags = $stored->getTags(); if (!empty($nb->description)) { $out->element('p', array('class' => 'bookmark-description'), $nb->description); } if (!empty($replies) || !empty($tags)) { $out->elementStart('ul', array('class' => 'bookmark-tags')); foreach ($replies as $reply) { $other = Profile::getKV('id', $reply); if (!empty($other)) { $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => $other->profileurl, 'title' => $other->getBestName()), sprintf('for:%s', $other->nickname)); $out->elementEnd('li'); $out->text(' '); } } foreach ($tags as $tag) { $tag = trim($tag); if (!empty($tag)) { $out->elementStart('li'); $out->element('a', array('rel' => 'tag', 'href' => Notice_tag::url($tag)), $tag); $out->elementEnd('li'); $out->text(' '); } } $out->elementEnd('ul'); } }
/** * Save a new notice bookmark * * @param Profile $profile To save the bookmark for * @param string $title Title of the bookmark * @param string $url URL of the bookmark * @param mixed $rawtags array of tags or string * @param string $description Description of the bookmark * @param array $options Options for the Notice::saveNew() * * @return Notice saved notice */ static function saveNew($profile, $title, $url, $rawtags, $description, $options = null) { if (!common_valid_http_url($url)) { throw new ClientException(_m('Only web bookmarks can be posted (HTTP or HTTPS).')); } $nb = self::getByURL($profile, $url); if (!empty($nb)) { // TRANS: Client exception thrown when trying to save a new bookmark that already exists. throw new ClientException(_m('Bookmark already exists.')); } if (empty($options)) { $options = array(); } if (array_key_exists('uri', $options)) { $other = Bookmark::getKV('uri', $options['uri']); if (!empty($other)) { // TRANS: Client exception thrown when trying to save a new bookmark that already exists. throw new ClientException(_m('Bookmark already exists.')); } } if (is_string($rawtags)) { if (empty($rawtags)) { $rawtags = array(); } else { $rawtags = preg_split('/[\\s,]+/', $rawtags); } } $nb = new Bookmark(); $nb->id = UUID::gen(); $nb->profile_id = $profile->id; $nb->url = $url; $nb->title = $title; $nb->description = $description; if (array_key_exists('created', $options)) { $nb->created = $options['created']; } else { $nb->created = common_sql_now(); } if (array_key_exists('uri', $options)) { $nb->uri = $options['uri']; } else { // FIXME: hacks to work around router bugs in // queue daemons $r = Router::get(); $path = $r->build('showbookmark', array('id' => $nb->id)); if (empty($path)) { $nb->uri = common_path('bookmark/' . $nb->id, false, false); } else { $nb->uri = common_local_url('showbookmark', array('id' => $nb->id), null, null, false); } } $nb->insert(); $tags = array(); $replies = array(); // filter "for:nickname" tags foreach ($rawtags as $tag) { if (strtolower(mb_substr($tag, 0, 4)) == 'for:') { // skip if done by caller if (!array_key_exists('replies', $options)) { $nickname = mb_substr($tag, 4); $other = common_relative_profile($profile, $nickname); if (!empty($other)) { $replies[] = $other->getUri(); } } } else { $tags[] = common_canonical_tag($tag); } } $hashtags = array(); $taglinks = array(); foreach ($tags as $tag) { $hashtags[] = '#' . $tag; $attrs = array('href' => Notice_tag::url($tag), 'rel' => $tag, 'class' => 'tag'); $taglinks[] = XMLStringer::estring('a', $attrs, $tag); } // Use user's preferences for short URLs, if possible try { $user = User::getKV('id', $profile->id); $shortUrl = File_redirection::makeShort($url, empty($user) ? null : $user); } catch (Exception $e) { // Don't let this stop us. $shortUrl = $url; } // TRANS: Bookmark content. // TRANS: %1$s is a title, %2$s is a short URL, %3$s is the bookmark description, // TRANS: %4$s is space separated list of hash tags. $content = sprintf(_m('"%1$s" %2$s %3$s %4$s'), $title, $shortUrl, $description, implode(' ', $hashtags)); // TRANS: Rendered bookmark content. // TRANS: %1$s is a URL, %2$s the bookmark title, %3$s is the bookmark description, // TRANS: %4$s is space separated list of hash tags. $rendered = sprintf(_m('<span class="xfolkentry">' . '<a class="taggedlink" href="%1$s">%2$s</a> ' . '<span class="description">%3$s</span> ' . '<span class="meta">%4$s</span>' . '</span>'), htmlspecialchars($url), htmlspecialchars($title), htmlspecialchars($description), implode(' ', $taglinks)); $options = array_merge(array('urls' => array($url), 'rendered' => $rendered, 'tags' => $tags, 'replies' => $replies, 'object_type' => ActivityObject::BOOKMARK), $options); if (!array_key_exists('uri', $options)) { $options['uri'] = $nb->uri; } try { $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options); } catch (Exception $e) { $nb->delete(); throw $e; } if (empty($saved)) { $nb->delete(); } return $saved; }
function saveGroups() { $enabled = common_config('inboxes', 'enabled'); if ($enabled !== true && $enabled !== 'transitional') { return; } /* extract all !group */ $count = preg_match_all('/(?:^|\\s)!([A-Za-z0-9]{1,64})/', strtolower($this->content), $match); if (!$count) { return true; } $profile = $this->getProfile(); /* Add them to the database */ foreach (array_unique($match[1]) as $nickname) { /* XXX: remote groups. */ $group = User_group::staticGet('nickname', $nickname); if (!$group) { continue; } // we automatically add a tag for every group name, too $tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname), 'notice_id' => $this->id)); if (is_null($tag)) { $this->saveTag($nickname); } if ($profile->isMember($group)) { $gi = new Group_inbox(); $gi->group_id = $group->id; $gi->notice_id = $this->id; $gi->created = common_sql_now(); $result = $gi->insert(); if (!$result) { common_log_db_error($gi, 'INSERT', __FILE__); } // FIXME: do this in an offline daemon $inbox = new Notice_inbox(); $UT = common_config('db', 'type') == 'pgsql' ? '"user"' : 'user'; $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' . "SELECT {$UT}.id, " . $this->id . ", '" . $this->created . "', 2 " . "FROM {$UT} JOIN group_member ON {$UT}.id = group_member.profile_id " . 'WHERE group_member.group_id = ' . $group->id . ' ' . 'AND NOT EXISTS (SELECT user_id, notice_id ' . 'FROM notice_inbox ' . "WHERE user_id = {$UT}.id " . 'AND notice_id = ' . $this->id . ' )'; if ($enabled === 'transitional') { $qry .= " AND {$UT}.inboxed = 1"; } $result = $inbox->query($qry); } } }