Пример #1
0
 public function testUnique()
 {
     $reps = 100;
     $ids = array();
     for ($i = 0; $i < $reps; $i++) {
         $ids[] = UUID::gen();
     }
     $this->assertEquals(count($ids), count(array_unique($ids)), "UUIDs must be unique");
 }
Пример #2
0
 /**
  * Save a vote on a question or answer
  *
  * @param Profile  $profile
  * @param QnA_Question the question being voted on
  * @param QnA_Answer   the answer being voted on
  * @param vote
  * @param array
  *
  * @return Void
  */
 static function save($profile, $question, $answer, $vote)
 {
     $v = new QnA_Vote();
     $v->id = UUID::gen();
     $v->profile_id = $profile->id;
     $v->question_id = $question->id;
     $v->answer_id = $answer->id;
     $v->vote = $vote;
     $v->created = common_sql_now();
     common_log(LOG_DEBUG, "Saving vote: {$v->id} {$v->vote}");
     $v->insert();
 }
Пример #3
0
 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;
 }
Пример #4
0
 function onEndRevokeRole($profile, $role)
 {
     $modlog = new ModLog();
     $modlog->id = UUID::gen();
     $modlog->profile_id = $profile->id;
     $scoped = Profile::current();
     if ($scoped instanceof Profile) {
         $modlog->moderator_id = $scoped->getID();
     }
     $modlog->role = $role;
     $modlog->is_grant = 0;
     $modlog->created = common_sql_now();
     $modlog->insert();
     return true;
 }
Пример #5
0
 static function saveNew(Profile $profile, $url, $options = array())
 {
     $vid = new Video();
     $vid->id = UUID::gen();
     $vid->profile_id = $profile->id;
     $vid->url = $url;
     $options['object_type'] = Video::OBJECT_TYPE;
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = common_local_url('showvideo', array('id' => $vid->id));
     }
     if (!array_key_exists('rendered', $options)) {
         $options['rendered'] = sprintf("<video src=\"%s\">Sorry, your browser doesn't support the video tag.</video>", $url);
     }
     $vid->uri = $options['uri'];
     $vid->insert();
     return Notice::saveNew($profile->id, '', 'web', $options);
 }
Пример #6
0
 static function saveNew(Profile $profile, $photo_uri, $thumb_uri, $title, $description, $options = array())
 {
     $photo = new Photo();
     $photo->id = UUID::gen();
     $photo->profile_id = $profile->id;
     $photo->photo_uri = $photo_uri;
     $photo->thumb_uri = $thumb_uri;
     $options['object_type'] = Photo::OBJECT_TYPE;
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = common_local_url('showphoto', array('id' => $photo->id));
     }
     if (!array_key_exists('rendered', $options)) {
         $options['rendered'] = sprintf("<img src=\"%s\" alt=\"%s\"></img>", $photo_uri, $title);
     }
     $photo->uri = $options['uri'];
     $photo->insert();
     return Notice::saveNew($profile->id, '', 'web', $options);
 }
Пример #7
0
 function saveNewFromNotice($notice, $event, $verb)
 {
     $other = RSVP::getKV('uri', $notice->uri);
     if (!empty($other)) {
         // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
         throw new ClientException(_m('RSVP already exists.'));
     }
     $profile = $notice->getProfile();
     try {
         $other = RSVP::getByKeys(['profile_id' => $profile->getID(), 'event_uri' => $event->getUri()]);
         // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
         throw new AlreadyFulfilledException(_m('RSVP already exists.'));
     } catch (NoResultException $e) {
         // No previous RSVP, so go ahead and add.
     }
     $rsvp = new RSVP();
     preg_match('/\\/([^\\/]+)\\/*/', $notice->uri, $match);
     $rsvp->id = $match[1] ? $match[1] : UUID::gen();
     $rsvp->profile_id = $profile->id;
     $rsvp->event_id = $event->id;
     $rsvp->response = self::codeFor($verb);
     $rsvp->created = $notice->created;
     $rsvp->uri = $notice->uri;
     $rsvp->insert();
     self::blow('rsvp:for-event:%s', $event->getUri());
     return $rsvp;
 }
Пример #8
0
 /**
  * Save a new poll notice
  *
  * @param Profile $profile
  * @param Poll    $poll the poll being responded to
  * @param int     $selection (1-based)
  * @param array   $opts (poll responses)
  *
  * @return Notice saved notice
  */
 static function saveNew($profile, $poll, $selection, $options = null)
 {
     if (empty($options)) {
         $options = array();
     }
     if (!$poll->isValidSelection($selection)) {
         // TRANS: Client exception thrown when responding to a poll with an invalid option.
         throw new ClientException(_m('Invalid poll selection.'));
     }
     $opts = $poll->getOptions();
     $answer = $opts[$selection - 1];
     $pr = new Poll_response();
     $pr->id = UUID::gen();
     $pr->profile_id = $profile->id;
     $pr->poll_id = $poll->id;
     $pr->selection = $selection;
     if (array_key_exists('created', $options)) {
         $pr->created = $options['created'];
     } else {
         $pr->created = common_sql_now();
     }
     if (array_key_exists('uri', $options)) {
         $pr->uri = $options['uri'];
     } else {
         $pr->uri = common_local_url('showpollresponse', array('id' => $pr->id));
     }
     common_log(LOG_DEBUG, "Saving poll response: {$pr->id} {$pr->uri}");
     $pr->insert();
     // TRANS: Notice content voting for a poll.
     // TRANS: %s is the chosen option in the poll.
     $content = sprintf(_m('voted for "%s"'), $answer);
     $link = '<a href="' . htmlspecialchars($poll->uri) . '">' . htmlspecialchars($answer) . '</a>';
     // TRANS: Rendered version of the notice content voting for a poll.
     // TRANS: %s a link to the poll with the chosen option as link description.
     $rendered = sprintf(_m('voted for "%s"'), $link);
     $tags = array();
     $options = array_merge(array('urls' => array(), 'rendered' => $rendered, 'tags' => $tags, 'reply_to' => $poll->getNotice()->id, 'object_type' => PollPlugin::POLL_RESPONSE_OBJECT), $options);
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = $pr->uri;
     }
     $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options);
     return $saved;
 }
Пример #9
0
 /**
  * Save a new answer notice
  *
  * @param Profile  $profile
  * @param Question $Question the question being answered
  * @param array
  *
  * @return Notice saved notice
  */
 static function saveNew($profile, $question, $text, $options = null)
 {
     if (empty($options)) {
         $options = array();
     }
     $answer = new QnA_Answer();
     $answer->id = UUID::gen();
     $answer->profile_id = $profile->id;
     $answer->question_id = $question->id;
     $answer->revisions = 0;
     $answer->best = 0;
     $answer->content = $text;
     $answer->created = common_sql_now();
     $answer->uri = common_local_url('qnashowanswer', array('id' => $answer->id));
     common_log(LOG_DEBUG, "Saving answer: {$answer->id}, {$answer->uri}");
     $answer->insert();
     $content = sprintf(_m('answered "%s"'), $question->title);
     $link = '<a href="' . htmlspecialchars($answer->uri) . '">' . htmlspecialchars($question->title) . '</a>';
     // TRANS: Rendered version of the notice content answering a question.
     // TRANS: %s a link to the question with question title as the link content.
     $rendered = sprintf(_m('answered "%s"'), $link);
     $tags = array();
     $replies = array();
     $options = array_merge(array('urls' => array(), 'content' => $content, 'rendered' => $rendered, 'tags' => $tags, 'replies' => $replies, 'reply_to' => $question->getNotice()->id, 'object_type' => self::OBJECT_TYPE), $options);
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = $answer->uri;
     }
     $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options);
     return $saved;
 }
Пример #10
0
 /**
  * Store a Bookmark object
  *
  * @param Profile $profile     To save the bookmark for
  * @param string  $title       Title of the bookmark
  * @param string  $url         URL of the bookmark
  * @param string  $description Description of the bookmark
  *
  * @return Bookmark the Bookmark object
  */
 static function saveActivityObject(ActivityObject $actobj, Notice $stored)
 {
     $url = null;
     // each extra element is array('tagname', array('attr'=>'val', ...), 'content')
     foreach ($actobj->extra as $extra) {
         if ($extra[1]['rel'] !== 'related') {
             continue;
         }
         if ($url === null && strlen($extra[1]['href']) > 0) {
             $url = $extra[1]['href'];
         } elseif ($url !== null) {
             // TRANS: Client exception thrown when a bookmark is formatted incorrectly.
             throw new ClientException(sprintf(_m('Expected exactly 1 link rel=related in a Bookmark, got %1$d.'), count($relLinkEls)));
         }
     }
     if (is_null($url)) {
         // TRANS: Client exception thrown when a bookmark is formatted incorrectly.
         throw new ClientException(sprintf(_m('Expected exactly 1 link rel=related in a Bookmark, got %1$d.'), count($relLinkEls)));
     }
     if (!strlen($actobj->title)) {
         throw new ClientException(_m('You must provide a non-empty title.'));
     }
     if (!common_valid_http_url($url)) {
         throw new ClientException(_m('Only web bookmarks can be posted (HTTP or HTTPS).'));
     }
     try {
         $object = self::getByURL($stored->getProfile(), $url);
         throw new ClientException(_m('You have already bookmarked this URL.'));
     } catch (NoResultException $e) {
         // Alright, so then we have to create it.
     }
     $nb = new Bookmark();
     $nb->id = UUID::gen();
     $nb->uri = $stored->getUri();
     $nb->profile_id = $stored->getProfile()->getID();
     $nb->title = $actobj->title;
     $nb->url = $url;
     $nb->description = $actobj->summary;
     $nb->created = $stored->created;
     $result = $nb->insert();
     if ($result === false) {
         throw new ServerException('Could not insert Bookmark into database!');
     }
     return $nb;
 }
Пример #11
0
 static function send($user, $group, $text)
 {
     if (!$user->hasRight(Right::NEWMESSAGE)) {
         // XXX: maybe break this out into a separate right
         // TRANS: Exception thrown when trying to send group private message without having the right to do that.
         // TRANS: %s is a user nickname.
         throw new Exception(sprintf(_m('User %s is not allowed to send private messages.'), $user->nickname));
     }
     Group_privacy_settings::ensurePost($user, $group);
     $text = $user->shortenLinks($text);
     // We use the same limits as for 'regular' private messages.
     if (Message::contentTooLong($text)) {
         // TRANS: Exception thrown when trying to send group private message that is too long.
         // TRANS: %d is the maximum meggage length.
         throw new Exception(sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()), Message::maxContent()));
     }
     // Valid! Let's do this thing!
     $gm = new Group_message();
     $gm->id = UUID::gen();
     $gm->uri = common_local_url('showgroupmessage', array('id' => $gm->id));
     $gm->from_profile = $user->id;
     $gm->to_group = $group->id;
     $gm->content = $text;
     // XXX: is this cool?!
     $gm->rendered = common_render_text($text);
     $gm->url = $gm->uri;
     $gm->created = common_sql_now();
     // This throws a conniption if there's a problem
     $gm->insert();
     $gm->distribute();
     return $gm;
 }
Пример #12
0
 function getUpload()
 {
     $imagefile = ImageFile::fromUpload('photo_upload');
     if ($imagefile === null) {
         throw new Exception(_('No file uploaded'));
     }
     $title = $this->trimmed('title');
     $description = $this->trimmed('description');
     $new_filename = UUID::gen() . image_type_to_extension($imagefile->type);
     move_uploaded_file($imagefile->filepath, INSTALLDIR . '/file/' . $new_filename);
     // XXX: we should be using https where we can. TODO: detect whether the server
     // supports this.
     $photo_uri = 'http://' . common_config('site', 'server') . '/file/' . $new_filename;
     $thumb_uri = $photo_uri;
     $photo = Photo::saveNew($profile, $photo_uri, $thumb_uri, $title, $description, $options);
 }
Пример #13
0
 function saveNew($profile, $event, $verb, $options = array())
 {
     if (array_key_exists('uri', $options)) {
         $other = RSVP::staticGet('uri', $options['uri']);
         if (!empty($other)) {
             // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
             throw new ClientException(_m('RSVP already exists.'));
         }
     }
     $other = RSVP::pkeyGet(array('profile_id' => $profile->id, 'event_id' => $event->id));
     if (!empty($other)) {
         // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
         throw new ClientException(_m('RSVP already exists.'));
     }
     $rsvp = new RSVP();
     $rsvp->id = UUID::gen();
     $rsvp->profile_id = $profile->id;
     $rsvp->event_id = $event->id;
     $rsvp->response = self::codeFor($verb);
     if (array_key_exists('created', $options)) {
         $rsvp->created = $options['created'];
     } else {
         $rsvp->created = common_sql_now();
     }
     if (array_key_exists('uri', $options)) {
         $rsvp->uri = $options['uri'];
     } else {
         $rsvp->uri = common_local_url('showrsvp', array('id' => $rsvp->id));
     }
     $rsvp->insert();
     self::blow('rsvp:for-event:%s', $event->id);
     // XXX: come up with something sexier
     $content = $rsvp->asString();
     $rendered = $rsvp->asHTML();
     $options = array_merge(array('object_type' => $verb), $options);
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = $rsvp->uri;
     }
     $eventNotice = $event->getNotice();
     if (!empty($eventNotice)) {
         $options['reply_to'] = $eventNotice->id;
     }
     $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options);
     return $saved;
 }
Пример #14
0
 /**
  * Save a new question notice
  *
  * @param Profile $profile
  * @param string  $question
  * @param string  $title
  * @param string  $description
  * @param array   $option // and whatnot
  *
  * @return Notice saved notice
  */
 static function saveNew($profile, $title, $description, $options = array())
 {
     $q = new QnA_Question();
     $q->id = UUID::gen();
     $q->profile_id = $profile->id;
     $q->title = $title;
     $q->description = $description;
     if (array_key_exists('created', $options)) {
         $q->created = $options['created'];
     } else {
         $q->created = common_sql_now();
     }
     if (array_key_exists('uri', $options)) {
         $q->uri = $options['uri'];
     } else {
         $q->uri = common_local_url('qnashowquestion', array('id' => $q->id));
     }
     common_log(LOG_DEBUG, "Saving question: {$q->id} {$q->uri}");
     $q->insert();
     if (Notice::contentTooLong($q->title . ' ' . $q->uri)) {
         $max = Notice::maxContent();
         $uriLen = mb_strlen($q->uri);
         $targetLen = $max - ($uriLen + 15);
         $title = mb_substr($q->title, 0, $targetLen) . '…';
     }
     $content = $title . ' ' . $q->uri;
     $link = '<a href="' . htmlspecialchars($q->uri) . '">' . htmlspecialchars($q->title) . '</a>';
     // TRANS: Rendered version of the notice content creating a question.
     // TRANS: %s a link to the question as link description.
     $rendered = sprintf(_m('Question: %s'), $link);
     $tags = array('question');
     $replies = array();
     $options = array_merge(array('urls' => array(), 'rendered' => $rendered, 'tags' => $tags, 'replies' => $replies, 'object_type' => self::OBJECT_TYPE), $options);
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = $q->uri;
     }
     $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options);
     return $saved;
 }
Пример #15
0
 /**
  * Save a new poll notice
  *
  * @param Profile $profile
  * @param string  $question
  * @param array   $opts (poll responses)
  *
  * @return Notice saved notice
  */
 static function saveNew($profile, $question, $opts, $options = null)
 {
     if (empty($options)) {
         $options = array();
     }
     $p = new Poll();
     $p->id = UUID::gen();
     $p->profile_id = $profile->id;
     $p->question = $question;
     $p->options = implode("\n", $opts);
     if (array_key_exists('created', $options)) {
         $p->created = $options['created'];
     } else {
         $p->created = common_sql_now();
     }
     if (array_key_exists('uri', $options)) {
         $p->uri = $options['uri'];
     } else {
         $p->uri = common_local_url('showpoll', array('id' => $p->id));
     }
     common_log(LOG_DEBUG, "Saving poll: {$p->id} {$p->uri}");
     $p->insert();
     // TRANS: Notice content creating a poll.
     // TRANS: %1$s is the poll question, %2$s is a link to the poll.
     $content = sprintf(_m('Poll: %1$s %2$s'), $question, $p->uri);
     $link = '<a href="' . htmlspecialchars($p->uri) . '">' . htmlspecialchars($question) . '</a>';
     // TRANS: Rendered version of the notice content creating a poll.
     // TRANS: %s is a link to the poll with the question as link description.
     $rendered = sprintf(_m('Poll: %s'), $link);
     $tags = array('poll');
     $replies = array();
     $options = array_merge(array('urls' => array(), 'rendered' => $rendered, 'tags' => $tags, 'replies' => $replies, 'object_type' => PollPlugin::POLL_OBJECT), $options);
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = $p->uri;
     }
     $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options);
     return $saved;
 }
Пример #16
0
 /**
  * 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;
 }
Пример #17
0
 static function saveNew($profile, $start_time, $end_time, $title, $location, $description, $url, $options = array())
 {
     if (array_key_exists('uri', $options)) {
         $other = Happening::getKV('uri', $options['uri']);
         if (!empty($other)) {
             // TRANS: Client exception thrown when trying to create an event that already exists.
             throw new ClientException(_m('Event already exists.'));
         }
     }
     $ev = new Happening();
     $ev->id = UUID::gen();
     $ev->profile_id = $profile->id;
     $ev->start_time = common_sql_date($start_time);
     $ev->end_time = common_sql_date($end_time);
     $ev->title = $title;
     $ev->location = $location;
     $ev->description = $description;
     $ev->url = $url;
     if (array_key_exists('created', $options)) {
         $ev->created = $options['created'];
     } else {
         $ev->created = common_sql_now();
     }
     if (array_key_exists('uri', $options)) {
         $ev->uri = $options['uri'];
     } else {
         $ev->uri = common_local_url('showevent', array('id' => $ev->id));
     }
     $ev->insert();
     // XXX: does this get truncated?
     // TRANS: Event description. %1$s is a title, %2$s is start time, %3$s is end time,
     // TRANS: %4$s is location, %5$s is a description.
     $content = sprintf(_m('"%1$s" %2$s - %3$s (%4$s): %5$s'), $title, common_exact_date($ev->start_time), common_exact_date($ev->end_time), $location, $description);
     // TRANS: Rendered microformats2 tagged event description.
     // TRANS: %1$s is a title, %2$s is start time, %3$s is start time,
     // TRANS: %4$s is end time, %5$s is end time, %6$s is location, %7$s is description.
     // TRANS: Class names should not be translated.
     $rendered = sprintf(_m('<div class="h-event">' . '<p class="p-name p-summary">%1$s</p> ' . '<time class="dt-start" datetime="%2$s">%3$s</time> - ' . '<time class="dt-end" datetime="%4$s">%5$s</time> ' . '(<span class="p-location">%6$s</span>): ' . '<div class="p-description">%7$s</div> ' . '</div>'), htmlspecialchars($title), htmlspecialchars(common_date_iso8601($ev->start_time)), htmlspecialchars(common_exact_date($ev->start_time)), htmlspecialchars(common_date_iso8601($ev->end_time)), htmlspecialchars(common_exact_date($ev->end_time)), htmlspecialchars($location), htmlspecialchars($description));
     $options = array_merge(array('object_type' => Happening::OBJECT_TYPE), $options);
     if (!array_key_exists('uri', $options)) {
         $options['uri'] = $ev->uri;
     }
     if (!empty($url)) {
         $options['urls'] = array($url);
     }
     $saved = Notice::saveNew($profile->id, $content, array_key_exists('source', $options) ? $options['source'] : 'web', $options);
     return $saved;
 }