$_REQUEST['first_comment'] .= '<div>' . Skin::build_list(Files::list_for_anchor_and_name('article:' . $_REQUEST['id'], $uploaded, 'compact'), 'compact') . '</div>'; } elseif ($file =& Files::get_by_anchor_and_name('article:' . $_REQUEST['id'], $uploaded)) { $_REQUEST['first_comment'] .= '<div>' . Codes::render_object('file', $file['id']) . '</div>'; // silently delete the previous file if the name has changed if (isset($file['file_name']) && $file['file_name'] != $uploaded) { Safe::unlink($file_path . '/' . $file['file_name']); } } } // capture first comment too if (isset($_REQUEST['first_comment']) && $_REQUEST['first_comment']) { include_once $context['path_to_root'] . 'comments/comments.php'; $fields = array(); $fields['anchor'] = 'article:' . $_REQUEST['id']; $fields['description'] = $_REQUEST['first_comment']; Comments::post($fields); } // post an overlay, with the new article id --don't stop on error if (is_object($overlay)) { $overlay->remember('insert', $_REQUEST, 'article:' . $_REQUEST['id']); } // increment the post counter of the surfer Users::increment_posts(Surfer::get_id()); // do whatever is necessary on page publication if (isset($_REQUEST['publish_date']) && $_REQUEST['publish_date'] > NULL_DATE) { Articles::finalize_publication($anchor, $_REQUEST, $overlay, isset($_REQUEST['silent']) && $_REQUEST['silent'] == 'Y', isset($_REQUEST['notify_followers']) && $_REQUEST['notify_followers'] == 'Y'); // else do whatever is necessary on page submission } else { Articles::finalize_submission($anchor, $_REQUEST, $overlay); } // get the new item
<?php require_once 'common.php'; if ($current_user) { $keys = array('comment', 'id'); foreach ($keys as $key) { if (array_key_exists($key, $_POST)) { ${$key} = $_POST[$key]; } else { ${$key} = false; } } if ($comment and $id) { $c = new Comments($id); $c->post($current_user, $comment); } } header("Location: /index.php?id={$id}");
/** * remember the last action for this article * * This function is called by related items. What does it do? * - On image creation, the adequate code is added to the description field to let the image be displayed inline * - On icon selection, the icon field is updated * - On thumbnail image selection, the thumbnail image field is updated * - On location creation, some code is inserted in the description field to display location name inline * - On table creation, some code is inserted in the description field to display the table inline * * @see articles/article.php * @see articles/edit.php * @see shared/anchor.php * * @param string one of the pre-defined action code * @param string the id of the item related to this update * @param boolean TRUE to not change the edit date of this anchor, default is FALSE */ function touch($action, $origin = NULL, $silently = FALSE) { global $context; // we make extensive use of comments below include_once $context['path_to_root'] . 'comments/comments.php'; // don't go further on import if (preg_match('/import$/i', $action)) { return; } // no article bound if (!isset($this->item['id'])) { return; } // delegate to overlay if (is_object($this->overlay) && $this->overlay->touch($action, $origin, $silently) === false) { return; // stop on false } // clear floating objects if ($action == 'clear') { $this->item['description'] .= ' [clear]'; $query = "UPDATE " . SQL::table_name('articles') . " SET description='" . SQL::escape($this->item['description']) . "'" . " WHERE id = " . SQL::escape($this->item['id']); SQL::query($query); return; } // get the related overlay, if any if (!isset($this->overlay)) { $this->overlay = NULL; if (isset($this->item['overlay'])) { $this->overlay = Overlay::load($this->item, 'article:' . $this->item['id']); } } // components of the query $query = array(); // a new comment has been posted if ($action == 'comment:create') { // purge oldest comments Comments::purge_for_anchor('article:' . $this->item['id']); // file upload } elseif ($action == 'file:create' || $action == 'file:upload') { // actually, several files have been added $label = ''; if (!$origin) { // only when comments are allowed if (!Articles::has_option('no_comments', $this->anchor, $this->item)) { // remember this as an automatic notification $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; $fields['description'] = i18n::s('Several files have been added'); $fields['type'] = 'notification'; Comments::post($fields); } // one file has been added } elseif (!Codes::check_embedded($this->item['description'], 'embed', $origin) && ($item = Files::get($origin, TRUE))) { // this file is eligible for being embedded in the page if (isset($item['file_name']) && Files::is_embeddable($item['file_name'])) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { $label = '[embed=' . $origin . ']'; } // else add a comment to take note of the upload } else { // only when comments are allowed if (!Articles::has_option('no_comments', $this->anchor, $this->item)) { // remember this as an automatic notification $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; if ($action == 'file:create') { $fields['description'] = '[file=' . $item['id'] . ',' . $item['file_name'] . ']'; } else { $fields['description'] = '[download=' . $item['id'] . ',' . $item['file_name'] . ']'; } Comments::post($fields); } } } // we are in some interactive thread if ($origin && $this->has_option('view_as_chat')) { // default is to download the file if (!$label) { $label = '[download=' . $origin . ']'; } // this is the first contribution to the thread if (!($comment = Comments::get_newest_for_anchor('article:' . $this->item['id']))) { $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; $fields['description'] = $label; // this is a continuated contribution from this authenticated surfer } elseif ($comment['type'] != 'notification' && Surfer::get_id() && (isset($comment['create_id']) && Surfer::get_id() == $comment['create_id'])) { $comment['description'] .= BR . $label; $fields = $comment; // else process the contribution as a new comment } else { $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; $fields['description'] = $label; } // only when comments are allowed if (!Articles::has_option('no_comments', $this->anchor, $this->item)) { Comments::post($fields); } // include flash videos in a regular page } elseif ($origin && $label) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' ' . $label) . "'"; } // suppress references to a deleted file } elseif ($action == 'file:delete' && $origin) { // suppress reference in main description field $text = Codes::delete_embedded($this->item['description'], 'download', $origin); $text = Codes::delete_embedded($text, 'embed', $origin); $text = Codes::delete_embedded($text, 'file', $origin); // save changes $query[] = "description = '" . SQL::escape($text) . "'"; // append a reference to a new image to the description } elseif ($action == 'image:create' && $origin) { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { // list has already started if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) { $this->item['description'] .= ' [image=' . $origin . ']'; } else { $this->item['description'] .= "\n\n" . '[image=' . $origin . ']'; } $query[] = "description = '" . SQL::escape($this->item['description']) . "'"; } } // also use it as thumnail if none has been defined yet if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) { include_once $context['path_to_root'] . 'images/images.php'; if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } // refresh stamp only if image update occurs within 6 hours after last edition if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) { $silently = TRUE; } // suppress a reference to an image that has been deleted } elseif ($action == 'image:delete' && $origin) { // suppress reference in main description field $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'"; // suppress references as icon and thumbnail as well include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } if ($url = Images::get_thumbnail_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } } // set an existing image as the article icon } elseif ($action == 'image:set_as_icon' && $origin) { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { $query[] = "icon_url = '" . SQL::escape($url) . "'"; } // also use it as thumnail if none has been defined yet if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } // set an existing image as the article thumbnail } elseif ($action == 'image:set_as_thumbnail' && $origin) { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } // do not remember minor changes $silently = TRUE; // append a new image, and set it as the article thumbnail } elseif ($action == 'image:set_as_both' && $origin) { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } // do not remember minor changes $silently = TRUE; // add a reference to a location in the article description } elseif ($action == 'location:create' && $origin) { if (!Codes::check_embedded($this->item['description'], 'location', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [location=' . $origin . ']') . "'"; } // suppress a reference to a location that has been deleted } elseif ($action == 'location:delete' && $origin) { $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'location', $origin)) . "'"; // add a reference to a new table in the article description } elseif ($action == 'table:create' && $origin) { if (!Codes::check_embedded($this->item['description'], 'table', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . "\n" . '[table=' . $origin . ']' . "\n") . "'"; } // suppress a reference to a table that has been deleted } elseif ($action == 'table:delete' && $origin) { $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'"; } // stamp the update if (!$silently) { $query[] = "edit_name='" . SQL::escape(Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(Surfer::get_id()) . "," . "edit_address='" . SQL::escape(Surfer::get_email_address()) . "'," . "edit_action='" . SQL::escape($action) . "'," . "edit_date='" . gmstrftime('%Y-%m-%d %H:%M:%S') . "'"; } // update the database if (count($query)) { $query = "UPDATE " . SQL::table_name('articles') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']); SQL::query($query); } // add this page to the watch list of the contributor, on any action if (Surfer::get_id()) { Members::assign('article:' . $this->item['id'], 'user:'******'article:' . $this->item['id'], $this->item['active']); // always clear the cache, even on no update Articles::clear($this->item); // get the parent if (!$this->anchor) { $this->anchor = Anchors::get($this->item['anchor']); } // propagate the touch upwards if (is_object($this->anchor)) { $this->anchor->touch('article:update', $this->item['id'], TRUE); } }
if (!($item = Comments::get_newest_for_anchor($anchor->get_reference()))) { $fields = array(); $fields['anchor'] = $anchor->get_reference(); $fields['description'] = $_REQUEST['message']; // this is a continuated contribution from this authenticated surfer } elseif ($item['type'] != 'notification' && Surfer::get_id() && (isset($item['create_id']) && Surfer::get_id() == $item['create_id']) && $continuity_limit < $item['edit_date']) { $item['description'] .= BR . $_REQUEST['message']; $fields = $item; // else process the contribution as a new comment } else { $fields = array(); $fields['anchor'] = $anchor->get_reference(); $fields['description'] = $_REQUEST['message']; } // actual database update if (!($fields['id'] = Comments::post($fields))) { Safe::header('Status: 500 Internal Error', TRUE, 500); die(i18n::s('Your contribution has not been posted.')); } // touch the related anchor, but don't notify watchers $anchor->touch('comment:thread', $fields['id']); // clear cache Comments::clear($fields); // thread update will trigger screen repaint through separate pending call of this script die('OK'); // get some updates } else { // we are running global $pending; $pending = TRUE; // invoked on shutdown
/** * remember the last action for this section * * @see articles/article.php * @see shared/anchor.php * * @param string the description of the last action * @param string the id of the item related to this update * @param boolean TRUE to not change the edit date of this anchor, default is FALSE */ function touch($action, $origin = NULL, $silently = FALSE) { global $context; // we make extensive use of comments below include_once $context['path_to_root'] . 'comments/comments.php'; // don't go further on import if (preg_match('/import$/i', $action)) { return; } // no section bound if (!isset($this->item['id'])) { return; } // delegate to overlay if (is_object($this->overlay) && $this->overlay->touch($action, $origin, $silently) === false) { return; // stop on false } // sanity check if (!$origin) { logger::remember('sections/section.php: unexpected NULL origin at touch()'); return; } // components of the query $query = array(); // a new page has been added to the section if ($action == 'article:publish' || $action == 'article:submit') { // limit the number of items attached to this section if (isset($this->item['maximum_items']) && $this->item['maximum_items'] > 10) { Articles::purge_for_anchor('section:' . $this->item['id'], $this->item['maximum_items']); } // a new comment has been posted } elseif ($action == 'comment:create') { // purge oldest comments Comments::purge_for_anchor('section:' . $this->item['id']); // file upload } elseif ($action == 'file:create' || $action == 'file:upload') { // actually, several files have been added $label = ''; if (!$origin) { $fields = array(); $fields['anchor'] = 'section:' . $this->item['id']; $fields['description'] = i18n::s('Several files have been added'); $fields['type'] = 'notification'; Comments::post($fields); // one file has been added } elseif (!Codes::check_embedded($this->item['description'], 'embed', $origin) && ($item = Files::get($origin, TRUE))) { // this file is eligible for being embedded in the page if (isset($item['file_name']) && Files::is_embeddable($item['file_name'])) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { $label = '[embed=' . $origin . ']'; } // else add a comment to take note of the upload } elseif (Comments::allow_creation($this->item, null, 'section')) { $fields = array(); $fields['anchor'] = 'section:' . $this->item['id']; if ($action == 'file:create') { $fields['description'] = '[file=' . $item['id'] . ',' . $item['file_name'] . ']'; } else { $fields['description'] = '[download=' . $item['id'] . ',' . $item['file_name'] . ']'; } Comments::post($fields); } } // include flash videos in a regular page if ($label) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' ' . $label) . "'"; } // suppress references to a deleted file } elseif ($action == 'file:delete') { // suppress reference in main description field $text = Codes::delete_embedded($this->item['description'], 'download', $origin); $text = Codes::delete_embedded($text, 'embed', $origin); $text = Codes::delete_embedded($text, 'file', $origin); // save changes $query[] = "description = '" . SQL::escape($text) . "'"; // append a reference to a new image to the description } elseif ($action == 'image:create') { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { // list has already started if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } else { $query[] = "description = '" . SQL::escape($this->item['description'] . "\n\n" . '[image=' . $origin . ']') . "'"; } } } // also use it as thumnail if none has been defined yet if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) { include_once $context['path_to_root'] . 'images/images.php'; if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } // refresh stamp only if image update occurs within 6 hours after last edition if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) { $silently = TRUE; } // suppress a reference to an image that has been deleted } elseif ($action == 'image:delete') { // suppress reference in main description field $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'"; // suppress references as icon and thumbnail as well include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } if ($url = Images::get_thumbnail_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } } // set an existing image as the section icon } elseif ($action == 'image:set_as_icon') { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { $query[] = "icon_url = '" . SQL::escape($url) . "'"; } // also use it as thumnail if none has been defined yet if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } elseif ($origin) { $query[] = "icon_url = '" . SQL::escape($origin) . "'"; } $silently = TRUE; // set an existing image as the section thumbnail } elseif ($action == 'image:set_as_thumbnail') { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } $silently = TRUE; // append a new image, and set it as the article thumbnail } elseif ($action == 'image:set_as_both') { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } // do not remember minor changes $silently = TRUE; // add a reference to a new table in the section description } elseif ($action == 'table:create') { if (!Codes::check_embedded($this->item['description'], 'table', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [table=' . $origin . ']') . "'"; } // suppress a reference to a table that has been deleted } elseif ($action == 'table:delete') { $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'"; } // stamp the update if (!$silently) { $query[] = "edit_name='" . SQL::escape(Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(Surfer::get_id()) . "," . "edit_address='" . SQL::escape(Surfer::get_email_address()) . "'," . "edit_action='{$action}'," . "edit_date='" . SQL::escape(gmstrftime('%Y-%m-%d %H:%M:%S')) . "'"; } // update the database if (@count($query)) { $query = "UPDATE " . SQL::table_name('sections') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']); SQL::query($query); } // always clear the cache, even on no update Sections::clear($this->item); // get the parent if (!$this->anchor) { $this->anchor = Anchors::get($this->item['anchor']); } // propagate the touch upwards silently -- we only want to purge the cache if (is_object($this->anchor)) { $this->anchor->touch('section:touch', $this->item['id'], TRUE); } }
/** * create a page out of a textual entity * * If a target is provided, it is extended with the text of this entity. * Else if the anchor is an article, a comment is created. Otherwise an article is created. * * @param array of entity attributes * @param string the textual entity to process * @param array poster attributes * @param string an optional anchor (e.g., 'article:123') * @param string reference of the object to be extended, if any * @return string reference to the created or updated object, or NULL */ public static function submit_page($entity_headers, $text, $user, $anchor = NULL, $target = NULL) { global $context; // retrieve queue parameters list($server, $account, $password, $allowed, $match, $section, $options, $hooks, $prefix, $suffix) = $context['mail_queue']; // preserve breaks $text = preg_replace('/\\s*<(br|div|h|p)/is', "\n\n<\$1", $text); // suppress dangerous html tags $text = strip_tags($text, $context['users_allowed_tags']); // trim white spaces while (TRUE) { $text = trim($text, " \t\r\n"); if (!strncmp($text, '<br>', 4)) { $text = substr($text, 4); } elseif (!strncmp($text, '<br/>', 5)) { $text = substr($text, 5); } elseif (!strncmp($text, '<br />', 6)) { $text = substr($text, 6); } else { break; } } // parse article content include_once $context['path_to_root'] . 'articles/article.php'; $article = new Article(); $entry_fields = array(); $entry_fields = $article->parse($text, $entry_fields); // trim the header if ($prefix) { $tokens = explode($prefix, $entry_fields['description']); if (isset($tokens[1])) { $entry_fields['description'] = $tokens[1]; } else { $entry_fields['description'] = $tokens[0]; } } // trim the signature if ($suffix) { list($entry_fields['description'], $dropped) = explode($suffix, $entry_fields['description']); } // strip extra text $entry_fields['description'] = trim(preg_replace('/\\(See attached file: [^\\)]+?\\)/', '', $entry_fields['description'])); // anchor this item to something $entry_fields['anchor'] = $anchor; // make a title if (!isset($entry_fields['title'])) { $entry_fields['title'] = $context['mail_subject']; } // message creation stamp $entry_fields['create_date'] = gmstrftime('%Y-%m-%d %H:%M:%S', strtotime($context['mail_date'])); if (!isset($entry_fields['create_name'])) { $entry_fields['create_name'] = $user['nick_name']; } if (!isset($entry_fields['create_id'])) { $entry_fields['create_id'] = $user['id']; } if (!isset($entry_fields['create_address'])) { $entry_fields['create_address'] = $user['email']; } // message edition stamp $entry_fields['edit_date'] = gmstrftime('%Y-%m-%d %H:%M:%S', time()); if (!isset($entry_fields['edit_name'])) { $entry_fields['edit_name'] = $user['nick_name']; } if (!isset($entry_fields['edit_id'])) { $entry_fields['edit_id'] = $user['id']; } if (!isset($entry_fields['edit_address'])) { $entry_fields['edit_address'] = $user['email']; } // we have to extend an existing article --this entity is mutable if ($target && !strncmp($target, 'article:', 8) && ($article = Articles::get(substr($target, 8), TRUE))) { // append the text to article description field $fields = array(); $fields['id'] = $article['id']; $fields['description'] = $article['description'] . $entry_fields['description']; $fields['silent'] = TRUE; Articles::put_attributes($fields); return $target; // we have to extend an existing comment --this entity is mutable } elseif ($target && !strncmp($target, 'comment:', 8) && ($comment = Comments::get(substr($target, 8), TRUE))) { // append the text to comment description field $comment['description'] .= $entry_fields['description']; Comments::post($comment); return $target; // we have to comment an existing page } elseif (!strncmp($anchor, 'article:', 8)) { // insert comment in the database if (!($entry_fields['id'] = Comments::post($entry_fields))) { Logger::remember('agents/messages.php: ' . Logger::error_pop()); return NULL; } // debug, if required to do so if ($context['debug_messages'] == 'Y') { Logger::remember('agents/messages.php: Messages::submit_page() as a comment', $entry_fields, 'debug'); } // increment the post counter of the surfer Users::increment_posts($user['id']); // clear cache $parent = Anchors::get($entry_fields['anchor']); // touch the related anchor if (is_object($parent) && isset($entry_fields['id'])) { $parent->touch('comment:create', $entry_fields['id'], TRUE); } return 'comment:' . $entry_fields['id']; // create a new page } else { // publish automatically, if required to do so $section = Anchors::get($entry_fields['anchor']); if (isset($context['users_with_auto_publish']) && $context['users_with_auto_publish'] == 'Y' || preg_match('/\\bauto_publish\\b/i', $options) || is_object($section) && $section->has_option('auto_publish')) { $entry_fields['publish_date'] = gmstrftime('%Y-%m-%d %H:%M:%S', time()); if (!isset($entry_fields['publish_name'])) { $entry_fields['publish_name'] = $user['nick_name']; } if (!isset($entry_fields['publish_id'])) { $entry_fields['publish_id'] = $user['id']; } if (!isset($entry_fields['publish_address'])) { $entry_fields['publish_address'] = $user['email']; } } // ensure we are using ids instead of nicknames if (is_object($section)) { $entry_fields['anchor'] = $section->get_reference(); } // save in the database if (!($entry_fields['id'] = Articles::post($entry_fields))) { Logger::remember('agents/messages.php: ' . Logger::error_pop()); return NULL; } // debugging log if (isset($context['debug_messages']) && $context['debug_messages'] == 'Y') { $entry_fields['description'] = substr($entry_fields['description'], 0, 1024); Logger::remember('agents/messages.php: Messages::submit_page() as an article', $entry_fields, 'debug'); } // increment the post counter of the surfer Users::increment_posts($user['id']); // do whatever is necessary on page creation if (isset($entry_fields['publish_date']) && $entry_fields['publish_date'] > NULL_DATE) { Articles::finalize_publication($section, $entry_fields); } else { Articles::finalize_submission($section, $entry_fields); } // get the new item $article = Anchors::get($anchor); // if replies are allowed if (!preg_match('/\\bno_reply\\b/i', $options)) { // let the sender know about his post if (isset($entry_fields['publish_date']) && $entry_fields['publish_date'] > NULL_DATE) { $splash = i18n::s("The page received by e-mail has been successfully published. Please review it now to ensure that it reflects your mind."); } else { $splash = i18n::s("The page received by e-mail has been posted. Don't forget to read it online. Then click on the Publish command to make it publicly available."); } $message = '<p>' . $splash . '</p>' . '<p><a href="' . $context['url_to_home'] . $context['url_to_root'] . $article->get_url() . '">' . $article->get_title() . '</a></p>' . '<div>' . $article->get_teaser('basic') . '</div>' . '<p>' . i18n::c('Thank you for your contribution') . '</p>'; // enable threading $headers = Mailer::set_thread($section); // send a mail message Mailer::notify(NULL, $post_sender, 'Re: ' . $post_subject, $message, $headers); } // reference to the new page return 'article:' . $entry_fields['id']; } // job ends return NULL; }
/** * duplicate all comments for a given anchor * * This function duplicates records in the database, and changes anchors * to attach new records as per second parameter. * * @param string the source anchor * @param string the target anchor * @return int the number of duplicated records * * @see shared/anchors.php */ public static function duplicate_for_anchor($anchor_from, $anchor_to) { global $context; // look for records attached to this anchor $count = 0; $query = "SELECT * FROM " . SQL::table_name('comments') . " WHERE anchor LIKE '" . SQL::escape($anchor_from) . "'"; if (($result = SQL::query($query)) && SQL::count($result)) { // the list of transcoded strings $transcoded = array(); // process all matching records one at a time while ($item = SQL::fetch($result)) { // a new id will be allocated $old_id = $item['id']; unset($item['id']); // target anchor $item['anchor'] = $anchor_to; // actual duplication if ($new_id = Comments::post($item)) { // more pairs of strings to transcode $transcoded[] = array('/\\[comment=' . preg_quote($old_id, '/') . '/i', '[comment=' . $new_id); // duplicate elements related to this item Anchors::duplicate_related_to('comment:' . $old_id, 'comment:' . $new_id); // stats $count++; } } // transcode in anchor if ($anchor = Anchors::get($anchor_to)) { $anchor->transcode($transcoded); } } // number of duplicated records return $count; }
if (Articles::post($fields)) { $text .= sprintf(i18n::s('A page "%s" has been created.'), $fields['nick_name']) . BR . "\n"; } else { $text .= Logger::error_pop() . BR . "\n"; } } // comments // $text .= Skin::build_block(i18n::s('Comments'), 'subtitle'); // add a sample comment to 'my_article' if ($anchor = Articles::lookup('my_article')) { $fields = array(); $fields['anchor'] = $anchor; $fields['description'] = i18n::c('Hello world'); $fields['edit_name'] = $names[rand(0, 2)]; if (Comments::post($fields)) { $text .= sprintf(i18n::s('Comments have been added to "%s".'), 'my_article') . BR . "\n"; } else { $text .= Logger::error_pop() . BR . "\n"; } } // tables // $text .= Skin::build_block(i18n::s('Tables'), 'subtitle'); // 'my_articles' article if (Tables::get('my_articles')) { $text .= i18n::s('A sample "my_articles" table already exists.') . BR . "\n"; } elseif ($anchor = Articles::lookup('my_article')) { $fields = array(); $fields['anchor'] = $anchor; $fields['nick_name'] = 'my_articles';
/** * remember an action once it's done * * This function saves data into the table [code]yacs_issues[/code]. * * @see overlays/overlay.php * * @param string the action 'insert', 'update' or 'delete' * @param array the hosting record * @param string reference of the hosting record (e.g., 'article:123') * @return FALSE on error, TRUE otherwise */ function remember($action, $host, $reference) { global $context; // locate anchor on 'insert' if ($reference) { $this->anchor = Anchors::get($reference); } // remember data from the anchor $this->attributes['anchor_reference'] = ''; $this->attributes['anchor_title'] = ''; $this->attributes['anchor_url'] = ''; if (is_callable(array($this->anchor, 'get_url'))) { $this->attributes['anchor_reference'] = $this->anchor->get_reference(); $this->attributes['anchor_title'] = $this->anchor->get_title(); $this->attributes['anchor_url'] = $this->anchor->get_url(); } // set default values for this editor Surfer::check_default_editor($this->attributes); // default date values if (!isset($this->attributes['create_date']) || $this->attributes['create_date'] <= NULL_DATE) { $this->attributes['create_date'] = $this->attributes['edit_date']; } if (!isset($this->attributes['qualification_date']) || $this->attributes['qualification_date'] <= NULL_DATE) { $this->attributes['qualification_date'] = NULL_DATE; } if (!isset($this->attributes['analysis_date']) || $this->attributes['analysis_date'] <= NULL_DATE) { $this->attributes['analysis_date'] = NULL_DATE; } if (!isset($this->attributes['resolution_date']) || $this->attributes['resolution_date'] <= NULL_DATE) { $this->attributes['resolution_date'] = NULL_DATE; } if (!isset($this->attributes['close_date']) || $this->attributes['close_date'] <= NULL_DATE) { $this->attributes['close_date'] = NULL_DATE; } // add a notification to the anchor page $comments = array(); // build the update query switch ($action) { case 'delete': $query = "DELETE FROM " . SQL::table_name('issues') . " WHERE anchor LIKE '" . $this->attributes['anchor_reference'] . "'"; break; case 'insert': $comments[] = i18n::s('Page has been created'); // set host owner, if any if (isset($this->attributes['owner']) && ($user = Users::get($this->attributes['owner'])) && $user['id'] != Surfer::get_id()) { $fields = array(); $fields['owner_id'] = $user['id']; $this->anchor->set_values($fields); Members::assign('user:'******'id'], $this->anchor->get_reference()); Members::assign($this->anchor->get_reference(), 'user:'******'id']); $comments[] = sprintf(i18n::s('Owner has been changed to %s'), Skin::build_link(Users::get_permalink($user), $user['full_name'])); } $query = "INSERT INTO " . SQL::table_name('issues') . " SET \n" . "anchor='" . SQL::escape($this->attributes['anchor_reference']) . "', \n" . "anchor_url='" . SQL::escape($this->attributes['anchor_url']) . "', \n" . "color='" . SQL::escape(isset($this->attributes['color']) ? $this->attributes['color'] : 'green') . "', \n" . "status='" . SQL::escape(isset($this->attributes['status']) ? $this->attributes['status'] : 'on-going:suspect') . "', \n" . "title='" . SQL::escape($this->attributes['anchor_title']) . "', \n" . "type='" . SQL::escape(isset($this->attributes['type']) ? $this->attributes['type'] : 'incident') . "', \n" . "create_name='" . SQL::escape(isset($this->attributes['create_name']) ? $this->attributes['create_name'] : $this->attributes['edit_name']) . "', \n" . "create_id=" . SQL::escape(isset($this->attributes['create_id']) ? $this->attributes['create_id'] : $this->attributes['edit_id']) . ", \n" . "create_address='" . SQL::escape(isset($this->attributes['create_address']) ? $this->attributes['create_address'] : $this->attributes['edit_address']) . "', \n" . "create_date='" . SQL::escape(isset($this->attributes['create_date']) ? $this->attributes['create_date'] : $this->attributes['edit_date']) . "', \n" . "edit_name='" . SQL::escape($this->attributes['edit_name']) . "', \n" . "edit_id=" . SQL::escape($this->attributes['edit_id']) . ", \n" . "edit_address='" . SQL::escape($this->attributes['edit_address']) . "', \n" . "edit_action='create', \n" . "edit_date='" . SQL::escape($this->attributes['edit_date']) . "', \n" . "qualification_date='" . SQL::escape(isset($this->attributes['qualification_date']) ? $this->attributes['qualification_date'] : NULL_DATE) . "', \n" . "analysis_date='" . SQL::escape(isset($this->attributes['analysis_date']) ? $this->attributes['analysis_date'] : NULL_DATE) . "', \n" . "resolution_date='" . SQL::escape(isset($this->attributes['resolution_date']) ? $this->attributes['resolution_date'] : NULL_DATE) . "', \n" . "close_date='" . SQL::escape(isset($this->attributes['close_date']) ? $this->attributes['close_date'] : NULL_DATE) . "'"; break; case 'update': // only associates and page owners can update the record if (is_callable(array($this->anchor, 'is_owned')) && $this->anchor->is_owned()) { // detect type modification if ($this->attributes['type'] != $this->snapshot['type']) { $comments[] = sprintf(i18n::s('Workflow has been changed to "%s"'), $this->get_type_label($this->attributes['type'])); } // detect color modification if ($this->attributes['color'] != $this->snapshot['color']) { $comments[] = $this->get_color_label($this->attributes['color']); } // change host owner, if any if ($this->attributes['owner'] && ($user = Users::get($this->attributes['owner'])) && $user['id'] != $this->anchor->get_value('owner_id')) { $fields = array(); $fields['owner_id'] = $user['id']; $this->anchor->set_values($fields); Members::assign('user:'******'id'], $this->anchor->get_reference()); Members::assign($this->anchor->get_reference(), 'user:'******'id']); $comments[] = sprintf(i18n::s('Owner has been changed to %s'), Skin::build_link(Users::get_permalink($user), $user['full_name'])); } // update the table of issues $query = "UPDATE " . SQL::table_name('issues') . " SET \n" . "anchor='" . SQL::escape($this->attributes['anchor_reference']) . "', \n" . "anchor_url='" . SQL::escape($this->attributes['anchor_url']) . "', \n" . "color='" . SQL::escape($this->attributes['color']) . "', \n" . "status='" . SQL::escape($this->attributes['status']) . "', \n" . "title='" . SQL::escape($this->attributes['anchor_title']) . "', \n" . "type='" . SQL::escape($this->attributes['type']) . "', \n" . "create_date='" . SQL::escape(isset($this->attributes['create_date']) ? $this->attributes['create_date'] : $this->attributes['edit_date']) . "', \n" . "qualification_date='" . SQL::escape(isset($this->attributes['qualification_date']) ? $this->attributes['qualification_date'] : NULL_DATE) . "', \n" . "analysis_date='" . SQL::escape(isset($this->attributes['analysis_date']) ? $this->attributes['analysis_date'] : NULL_DATE) . "', \n" . "resolution_date='" . SQL::escape(isset($this->attributes['resolution_date']) ? $this->attributes['resolution_date'] : NULL_DATE) . "', \n" . "close_date='" . SQL::escape(isset($this->attributes['close_date']) ? $this->attributes['close_date'] : NULL_DATE) . "', \n"; // detect status modification if ($this->attributes['status'] != $this->snapshot['status']) { $comments[] = $this->get_status_label($this->attributes['status']); // depending of new status switch ($this->attributes['status']) { // case has been recorded --should not happen case 'on-going:suspect': $query .= "create_name='" . SQL::escape($this->attributes['edit_name']) . "', \n" . "create_id=" . SQL::escape($this->attributes['edit_id']) . ", \n" . "create_address='" . SQL::escape($this->attributes['edit_address']) . "', \n"; break; // problem has been validated // problem has been validated case 'cancelled:suspect': case 'on-going:problem': $query .= "qualification_name='" . SQL::escape($this->attributes['edit_name']) . "', \n" . "qualification_id='" . SQL::escape($this->attributes['edit_id']) . "', \n" . "qualification_address='" . SQL::escape($this->attributes['edit_address']) . "', \n"; break; // cause has been identified // cause has been identified case 'cancelled:problem': case 'on-going:issue': $query .= "analysis_name='" . SQL::escape($this->attributes['edit_name']) . "', \n" . "analysis_id='" . SQL::escape($this->attributes['edit_id']) . "', \n" . "analysis_address='" . SQL::escape($this->attributes['edit_address']) . "', \n"; break; // solution has been achieved // solution has been achieved case 'cancelled:issue': case 'on-going:solution': $query .= "resolution_name='" . SQL::escape($this->attributes['edit_name']) . "', \n" . "resolution_id='" . SQL::escape($this->attributes['edit_id']) . "', \n" . "resolution_address='" . SQL::escape($this->attributes['edit_address']) . "', \n"; break; // ending the issue // ending the issue case 'cancelled:solution': case 'completed:solution': $query .= "close_name='" . SQL::escape($this->attributes['edit_name']) . "', \n" . "close_id='" . SQL::escape($this->attributes['edit_id']) . "', \n" . "close_address='" . SQL::escape($this->attributes['edit_address']) . "', \n"; break; } } // track the person who modifies the record $query .= "edit_name='" . SQL::escape($this->attributes['edit_name']) . "', \n" . "edit_id=" . SQL::escape($this->attributes['edit_id']) . ", \n" . "edit_address='" . SQL::escape($this->attributes['edit_address']) . "', \n" . "edit_action='update', \n" . "edit_date='" . SQL::escape($this->attributes['edit_date'] ? $this->attributes['edit_date'] : $this->attributes['edit_date']) . "' \n" . " WHERE anchor LIKE '" . SQL::escape($this->attributes['anchor_reference']) . "'"; } // ensure that this change has been recorded if (!$comments) { $comments[] = i18n::s('Page has been edited'); } break; } // execute the query --don't stop on error if (isset($query) && $query) { SQL::query($query); } // add a comment if ($comments && !$this->anchor->has_option('no_comments')) { include_once $context['path_to_root'] . 'comments/comments.php'; $fields = array(); $fields['anchor'] = $this->attributes['anchor_reference']; $fields['description'] = join(BR, $comments); $fields['type'] = 'notification'; Comments::post($fields); } // job done return TRUE; }
/** * stop a meeting * */ function stop_meeting() { global $context; // move to the 'closed' status $fields = array('status' => 'stopped'); $this->set_values($fields); // track the end of the meeting include_once $context['path_to_root'] . 'comments/comments.php'; if (is_callable(array($this->anchor, 'get_reference')) && !$this->anchor->has_option('no_comments')) { $fields = array(); $fields['anchor'] = $this->anchor->get_reference(); $fields['description'] = sprintf(i18n::s('%s has stopped the meeting'), Surfer::get_name()); $fields['type'] = 'notification'; Comments::post($fields); } }
// post the new thread if (!($article['id'] = Articles::post($article))) { Logger::error(i18n::s('Impossible to add a page.')); } else { //get full article $article = Articles::get($article['id']); // attach some file if (isset($_FILES['upload']) && ($file = Files::upload($_FILES['upload'], 'files/article/' . $article['id'], 'article:' . $article['id']))) { $_REQUEST['message'] .= $file; } // make a new comment out of received message, if any if (isset($_REQUEST['message']) && trim($_REQUEST['message'])) { $comment = array(); $comment['anchor'] = 'article:' . $article['id']; $comment['description'] = strip_tags($_REQUEST['message']); Comments::post($comment); } // page title $context['page_title'] = i18n::s('Message sent !'); // feed-back to surfer // $context['text'] .= '<p>'.i18n::s('A new thread has been created, and it will be listed in profiles of the persons that you have involved. You can invite additional people later on if you wish.').'</p>'; // increment the post counter of the surfer Users::increment_posts(Surfer::get_id()); // make editors of the new page Members::assign('user:'******'article:' . $article['id']); foreach ($items as $item) { if (isset($item['id'])) { Members::assign('user:'******'id'], 'article:' . $article['id']); } } // add this page to watch lists
<?php authorize(); if (!isset($_REQUEST['page']) || !in_array($_REQUEST['page'], array('artist', 'collages', 'requests', 'torrents')) || !isset($_POST['pageid']) || !is_number($_POST['pageid']) || !isset($_POST['body']) || trim($_POST['body']) === '') { error(0); } if ($LoggedUser['DisablePosting']) { error('Your posting privileges have been removed.'); } $Page = $_REQUEST['page']; $PageID = (int) $_POST['pageid']; if (!$PageID) { error(404); } if (isset($_POST['subscribe']) && Subscriptions::has_subscribed_comments($Page, $PageID) === false) { Subscriptions::subscribe_comments($Page, $PageID); } $PostID = Comments::post($Page, $PageID, $_POST['body']); header("Location: " . Comments::get_url($Page, $PageID, $PostID)); die;
/** * remember an action once it's done * * @see articles/delete.php * @see articles/edit.php * * @param string the action 'insert', 'update' or 'delete' * @param array the hosting record * @param string reference of the hosting record (e.g., 'article:123') * @return FALSE on error, TRUE otherwise */ function remember($action, $host, $reference) { global $context; // set default values for this editor Surfer::check_default_editor($this->attributes); // add a notification to the anchor page $comments = array(); // on page creation if ($action == 'insert') { // expose all of the anchor interface to the contained overlay $this->anchor = Anchors::get($reference); // embed an object referenced by address if ($this->attributes['embed_type'] == 'href') { // ask some oEmbed provider to tell us more about this if ($this->attributes['embed_href'] && ($fields = $this->oembed($this->attributes['embed_href']))) { // we do want a photo, right? if (preg_match('/\\.(gif|jpg|jpeg|png)$/i', $this->attributes['embed_href'])) { $fields['type'] = 'photo'; } // because deviant-art returns non-standard type 'file' ??? if (isset($fields['url']) && preg_match('/\\.(gif|jpg|jpeg|png)$/i', $fields['url'])) { $fields['type'] = 'photo'; } // save meta data in the overlay itself $fields['id'] = $host['id']; $this->set_values($fields); // notify this contribution switch ($this->attributes['type']) { case 'link': $comments[] = sprintf(i18n::s('%s has shared a link'), Surfer::get_name()); break; case 'photo': $comments[] = sprintf(i18n::s('%s has shared a photo'), Surfer::get_name()); break; case 'rich': $comments[] = sprintf(i18n::s('%s has shared some information'), Surfer::get_name()); break; case 'video': $comments[] = sprintf(i18n::s('%s has shared a video'), Surfer::get_name()); break; default: // default label is the link itself $label = $this->attributes['embed_href']; // fetch page title if possible if ($this->attributes['embed_href'] && ($content = http::proceed($this->attributes['embed_href']))) { if (preg_match('/<title>(.*)<\\/title>/siU', $content, $matches)) { $label = trim(strip_tags(preg_replace('/\\s+/', ' ', $matches[1]))); } } // update the record $fields = array(); $fields['type'] = 'link'; $fields['label'] = $label; $this->set_values($fields); $comments[] = sprintf(i18n::s('%s has shared a link'), Surfer::get_name()); break; } } // uploaded files are turned to comments automatically in articles/article.php } } // add a comment if allowed if ($comments && !$this->anchor->has_option('no_comments')) { include_once $context['path_to_root'] . 'comments/comments.php'; $fields = array(); $fields['anchor'] = $reference; $fields['description'] = join(BR, $comments); $fields['type'] = 'notification'; Comments::post($fields); } // job done return TRUE; }
/** * the URL to stop and to leave a meeting * * @see overlays/events/stop.php * * @return string the URL to redirect the user from the meeting, or NULL on error */ function get_stop_url() { global $context; // export pad content $url = 'http://' . $this->get_hostname() . '/ep/pad/export/' . $this->attributes['meeting_id'] . '/latest?format=html'; // we don't care about the return code if (($result = http::proceed($url)) && preg_match('|\\<body[^>]*>(.*)</body[^>]*>|isU', $result, $matches)) { // put the text of the pad in a comment include_once $context['path_to_root'] . 'comments/comments.php'; $fields = array(); $fields['anchor'] = $this->anchor->get_reference(); $fields['description'] = i18n::s('Resulting text') . '<div style="border: 2px solid #ccc; margin: 1em; padding: 1em;">' . $matches[1] . '</div>'; $fields['type'] = 'notification'; Comments::post($fields); } // back to the yacs page if (is_callable(array($this->anchor, 'get_url'))) { return $context['url_to_home'] . $context['url_to_root'] . $this->anchor->get_url(); } // this should not happen return NULL; }
if (is_array($uploaded)) { $_REQUEST['description'] .= '<div style="margin-top: 1em;">' . Skin::build_list(Files::list_for_anchor_and_name($anchor->get_reference(), $uploaded, 'compact'), 'compact') . '</div>'; } elseif ($file =& Files::get_by_anchor_and_name($anchor->get_reference(), $uploaded)) { $_REQUEST['description'] .= '<div style="margin-top: 1em;">[file=' . $file['id'] . ',' . $file['file_name'] . ']</div>'; // silently delete the previous file if the name has changed if (isset($file['file_name']) && $file['file_name'] != $uploaded) { Safe::unlink($file_path . '/' . $file['file_name']); } } } // preview mode if (isset($_REQUEST['preview']) && $_REQUEST['preview'] == 'Y') { $item = $_REQUEST; $with_form = TRUE; // display the form on error } elseif (!($_REQUEST['id'] = Comments::post($_REQUEST))) { $item = $_REQUEST; $with_form = TRUE; // reward the poster for new posts } elseif (!isset($item['id']) || $item['id'] != $_REQUEST['id']) { if (is_object($anchor->overlay) && is_callable(array($anchor->overlay, 'get_comment_notification'))) { // delegate notification to overlay $mail = $anchor->overlay->get_comment_notification($_REQUEST); } else { // regular notification to send by e-mail $mail = array(); $mail['subject'] = sprintf(i18n::c('%s: %s'), $_REQUEST['type'] == 'approval' ? i18n::c('Approval') : i18n::c('Contribution'), strip_tags($anchor->get_title())); $mail['notification'] = Comments::build_notification($_REQUEST); } // send to anchor watchers if (isset($_REQUEST['notify_watchers']) && $_REQUEST['notify_watchers'] == 'Y') {