Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 's9_MDL-26854_spam_comments_20_2' of git://github.com/do…

…ngsheng/moodle into MOODLE_20_STABLE
  • Loading branch information...
commit 7390fdde6305fc1d83a48ecce48a1607ad9972e8 2 parents 1374c61 + b473046
@samhemelryk samhemelryk authored
View
31 blocks/comments/block_comments.php
@@ -1,5 +1,31 @@
<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+/**
+ * The comments block
+ *
+ * @package block
+ * @subpackage comments
+ * @copyright 2009 Dongsheng Cai <dongsheng@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+// Obviously required
require_once($CFG->dirroot . '/comment/lib.php');
class block_comments extends block_base {
@@ -38,13 +64,12 @@ function get_content() {
$this->content->footer = '';
$this->content->text = '';
list($context, $course, $cm) = get_context_info_array($PAGE->context->id);
- $args = new stdClass();
+
+ $args = new stdClass;
$args->context = $PAGE->context;
$args->course = $course;
$args->area = 'page_comments';
$args->itemid = 0;
- // set 'env' to tell moodle tweak ui for this block
- $args->env = 'block_comments';
$args->component = 'block_comments';
$args->linktext = get_string('showcomments');
$args->notoggle = true;
View
62 blog/lib.php
@@ -966,3 +966,65 @@ function blog_get_associated_count($courseid, $cmid=null) {
}
return $DB->count_records('blog_association', array('contextid' => $context->id));
}
+
+/**
+ * Running addtional permission check on plugin, for example, plugins
+ * may have switch to turn on/off comments option, this callback will
+ * affect UI display, not like pluginname_comment_validate only throw
+ * exceptions.
+ * Capability check has been done in comment->check_permissions(), we
+ * don't need to do it again here.
+ *
+ * @param stdClass $comment_param {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return array
+ */
+function blog_comment_permissions($comment_param) {
+ return array('post'=>true, 'view'=>true);
+}
+
+/**
+ * Validate comment parameter before perform other comments actions
+ *
+ * @param stdClass $comment {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return boolean
+ */
+function blog_comment_validate($comment_param) {
+ global $DB;
+ // validate comment itemid
+ if (!$entry = $DB->get_record('post', array('id'=>$comment_param->itemid))) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ // validate comment area
+ if ($comment_param->commentarea != 'format_blog') {
+ throw new comment_exception('invalidcommentarea');
+ }
+ // validation for comment deletion
+ if (!empty($comment_param->commentid)) {
+ if ($record = $DB->get_record('comments', array('id'=>$comment_param->commentid))) {
+ if ($record->commentarea != 'format_blog') {
+ throw new comment_exception('invalidcommentarea');
+ }
+ if ($record->contextid != $comment_param->context->id) {
+ throw new comment_exception('invalidcontext');
+ }
+ if ($record->itemid != $comment_param->itemid) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ } else {
+ throw new comment_exception('invalidcommentid');
+ }
+ }
+ return true;
+}
View
4 comment/comment.js
@@ -40,7 +40,6 @@ M.core_comment = {
this.component = args.component;
this.courseid = args.courseid;
this.contextid = args.contextid;
- this.env = args.env;
this.autostart = (args.autostart);
// expand comments?
if (this.autostart) {
@@ -116,7 +115,6 @@ bodyContent: '<div class="comment-delete-confirm"><a href="#" id="confirmdelete-
scope = args['scope'];
}
//params['page'] = args.page?args.page:'';
- params['env'] = '';
// the form element only accept certain file types
params['sesskey'] = M.cfg.sesskey;
params['action'] = args.action?args.action:'';
@@ -348,7 +346,7 @@ bodyContent: '<div class="comment-delete-confirm"><a href="#" id="confirmdelete-
var d = container.getStyle('display');
if (d=='none'||d=='') {
// show
- if (this.autostart) {
+ if (!this.autostart) {
this.load(page);
} else {
this.register_delete_buttons();
View
120 comment/comment_ajax.php
@@ -1,5 +1,4 @@
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
@@ -24,87 +23,96 @@
require_once($CFG->dirroot . '/comment/lib.php');
$contextid = optional_param('contextid', SYSCONTEXTID, PARAM_INT);
+$action = optional_param('action', '', PARAM_ALPHA);
+
+if (empty($CFG->usecomments)) {
+ throw new comment_exception('commentsnotenabled', 'moodle');
+}
+
list($context, $course, $cm) = get_context_info_array($contextid);
-$PAGE->set_context($context);
$PAGE->set_url('/comment/comment_ajax.php');
-$action = optional_param('action', '', PARAM_ALPHA);
+// Allow anonymous user to view comments providing forcelogin now enabled
+require_course_login($course, true, $cm);
+$PAGE->set_context($context);
+if (!empty($cm)) {
+ $PAGE->set_cm($cm, $course);
+} else if (!empty($course)) {
+ $PAGE->set_course($course);
+}
if (!confirm_sesskey()) {
- $error = array('error'=>get_string('invalidsesskey'));
+ $error = array('error'=>get_string('invalidsesskey', 'error'));
die(json_encode($error));
}
-if (!isloggedin()) {
- // display comments on front page without permission check
- if ($action == 'get') {
- if ($context->id == get_context_instance(CONTEXT_COURSE, SITEID)->id) {
- $ignore_permission = true;
- } else {
- // tell user to log in to view comments
- $ignore_permission = false;
- echo json_encode(array('error'=>'require_login'));
- die;
- }
- } else {
- // ignore request
- die;
- }
-} else {
- $ignore_permission = false;
-}
-
+$client_id = required_param('client_id', PARAM_ALPHANUM);
$area = optional_param('area', '', PARAM_ALPHAEXT);
-$client_id = optional_param('client_id', '', PARAM_RAW);
$commentid = optional_param('commentid', -1, PARAM_INT);
$content = optional_param('content', '', PARAM_RAW);
$itemid = optional_param('itemid', '', PARAM_INT);
$page = optional_param('page', 0, PARAM_INT);
$component = optional_param('component', '', PARAM_ALPHAEXT);
-echo $OUTPUT->header(); // send headers
-
// initilising comment object
-if (!empty($client_id)) {
- $args = new stdClass();
- $args->context = $context;
- $args->course = $course;
- $args->cm = $cm;
- $args->area = $area;
- $args->itemid = $itemid;
- $args->client_id = $client_id;
- $args->component = $component;
- // only for comments in frontpage
- $args->ignore_permission = $ignore_permission;
- $manager = new comment($args);
-} else {
- die;
-}
+$args = new stdClass;
+$args->context = $context;
+$args->course = $course;
+$args->cm = $cm;
+$args->area = $area;
+$args->itemid = $itemid;
+$args->client_id = $client_id;
+$args->component = $component;
+$manager = new comment($args);
+
+echo $OUTPUT->header(); // send headers
// process ajax request
switch ($action) {
case 'add':
- $result = $manager->add($content);
- if (!empty($result) && is_object($result)) {
- $result->count = $manager->count();
- $result->client_id = $client_id;
- echo json_encode($result);
+ if ($manager->can_post()) {
+ $result = $manager->add($content);
+ if (!empty($result) && is_object($result)) {
+ $result->count = $manager->count();
+ $result->client_id = $client_id;
+ echo json_encode($result);
+ die();
+ }
}
break;
case 'delete':
- $result = $manager->delete($commentid);
- if ($result === true) {
- echo json_encode(array('client_id'=>$client_id, 'commentid'=>$commentid));
+ $comment_record = $DB->get_record('comments', array('id'=>$commentid));
+ if ($manager->can_delete($commentid) || $comment_record->userid == $USER->id) {
+ if ($manager->delete($commentid)) {
+ $result = array(
+ 'client_id' => $client_id,
+ 'commentid' => $commentid
+ );
+ echo json_encode($result);
+ die();
+ }
}
break;
case 'get':
default:
- $result = array();
- $comments = $manager->get_comments($page);
- $result['list'] = $comments;
- $result['count'] = $manager->count();
- $result['pagination'] = $manager->get_pagination($page);
- $result['client_id'] = $client_id;
- echo json_encode($result);
+ if ($manager->can_view()) {
+ $comments = $manager->get_comments($page);
+ $result = array(
+ 'list' => $comments,
+ 'count' => $manager->count(),
+ 'pagination' => $manager->get_pagination($page),
+ 'client_id' => $client_id
+ );
+ echo json_encode($result);
+ die();
+ }
+ break;
+}
+
+if (!isloggedin()) {
+ // tell user to log in to view comments
+ echo json_encode(array('error'=>'require_login'));
}
+// ignore request
+die;
View
32 comment/comment_post.php
@@ -1,5 +1,4 @@
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
@@ -21,35 +20,40 @@
require_once('../config.php');
require_once($CFG->dirroot . '/comment/lib.php');
+if (empty($CFG->usecomments)) {
+ throw new comment_exception('commentsnotenabled', 'moodle');
+}
+
$contextid = optional_param('contextid', SYSCONTEXTID, PARAM_INT);
list($context, $course, $cm) = get_context_info_array($contextid);
require_login($course, true, $cm);
require_sesskey();
-$action = optional_param('action', '', PARAM_ALPHA);
-$area = optional_param('area', '', PARAM_ALPHAEXT);
-$commentid = optional_param('commentid', -1, PARAM_INT);
-$content = optional_param('content', '', PARAM_RAW);
-$itemid = optional_param('itemid', '', PARAM_INT);
-$returnurl = optional_param('returnurl', '', PARAM_URL);
-$component = optional_param('component', '', PARAM_ALPHAEXT);
+$action = optional_param('action', '', PARAM_ALPHA);
+$area = optional_param('area', '', PARAM_ALPHAEXT);
+$content = optional_param('content', '', PARAM_RAW);
+$itemid = optional_param('itemid', '', PARAM_INT);
+$returnurl = optional_param('returnurl', '/', PARAM_URL);
+$component = optional_param('component', '', PARAM_ALPHAEXT);
+
+// Currently this script can only add comments
+if ($action !== 'add') {
+ redirect($returnurl);
+}
-$cmt = new stdClass();
+$cmt = new stdClass;
$cmt->contextid = $contextid;
$cmt->courseid = $course->id;
+$cmt->cm = $cm;
$cmt->area = $area;
$cmt->itemid = $itemid;
$cmt->component = $component;
$comment = new comment($cmt);
-switch ($action) {
-case 'add':
+if ($comment->can_post()) {
$cmt = $comment->add($content);
if (!empty($cmt) && is_object($cmt)) {
redirect($returnurl);
}
- break;
-default:
- exit;
}
View
9 comment/index.php
@@ -20,7 +20,7 @@
*/
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
-require_once('locallib.php');
+require_once($CFG->dirroot.'/comment/locallib.php');
require_login();
admin_externalpage_setup('comments', '', null, '', array('pagelayout'=>'report'));
@@ -81,8 +81,11 @@
}
if (empty($action)) {
echo '<form method="post">';
- $manager->print_comments($page);
- echo '<input type="submit" id="comments_delete" name="batchdelete" value="'.get_string('delete').'" />';
+ $return = $manager->print_comments($page);
+ // if no comments available, $return will be false
+ if ($return) {
+ echo '<input type="submit" id="comments_delete" name="batchdelete" value="'.get_string('delete').'" />';
+ }
echo '</form>';
}
View
499 comment/lib.php
@@ -1,5 +1,4 @@
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
@@ -23,18 +22,15 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+defined('MOODLE_INTERNAL') || die();
+
class comment {
/**
- * @var integer
- */
- private $page;
- /**
* there may be several comment box in one page
* so we need a client_id to recognize them
* @var integer
*/
private $cid;
- private $contextid;
/**
* commentarea is used to specify different
* parts shared the same itemid
@@ -46,80 +42,133 @@ class comment {
* @var integer
*/
private $itemid;
-
/**
* this html snippet will be used as a template
* to build comment content
* @var string
*/
private $template;
+ /**
+ * The context id for comments
+ * @var int
+ */
+ private $contextid;
+ /**
+ * The context itself
+ * @var stdClass
+ */
private $context;
+ /**
+ * The course id for comments
+ * @var int
+ */
private $courseid;
/**
* course module object, only be used to help find pluginname automatically
* if pluginname is specified, it won't be used at all
- * @var string
+ * @var stdClass
*/
private $cm;
- private $plugintype;
/**
- * When used in module, it is recommended to use it
+ * The component that this comment is for. It is STRONGLY recommended to set this.
+ * @var string
+ */
+ private $component;
+ /**
+ * This is calculated by normalising the component
* @var string
*/
private $pluginname;
- private $viewcap;
- private $postcap;
/**
- * to tell comments api where it is used
+ * This is calculated by normalising the component
* @var string
*/
- private $env;
+ private $plugintype;
+ /**
+ * Whether the user has the required capabilities/permissions to view comments.
+ * @var bool
+ */
+ private $viewcap = false;
+ /**
+ * Whether the user has the required capabilities/permissions to post comments.
+ * @var bool
+ */
+ private $postcap = false;
/**
* to costomize link text
* @var string
*/
private $linktext;
-
/**
* If set to true then comment sections won't be able to be opened and closed
* instead they will always be visible.
* @var bool
*/
protected $notoggle = false;
-
/**
* If set to true comments are automatically loaded as soon as the page loads.
* Normally this happens when the user expands the comment section.
* @var bool
*/
protected $autostart = false;
-
+ /**
+ * If set to true the total count of comments is displayed when displaying comments.
+ * @var bool
+ */
+ protected $displaytotalcount = false;
/**
* If set to true a cancel button will be shown on the form used to submit comments.
* @var bool
*/
protected $displaycancel = false;
+ /**
+ * The number of comments associated with this comments params
+ * @var int
+ */
+ protected $totalcommentcount = null;
+ /**
+ * By default a user must have the generic comment capabilities plus any capabilities the
+ * component being commented on requires.
+ * When set to true only the component capabilities are checked, the system capabilities are
+ * ignored.
+ * This can be toggled by the component defining a callback in its lib.php e.g.
+ * function forum_comment_allow_anonymous_access(comment $comment) {}
+ * Note: On the front page this defaults to true.
+ * @var bool
+ */
+ protected $ignoresystempermissions = false;
- // static variable will be used by non-js comments UI
+ /**#@+
+ * static variable will be used by non-js comments UI
+ */
private static $nonjs = false;
private static $comment_itemid = null;
private static $comment_context = null;
private static $comment_area = null;
private static $comment_page = null;
private static $comment_component = null;
+ /**#@-*/
/**
* Construct function of comment class, initialise
* class members
- * @param object $options
+ * @param stdClass $options
+ * @param object $options {
+ * context => context context to use for the comment [required]
+ * component => string which plugin will comment being added to [required]
+ * itemid => int the id of the associated item (forum post, glossary item etc) [required]
+ * area => string comment area
+ * cm => stdClass course module
+ * course => course course object
+ * client_id => string an unique id to identify comment area
+ * autostart => boolean automatically expend comments
+ * showcount => boolean display the number of comments
+ * displaycancel => boolean display cancel button
+ * notoggle => boolean don't show/hide button
+ * linktext => string title of show/hide button
+ * }
*/
- public function __construct($options) {
- global $CFG, $DB;
-
- if (empty($CFG->commentsperpage)) {
- $CFG->commentsperpage = 15;
- }
-
+ public function __construct(stdClass $options) {
$this->viewcap = false;
$this->postcap = false;
@@ -142,7 +191,11 @@ public function __construct($options) {
}
if (!empty($options->component)) {
+ // set and validate component
$this->set_component($options->component);
+ } else {
+ // component cannot be empty
+ throw new comment_exception('invalidcomponent');
}
// setup course
@@ -174,13 +227,6 @@ public function __construct($options) {
$this->itemid = 0;
}
- // setup env
- if (!empty($options->env)) {
- $this->env = $options->env;
- } else {
- $this->env = '';
- }
-
// setup customized linktext
if (!empty($options->linktext)) {
$this->linktext = $options->linktext;
@@ -188,10 +234,24 @@ public function __construct($options) {
$this->linktext = get_string('comments');
}
- if (!empty($options->ignore_permission)) {
- $this->ignore_permission = true;
- } else {
- $this->ignore_permission = false;
+ // setup options for callback functions
+ $this->comment_param = new stdClass();
+ $this->comment_param->context = $this->context;
+ $this->comment_param->courseid = $this->courseid;
+ $this->comment_param->cm = $this->cm;
+ $this->comment_param->commentarea = $this->commentarea;
+ $this->comment_param->itemid = $this->itemid;
+
+ $this->allowanonymousaccess = false;
+ // By default everyone can view comments on the front page
+ if ($this->context->contextlevel == CONTEXT_COURSE && $this->context->instanceid == SITEID) {
+ $this->allowanonymousaccess = true;
+ } else if ($this->context->contextlevel == CONTEXT_MODULE && $this->courseid == SITEID) {
+ $this->allowanonymousaccess = true;
+ }
+ if (!empty($this->plugintype) && !empty($this->pluginname)) {
+ // Plugins can override this if they wish.
+ $this->allowanonymousaccess = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'allow_anonymous_access', array($this), $this->allowanonymousaccess);
}
// setup notoggle
@@ -209,38 +269,23 @@ public function __construct($options) {
$this->set_displaycancel($options->displaycancel);
}
+ // setup displaytotalcount
if (!empty($options->showcount)) {
- $count = $this->count();
- if (empty($count)) {
- $this->count = '';
- } else {
- $this->count = '('.$count.')';
- }
- } else {
- $this->count = '';
+ $this->set_displaytotalcount($options->showcount);
}
- // setup options for callback functions
- $this->args = new stdClass();
- $this->args->context = $this->context;
- $this->args->courseid = $this->courseid;
- $this->args->cm = $this->cm;
- $this->args->commentarea = $this->commentarea;
- $this->args->itemid = $this->itemid;
-
// setting post and view permissions
$this->check_permissions();
// load template
- $this->template = <<<EOD
-<div class="comment-userpicture">___picture___</div>
-<div class="comment-content">
- ___name___ - <span>___time___</span>
- <div>___content___</div>
-</div>
-EOD;
+ $this->template = html_writer::tag('div', '___picture___', array('class' => 'comment-userpicture'));
+ $this->template .= html_writer::start_tag('div', array('class' => 'comment-content'));
+ $this->template .= '___name___ - ';
+ $this->template .= html_writer::tag('span', '___time___');
+ $this->template .= html_writer::tag('div', '___content___');
+ $this->template .= html_writer::end_tag('div'); // .comment-content
if (!empty($this->plugintype)) {
- $this->template = plugin_callback($this->plugintype, $this->pluginname, FEATURE_COMMENT, 'template', $this->args, $this->template);
+ $this->template = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'template', array($this->comment_param), $this->template);
}
unset($options);
@@ -248,34 +293,63 @@ public function __construct($options) {
/**
* Receive nonjs comment parameters
+ *
+ * @param moodle_page $page The page object to initialise comments within
+ * If not provided the global $PAGE is used
*/
- public static function init() {
- global $PAGE, $CFG;
+ public static function init(moodle_page $page = null) {
+ global $PAGE;
+
+ if (empty($page)) {
+ $page = $PAGE;
+ }
// setup variables for non-js interface
- self::$nonjs = optional_param('nonjscomment', '', PARAM_ALPHA);
+ self::$nonjs = optional_param('nonjscomment', '', PARAM_ALPHANUM);
self::$comment_itemid = optional_param('comment_itemid', '', PARAM_INT);
self::$comment_context = optional_param('comment_context', '', PARAM_INT);
self::$comment_page = optional_param('comment_page', '', PARAM_INT);
self::$comment_area = optional_param('comment_area', '', PARAM_ALPHAEXT);
- $PAGE->requires->string_for_js('addcomment', 'moodle');
- $PAGE->requires->string_for_js('deletecomment', 'moodle');
- $PAGE->requires->string_for_js('comments', 'moodle');
- $PAGE->requires->string_for_js('commentsrequirelogin', 'moodle');
+ $page->requires->string_for_js('addcomment', 'moodle');
+ $page->requires->string_for_js('deletecomment', 'moodle');
+ $page->requires->string_for_js('comments', 'moodle');
+ $page->requires->string_for_js('commentsrequirelogin', 'moodle');
}
+ /**
+ * Sets the component.
+ *
+ * This method shouldn't be public, changing the component once it has been set potentially
+ * invalidates permission checks.
+ * A coding_error is now thrown if code attempts to change the component.
+ *
+ * @param string $component
+ * @return void
+ */
public function set_component($component) {
+ if (!empty($this->component) && $this->component !== $component) {
+ throw new coding_exception('You cannot change the component of a comment once it has been set');
+ }
$this->component = $component;
list($this->plugintype, $this->pluginname) = normalize_component($component);
- return null;
}
+ /**
+ * Determines if the user can view the comment.
+ *
+ * @param bool $value
+ */
public function set_view_permission($value) {
- $this->viewcap = $value;
+ $this->viewcap = (bool)$value;
}
+ /**
+ * Determines if the user can post a comment
+ *
+ * @param bool $value
+ */
public function set_post_permission($value) {
- $this->postcap = $value;
+ $this->postcap = (bool)$value;
}
/**
@@ -285,12 +359,11 @@ public function set_post_permission($value) {
* function named $pluginname_check_comment_post must be implemented
*/
private function check_permissions() {
- global $CFG;
$this->postcap = has_capability('moodle/comment:post', $this->context);
$this->viewcap = has_capability('moodle/comment:view', $this->context);
if (!empty($this->plugintype)) {
- $permissions = plugin_callback($this->plugintype, $this->pluginname, FEATURE_COMMENT, 'permissions', array($this->args), array('post'=>true, 'view'=>true));
- if ($this->ignore_permission) {
+ $permissions = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'permissions', array($this->comment_param), array('post'=>false, 'view'=>false));
+ if ($this->allowanonymousaccess) {
$this->postcap = $permissions['post'];
$this->viewcap = $permissions['view'];
} else {
@@ -319,7 +392,7 @@ public function get_nojslink(moodle_page $page = null) {
'comment_context' => $this->context->id,
'comment_area' => $this->commentarea,
));
- $link->remove_params(array('nonjscomment', 'comment_page'));
+ $link->remove_params(array('comment_page'));
return $link;
}
@@ -360,6 +433,18 @@ public function set_displaycancel($newvalue = true) {
}
/**
+ * Sets the displaytotalcount option
+ *
+ * If set to true then the total number of comments will be displayed
+ * when printing comments.
+ *
+ * @param bool $newvalue
+ */
+ public function set_displaytotalcount($newvalue = true) {
+ $this->displaytotalcount = (bool)$newvalue;
+ }
+
+ /**
* Initialises the JavaScript that enchances the comment API.
*
* @param moodle_page $page The moodle page object that the JavaScript should be
@@ -374,7 +459,6 @@ public function initialise_javascript(moodle_page $page) {
$options->page = 0;
$options->courseid = $this->courseid;
$options->contextid = $this->contextid;
- $options->env = $this->env;
$options->component = $this->component;
$options->notoggle = $this->notoggle;
$options->autostart = $this->autostart;
@@ -404,12 +488,12 @@ public function output($return = true) {
// print html template
// Javascript will use the template to render new comments
- if (empty($template_printed) && !empty($this->viewcap)) {
+ if (empty($template_printed) && $this->can_view()) {
$html .= html_writer::tag('div', $this->template, array('style' => 'display:none', 'id' => 'cmt-tmpl'));
$template_printed = true;
}
- if (!empty($this->viewcap)) {
+ if ($this->can_view()) {
// print commenting icon and tooltip
$html .= html_writer::start_tag('div', array('class' => 'mdl-left'));
$html .= html_writer::link($this->get_nojslink($PAGE), get_string('showcommentsnonjs'), array('class' => 'showcommentsnonjs'));
@@ -417,27 +501,33 @@ public function output($return = true) {
if (!$this->notoggle) {
// If toggling is enabled (notoggle=false) then print the controls to toggle
// comments open and closed
+ $countstring = '';
+ if ($this->displaytotalcount) {
+ $countstring = '('.$this->count().')';
+ }
$html .= html_writer::start_tag('a', array('class' => 'comment-link', 'id' => 'comment-link-'.$this->cid, 'href' => '#'));
$html .= html_writer::empty_tag('img', array('id' => 'comment-img-'.$this->cid, 'src' => $OUTPUT->pix_url('t/collapsed'), 'alt' => $this->linktext, 'title' => $this->linktext));
- $html .= html_writer::tag('span', $this->linktext.' '.$this->count, array('id' => 'comment-link-text-'.$this->cid));
+ $html .= html_writer::tag('span', $this->linktext.' '.$countstring, array('id' => 'comment-link-text-'.$this->cid));
$html .= html_writer::end_tag('a');
}
$html .= html_writer::start_tag('div', array('id' => 'comment-ctrl-'.$this->cid, 'class' => 'comment-ctrl'));
- $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
- $html .= html_writer::tag('li', '', array('class' => 'first'));
if ($this->autostart) {
// If autostart has been enabled print the comments list immediatly
+ $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list comments-loaded'));
+ $html .= html_writer::tag('li', '', array('class' => 'first'));
$html .= $this->print_comments(0, true, false);
$html .= html_writer::end_tag('ul'); // .comment-list
$html .= $this->get_pagination(0);
} else {
+ $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
+ $html .= html_writer::tag('li', '', array('class' => 'first'));
$html .= html_writer::end_tag('ul'); // .comment-list
$html .= html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
}
- if (!empty($this->postcap)) {
+ if ($this->can_post()) {
// print posting textarea
$html .= html_writer::start_tag('div', array('class' => 'comment-area'));
$html .= html_writer::start_tag('div', array('class' => 'db'));
@@ -478,15 +568,15 @@ public function output($return = true) {
*/
public function get_comments($page = '') {
global $DB, $CFG, $USER, $OUTPUT;
- if (empty($this->viewcap)) {
+ if (!$this->can_view()) {
return false;
}
if (!is_numeric($page)) {
$page = 0;
}
- $this->page = $page;
$params = array();
- $start = $page * $CFG->commentsperpage;
+ $perpage = (!empty($CFG->commentsperpage))?$CFG->commentsperpage:15;
+ $start = $page * $perpage;
$ufields = user_picture::fields('u');
$sql = "SELECT $ufields, c.id AS cid, c.content AS ccontent, c.format AS cformat, c.timecreated AS ctimecreated
FROM {comments} c
@@ -498,9 +588,8 @@ public function get_comments($page = '') {
$params['itemid'] = $this->itemid;
$comments = array();
- $candelete = has_capability('moodle/comment:delete', $this->context);
$formatoptions = array('overflowdiv' => true);
- $rs = $DB->get_recordset_sql($sql, $params, $start, $CFG->commentsperpage);
+ $rs = $DB->get_recordset_sql($sql, $params, $start, $perpage);
foreach ($rs as $u) {
$c = new stdClass();
$c->id = $u->cid;
@@ -512,8 +601,9 @@ public function get_comments($page = '') {
$c->fullname = fullname($u);
$c->time = userdate($c->timecreated, get_string('strftimerecent', 'langconfig'));
$c->content = format_text($c->content, $c->format, $formatoptions);
-
$c->avatar = $OUTPUT->user_picture($u, array('size'=>18));
+
+ $candelete = $this->can_delete($c->id);
if (($USER->id == $u->id) || !empty($candelete)) {
$c->delete = true;
}
@@ -523,31 +613,45 @@ public function get_comments($page = '') {
if (!empty($this->plugintype)) {
// moodle module will filter comments
- $comments = plugin_callback($this->plugintype, $this->pluginname, FEATURE_COMMENT, 'display', array($comments, $this->args), $comments);
+ $comments = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'display', array($comments, $this->comment_param), $comments);
}
return $comments;
}
+ /**
+ * Returns the number of comments associated with the details of this object
+ *
+ * @global moodle_database $DB
+ * @return int
+ */
public function count() {
global $DB;
- if ($count = $DB->count_records('comments', array('itemid'=>$this->itemid, 'commentarea'=>$this->commentarea, 'contextid'=>$this->context->id))) {
- return $count;
- } else {
- return 0;
+ if ($this->totalcommentcount === null) {
+ $this->totalcommentcount = $DB->count_records('comments', array('itemid' => $this->itemid, 'commentarea' => $this->commentarea, 'contextid' => $this->context->id));
}
+ return $this->totalcommentcount;
}
+ /**
+ * Returns HTML to display a pagination bar
+ *
+ * @global stdClass $CFG
+ * @global core_renderer $OUTPUT
+ * @param int $page
+ * @return string
+ */
public function get_pagination($page = 0) {
- global $DB, $CFG, $OUTPUT;
+ global $CFG, $OUTPUT;
$count = $this->count();
- $pages = (int)ceil($count/$CFG->commentsperpage);
+ $perpage = (!empty($CFG->commentsperpage))?$CFG->commentsperpage:15;
+ $pages = (int)ceil($count/$perpage);
if ($pages == 1 || $pages == 0) {
return html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
}
if (!empty(self::$nonjs)) {
// used in non-js interface
- return $OUTPUT->paging_bar($count, $page, $CFG->commentsperpage, $this->get_nojslink(), 'comment_page');
+ return $OUTPUT->paging_bar($count, $page, $perpage, $this->get_nojslink(), 'comment_page');
} else {
// return ajax paging bar
$str = '';
@@ -567,16 +671,18 @@ public function get_pagination($page = 0) {
/**
* Add a new comment
+ *
+ * @global moodle_database $DB
* @param string $content
* @return mixed
*/
public function add($content, $format = FORMAT_MOODLE) {
global $CFG, $DB, $USER, $OUTPUT;
- if (empty($this->postcap)) {
+ if (!$this->can_post()) {
throw new comment_exception('nopermissiontocomment');
}
$now = time();
- $newcmt = new stdClass();
+ $newcmt = new stdClass;
$newcmt->contextid = $this->contextid;
$newcmt->commentarea = $this->commentarea;
$newcmt->itemid = $this->itemid;
@@ -585,20 +691,15 @@ public function add($content, $format = FORMAT_MOODLE) {
$newcmt->userid = $USER->id;
$newcmt->timecreated = $now;
- if (!empty($this->plugintype)) {
- // moodle module will check content
- $ret = plugin_callback($this->plugintype, $this->pluginname, FEATURE_COMMENT, 'add', array(&$newcmt, $this->args), true);
- if (!$ret) {
- throw new comment_exception('modulererejectcomment');
- }
- }
+ // This callback allow module to modify the content of comment, such as filter or replacement
+ plugin_callback($this->plugintype, $this->pluginname, 'comment', 'add', array(&$newcmt, $this->comment_param));
$cmt_id = $DB->insert_record('comments', $newcmt);
if (!empty($cmt_id)) {
$newcmt->id = $cmt_id;
$newcmt->time = userdate($now, get_string('strftimerecent', 'langconfig'));
$newcmt->fullname = fullname($USER);
- $url = new moodle_url('/user/view.php', array('id'=>$USER->id, 'course'=>$this->courseid));
+ $url = new moodle_url('/user/view.php', array('id' => $USER->id, 'course' => $this->courseid));
$newcmt->profileurl = $url->out();
$newcmt->content = format_text($newcmt->content, $format, array('overflowdiv'=>true));
$newcmt->avatar = $OUTPUT->user_picture($USER, array('size'=>16));
@@ -610,7 +711,7 @@ public function add($content, $format = FORMAT_MOODLE) {
/**
* delete by context, commentarea and itemid
- * @param object $param {
+ * @param stdClass|array $param {
* contextid => int the context in which the comments exist [required]
* commentarea => string the comment area [optional]
* itemid => int comment itemid [optional]
@@ -629,7 +730,8 @@ public function delete_comments($param) {
/**
* Delete page_comments in whole course, used by course reset
- * @param object $context course context
+ *
+ * @param stdClass $context course context
*/
public function reset_course_page_comments($context) {
global $DB;
@@ -645,6 +747,7 @@ public function reset_course_page_comments($context) {
/**
* Delete a comment
+ *
* @param int $commentid
* @return mixed
*/
@@ -663,6 +766,7 @@ public function delete($commentid) {
/**
* Print comments
+ *
* @param int $page
* @param boolean $return return comments list string or print it out
* @param boolean $nonjs print nonjs comments list or not?
@@ -670,6 +774,11 @@ public function delete($commentid) {
*/
public function print_comments($page = 0, $return = true, $nonjs = true) {
global $DB, $CFG, $PAGE;
+
+ if (!$this->can_view()) {
+ return '';
+ }
+
$html = '';
if (!(self::$comment_itemid == $this->itemid &&
self::$comment_context == $this->context->id &&
@@ -680,38 +789,34 @@ public function print_comments($page = 0, $return = true, $nonjs = true) {
$html = '';
if ($nonjs) {
- $html .= '<h3>'.get_string('comments').'</h3>';
- $html .= "<ul id='comment-list-$this->cid' class='comment-list'>";
+ $html .= html_writer::tag('h3', get_string('comments'));
+ $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
}
- $results = array();
- $list = '';
-
- foreach ($comments as $cmt) {
- $list = '<li id="comment-'.$cmt->id.'-'.$this->cid.'">'.$this->print_comment($cmt, $nonjs).'</li>' . $list;
+ // Reverse the comments array to display them in the correct direction
+ foreach (array_reverse($comments) as $cmt) {
+ $html .= html_writer::tag('li', $this->print_comment($cmt, $nonjs), array('id' => 'comment-'.$cmt->id.'-'.$this->cid));
}
- $html .= $list;
if ($nonjs) {
- $html .= '</ul>';
+ $html .= html_writer::end_tag('ul');
$html .= $this->get_pagination($page);
}
- $sesskey = sesskey();
- $returnurl = $PAGE->url;
- $strsubmit = get_string('submit');
- if ($nonjs) {
- $html .= <<<EOD
-<form method="POST" action="{$CFG->wwwroot}/comment/comment_post.php">
-<textarea name="content" rows="2"></textarea>
-<input type="hidden" name="contextid" value="$this->contextid" />
-<input type="hidden" name="action" value="add" />
-<input type="hidden" name="area" value="$this->commentarea" />
-<input type="hidden" name="component" value="$this->component" />
-<input type="hidden" name="itemid" value="$this->itemid" />
-<input type="hidden" name="courseid" value="{$this->courseid}" />
-<input type="hidden" name="sesskey" value="{$sesskey}" />
-<input type="hidden" name="returnurl" value="{$returnurl}" />
-<input type="submit" value="{$strsubmit}" />
-</form>
-EOD;
+ if ($nonjs && $this->can_post()) {
+ // Form to add comments
+ $html .= html_writer::start_tag('form', array('method' => 'post', 'action' => new moodle_url('/comment/comment_post.php')));
+ // Comment parameters
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'contextid', 'value' => $this->contextid));
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'add'));
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'area', 'value' => $this->commentarea));
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'component', 'value' => $this->component));
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'itemid', 'value' => $this->itemid));
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'courseid', 'value' => $this->courseid));
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
+ $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'returnurl', 'value' => $PAGE->url));
+ // Textarea for the actual comment
+ $html .= html_writer::tag('textarea', '', array('name' => 'content', 'rows' => 2));
+ // Submit button to add the comment
+ $html .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('submit')));
+ $html .= html_writer::end_tag('form');
}
if ($return) {
return $html;
@@ -720,14 +825,35 @@ public function print_comments($page = 0, $return = true, $nonjs = true) {
}
}
+ /**
+ * Returns an array containing comments in HTML format.
+ *
+ * @global core_renderer $OUTPUT
+ * @param stdClass $cmt {
+ * id => int comment id
+ * content => string comment content
+ * format => int comment text format
+ * timecreated => int comment's timecreated
+ * profileurl => string link to user profile
+ * fullname => comment author's full name
+ * avatar => string user's avatar
+ * delete => boolean does user have permission to delete comment?
+ * }
+ * @param bool $nonjs
+ * @return array
+ */
public function print_comment($cmt, $nonjs = true) {
global $OUTPUT;
$patterns = array();
$replacements = array();
if (!empty($cmt->delete) && empty($nonjs)) {
- $cmt->content = '<div class="comment-delete"><a href="#" id ="comment-delete-'.$this->cid.'-'.$cmt->id.'"><img src="'.$OUTPUT->pix_url('t/delete').'" alt="'.get_string('delete').'" /></a></div>' . $cmt->content;
- // add the button
+ $deletelink = html_writer::start_tag('div', array('class'=>'comment-delete'));
+ $deletelink .= html_writer::start_tag('a', array('href' => '#', 'id' => 'comment-delete-'.$this->cid.'-'.$cmt->id));
+ $deletelink .= $OUTPUT->pix_icon('t/delete', get_string('delete'));
+ $deletelink .= html_writer::end_tag('a');
+ $deletelink .= html_writer::end_tag('div');
+ $cmt->content = $deletelink . $cmt->content;
}
$patterns[] = '___picture___';
$patterns[] = '___name___';
@@ -741,12 +867,101 @@ public function print_comment($cmt, $nonjs = true) {
// use html template to format a single comment.
return str_replace($patterns, $replacements, $this->template);
}
+
+ /**
+ * Revoke validate callbacks
+ *
+ * @param stdClass $params addtionall parameters need to add to callbacks
+ */
+ protected function validate($params=array()) {
+ foreach ($params as $key=>$value) {
+ $this->comment_param->$key = $value;
+ }
+ $validation = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'validate', array($this->comment_param), false);
+ if (!$validation) {
+ throw new comment_exception('invalidcommentparam');
+ }
+ }
+
+ /**
+ * Returns true if the user is able to view comments
+ * @return bool
+ */
+ public function can_view() {
+ $this->validate();
+ return !empty($this->viewcap);
+ }
+
+ /**
+ * Returns true if the user can add comments against this comment description
+ * @return bool
+ */
+ public function can_post() {
+ $this->validate();
+ return isloggedin() && !empty($this->postcap);
+ }
+
+ /**
+ * Returns true if the user can delete this comment
+ * @param int $commentid
+ * @return bool
+ */
+ public function can_delete($commentid) {
+ $this->validate(array('commentid'=>$commentid));
+ return has_capability('moodle/comment:delete', $this->context);
+ }
+
+ /**
+ * Returns the component associated with the comment
+ * @return string
+ */
+ public function get_compontent() {
+ return $this->component;
+ }
+
+ /**
+ * Returns the context associated with the comment
+ * @return stdClass
+ */
+ public function get_context() {
+ return $this->context;
+ }
+
+ /**
+ * Returns the course id associated with the comment
+ * @return int
+ */
+ public function get_courseid() {
+ return $this->courseid;
+ }
+
+ /**
+ * Returns the course module associated with the comment
+ *
+ * @return stdClass
+ */
+ public function get_cm() {
+ return $this->cm;
+ }
+
+ /**
+ * Returns the item id associated with the comment
+ *
+ * @return int
+ */
+ public function get_itemid() {
+ return $this->itemid;
+ }
+
+ /**
+ * Returns the comment area associated with the commentarea
+ *
+ * @return stdClass
+ */
+ public function get_commentarea() {
+ return $this->commentarea;
+ }
}
class comment_exception extends moodle_exception {
- public $message;
- function __construct($errorcode) {
- $this->errorcode = $errorcode;
- $this->message = get_string($errorcode, 'error');
- }
}
View
156 comment/locallib.php
@@ -23,46 +23,70 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class comment_manager {
+
+ /**
+ * The number of comments to display per page
+ * @var int
+ */
private $perpage;
- function __construct() {
+
+ /**
+ * Constructs the comment_manage object
+ */
+ public function __construct() {
global $CFG;
$this->perpage = $CFG->commentsperpage;
}
/**
* Return comments by pages
+ *
+ * @global moodle_database $DB
* @param int $page
- * @return mixed
+ * @return array An array of comments
*/
function get_comments($page) {
- global $DB, $CFG, $USER;
- $params = array();
+ global $DB;
+
if ($page == 0) {
$start = 0;
} else {
- $start = $page*$this->perpage;
+ $start = $page * $this->perpage;
}
- $sql = "SELECT c.id, c.contextid, c.itemid, c.commentarea, c.userid, c.content, u.firstname, u.lastname, c.timecreated
- FROM {comments} c, {user} u
- WHERE u.id=c.userid ORDER BY c.timecreated ASC";
-
$comments = array();
+
+ $sql = "SELECT c.id, c.contextid, c.itemid, c.commentarea, c.userid, c.content, u.firstname, u.lastname, c.timecreated
+ FROM {comments} c
+ JOIN {user} u
+ ON u.id=c.userid
+ ORDER BY c.timecreated ASC";
+ $rs = $DB->get_recordset_sql($sql, null, $start, $this->perpage);
$formatoptions = array('overflowdiv' => true);
- if ($records = $DB->get_records_sql($sql, array(), $start, $this->perpage)) {
- foreach ($records as $item) {
- $item->fullname = fullname($item);
- $item->time = userdate($item->timecreated);
- $item->content = format_text($item->content, FORMAT_MOODLE, $formatoptions);
- $comments[] = $item;
- unset($item->firstname);
- unset($item->lastname);
- unset($item->timecreated);
- }
+ foreach ($rs as $item) {
+ // Set calculated fields
+ $item->fullname = fullname($item);
+ $item->time = userdate($item->timecreated);
+ $item->content = format_text($item->content, FORMAT_MOODLE, $formatoptions);
+ // Unset fields not related to the comment
+ unset($item->firstname);
+ unset($item->lastname);
+ unset($item->timecreated);
+ // Record the comment
+ $comments[] = $item;
}
+ $rs->close();
return $comments;
}
+ /**
+ * Records the course object
+ *
+ * @global moodle_page $PAGE
+ * @global moodle_database $DB
+ * @param int $courseid
+ * @return void
+ */
private function setup_course($courseid) {
global $PAGE, $DB;
if (!empty($this->course)) {
@@ -71,88 +95,116 @@ private function setup_course($courseid) {
}
if ($courseid == $PAGE->course->id) {
$this->course = $PAGE->course;
- } else if (!$this->course = $DB->get_record('course', array('id'=>$courseid))) {
+ } else if (!$this->course = $DB->get_record('course', array('id' => $courseid))) {
$this->course = null;
}
}
+ /**
+ * Sets up the module or block information for a comment
+ *
+ * @global moodle_database $DB
+ * @param stdClass $comment
+ * @return bool
+ */
private function setup_plugin($comment) {
global $DB;
$this->context = get_context_instance_by_id($comment->contextid);
- if (!is_object($this->context)) {
- return;
+ if (!$this->context) {
+ return false;
}
- if ($this->context->contextlevel == CONTEXT_BLOCK) {
- if ($block = $DB->get_record('block_instances', array('id'=>$this->context->instanceid))) {
- $this->plugintype = 'block';
- $this->pluginname = $block->blockname;
- }
- }
- if ($this->context->contextlevel == CONTEXT_MODULE) {
- $this->plugintype = 'mod';
- $this->cm = get_coursemodule_from_id('', $this->context->instanceid);
- $this->setup_course($this->cm->course);
- $this->modinfo = get_fast_modinfo($this->course);
- $this->pluginname = $this->modinfo->cms[$this->cm->id]->modname;
+ switch ($this->context->contextlevel) {
+ case CONTEXT_BLOCK:
+ if ($block = $DB->get_record('block_instances', array('id' => $this->context->instanceid))) {
+ $this->plugintype = 'block';
+ $this->pluginname = $block->blockname;
+ } else {
+ return false;
+ }
+ break;
+ case CONTEXT_MODULE:
+ $this->plugintype = 'mod';
+ $this->cm = get_coursemodule_from_id('', $this->context->instanceid);
+ $this->setup_course($this->cm->course);
+ $this->modinfo = get_fast_modinfo($this->course);
+ $this->pluginname = $this->modinfo->cms[$this->cm->id]->modname;
+ break;
}
+ return true;
}
/**
* Print comments
* @param int $page
+ * @return boolean return false if no comments available
*/
- function print_comments($page=0) {
- global $CFG, $OUTPUT, $DB;
- $count = $DB->count_records_sql('SELECT COUNT(*) FROM {comments} c');
+ public function print_comments($page = 0) {
+ global $OUTPUT, $CFG, $OUTPUT, $DB;
+
+ $count = $DB->count_records('comments');
$comments = $this->get_comments($page);
+ if (count($comments) == 0) {
+ echo $OUTPUT->notification(get_string('nocomments', 'moodle'));
+ return false;
+ }
+
$table = new html_table();
- $table->head = array (html_writer::checkbox('selectall', '', false, get_string('selectall'), array('id'=>'comment_select_all', 'class'=>'comment-report-selectall')), get_string('author', 'search'), get_string('content'), get_string('action'));
+ $table->head = array (
+ html_writer::checkbox('selectall', '', false, get_string('selectall'), array('id'=>'comment_select_all', 'class'=>'comment-report-selectall')),
+ get_string('author', 'search'),
+ get_string('content'),
+ get_string('action')
+ );
$table->align = array ('left', 'left', 'left', 'left');
$table->attributes = array('class'=>'generaltable commentstable');
$table->data = array();
- $linkbase = $CFG->wwwroot.'/comment/index.php?action=delete&sesskey='.sesskey();
+
+ $link = new moodle_url('/comment/index.php', array('action' => 'delete', 'sesskey' => sesskey()));
foreach ($comments as $c) {
- $link = $linkbase . '&commentid='. $c->id;
$this->setup_plugin($c);
if (!empty($this->plugintype)) {
- $context_url = plugin_callback($this->plugintype, $this->pluginname, FEATURE_COMMENT, 'url', array($c));
+ $context_url = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'url', array($c));
}
$checkbox = html_writer::checkbox('comments', $c->id, false);
- $action = html_writer::link($link, get_string('delete'));
+ $action = html_writer::link(new moodle_url($link, array('commentid' => $c->id)), get_string('delete'));
if (!empty($context_url)) {
- $action .= html_writer::tag('br', null);
+ $action .= html_writer::empty_tag('br');
$action .= html_writer::link($context_url, get_string('commentincontext'), array('target'=>'_blank'));
}
$table->data[] = array($checkbox, $c->fullname, $c->content, $action);
}
echo html_writer::table($table);
echo $OUTPUT->paging_bar($count, $page, $this->perpage, $CFG->wwwroot.'/comment/index.php');
+ return true;
}
/**
- * delete a comment
+ * Delete a comment
+ *
* @param int $commentid
+ * @return bool
*/
public function delete_comment($commentid) {
global $DB;
- if ($comment = $DB->get_record('comments', array('id'=>$commentid))) {
- $DB->delete_records('comments', array('id'=>$commentid));
+ if ($DB->record_exists('comments', array('id' => $commentid))) {
+ $DB->delete_records('comments', array('id' => $commentid));
return true;
}
return false;
}
/**
- * delete comments
- * @param int $commentid
+ * Delete comments
+ *
+ * @param string $list A list of comment ids separated by hyphens
+ * @return bool
*/
public function delete_comments($list) {
global $DB;
$ids = explode('-', $list);
foreach ($ids as $id) {
- if (is_int((int)$id)) {
- if ($comment = $DB->get_record('comments', array('id'=>$id))) {
- $DB->delete_records('comments', array('id'=>$comment->id));
- }
+ $id = (int)$id;
+ if ($DB->record_exists('comments', array('id' => $id))) {
+ $DB->delete_records('comments', array('id' => $id));
}
}
return true;
View
7 lang/en/error.php
@@ -32,6 +32,7 @@
$string['blockdoesnotexist'] = 'This block does not exist';
$string['blockdoesnotexistonpage'] = 'This block (id={$a->instanceid}) does not exist on this page ({$a->url}).';
$string['blocknameconflict'] = 'Naming conflict: block {$a->name} has the same title with an existing block: {$a->conflict}!';
+$string['callbackrejectcomment'] = 'Comment callback rejected this comment.';
$string['cannotaddcoursemodule'] = 'Could not add a new course module';
$string['cannotaddcoursemoduletosection'] = 'Could not add the new course module to that section';
$string['cannotaddmodule'] = '{$a} module could not be added to the module list!';
@@ -261,6 +262,11 @@
$string['invalidcategory'] = 'Incorrect category!';
$string['invalidcategoryid'] = 'Incorrect category id!';
$string['invalidcomment'] = 'Comment is incorrect';
+$string['invalidcommentid'] = 'Invalid comment id';
+$string['invalidcommentitemid'] = 'Invalid comment itemid';
+$string['invalidcommentarea'] = 'Invalid comment area';
+$string['invalidcommentparam'] = 'Invalid comment parameters';
+$string['invalidcomponent'] = 'Invalid component name';
$string['invalidconfirmdata'] = 'Invalid confirmation data';
$string['invalidcontext'] = 'Invalid context';
$string['invalidcourse'] = 'Invalid course';
@@ -343,7 +349,6 @@
$string['moduledoesnotexist'] = 'This module does not exist';
$string['moduleinstancedoesnotexist'] = 'The instance of this module does not exist';
$string['modulemissingcode'] = 'Module {$a} is missing the code needed to perform this function';
-$string['modulerejectcomment'] = 'Module rejects to add this comment';
$string['multiplerecordsfound'] = 'Multiple records found, only one record expected.';
$string['multiplerestorenotallow'] = 'Multiple restore execution not allowed!';
$string['mustbeloggedin'] = 'You must be logged in to do this';
View
2  lang/en/moodle.php
@@ -242,6 +242,7 @@
$string['collapseall'] = 'Collapse all';
$string['commentincontext'] = 'Find this comment in context';
$string['comments'] = 'Comments';
+$string['commentsnotenabled'] = 'Comments feature is not enabled';
$string['commentsrequirelogin'] = 'You need to login to view the comments';
$string['comparelanguage'] = 'Compare and edit current language';
$string['complete'] = 'Complete';
@@ -1134,6 +1135,7 @@
$string['nocourses'] = 'No courses';
$string['nocoursesfound'] = 'No courses were found with the words \'{$a}\'';
$string['nocoursesyet'] = 'No courses in this category';
+$string['nocomments'] = 'No comments';
$string['nodstpresets'] = 'The administrator has not enabled Daylight Savings Time support.';
$string['nofilesselected'] = 'No files have been selected to restore';
$string['nofilesyet'] = 'No files have been uploaded to your course yet';
View
2  lib/moodlelib.php
@@ -7293,7 +7293,7 @@ function plugin_callback($type, $name, $feature, $action, $options = null, $defa
$name = clean_param($name, PARAM_SAFEDIR);
$function = $name.'_'.$feature.'_'.$action;
- $file = get_plugin_directory($type, $name) . '/lib.php';
+ $file = get_component_directory($type . '_' . $name) . '/lib.php';
// Load library and look for function
if (file_exists($file)) {
View
1  mod/data/lang/en/data.php
@@ -62,6 +62,7 @@
$string['comments'] = 'Comments';
$string['commentsaved'] = 'Comment saved';
$string['commentsn'] = '{$a} comment(s)';
+$string['commentsoff'] = 'Comments feature is not enabled';
$string['configenablerssfeeds'] = 'This switch will enable the possibility of RSS feeds for all databases. You will still need to turn feeds on manually in the settings for each database.';
$string['confirmdeletefield'] = 'You are about to delete this field, are you sure?';
$string['confirmdeleterecord'] = 'Are you sure you want to delete this entry?';
View
105 mod/data/lib.php
@@ -3171,3 +3171,108 @@ function data_presets_export($course, $cm, $data, $tostorage=false) {
// Return the full path to the exported preset file:
return $exportfile;
}
+
+/**
+ * Running addtional permission check on plugin, for example, plugins
+ * may have switch to turn on/off comments option, this callback will
+ * affect UI display, not like pluginname_comment_validate only throw
+ * exceptions.
+ * Capability check has been done in comment->check_permissions(), we
+ * don't need to do it again here.
+ *
+ * @param stdClass $comment_param {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return array
+ */
+function data_comment_permissions($comment_param) {
+ global $CFG, $DB;
+ if (!$record = $DB->get_record('data_records', array('id'=>$comment_param->itemid))) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ if (!$data = $DB->get_record('data', array('id'=>$record->dataid))) {
+ throw new comment_exception('invalidid', 'data');
+ }
+ if ($data->comments) {
+ return array('post'=>true, 'view'=>true);
+ } else {
+ return array('post'=>false, 'view'=>false);
+ }
+}
+
+/**
+ * Validate comment parameter before perform other comments actions
+ *
+ * @param stdClass $comment_param {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return boolean
+ */
+function data_comment_validate($comment_param) {
+ global $DB;
+ // validate comment area
+ if ($comment_param->commentarea != 'database_entry') {
+ throw new comment_exception('invalidcommentarea');
+ }
+ // validate itemid
+ if (!$record = $DB->get_record('data_records', array('id'=>$comment_param->itemid))) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ if (!$data = $DB->get_record('data', array('id'=>$record->dataid))) {
+ throw new comment_exception('invalidid', 'data');
+ }
+ if (!$course = $DB->get_record('course', array('id'=>$data->course))) {
+ throw new comment_exception('coursemisconf');
+ }
+ if (!$cm = get_coursemodule_from_instance('data', $data->id, $course->id)) {
+ throw new comment_exception('invalidcoursemodule');
+ }
+ if (!$data->comments) {
+ throw new comment_exception('commentsoff', 'data');
+ }
+ $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+
+ //check if approved
+ if ($data->approval and !$record->approved and !data_isowner($record) and !has_capability('mod/data:approve', $context)) {
+ throw new comment_exception('notapproved', 'data');
+ }
+
+ // group access
+ if ($record->groupid) {
+ $groupmode = groups_get_activity_groupmode($cm, $course);
+ if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
+ if (!groups_is_member($record->groupid)) {
+ throw new comment_exception('notmemberofgroup');
+ }
+ }
+ }
+ // validate context id
+ if ($context->id != $comment_param->context->id) {
+ throw new comment_exception('invalidcontext');
+ }
+ // validation for comment deletion
+ if (!empty($comment_param->commentid)) {
+ if ($comment = $DB->get_record('comments', array('id'=>$comment_param->commentid))) {
+ if ($comment->commentarea != 'database_entry') {
+ throw new comment_exception('invalidcommentarea');
+ }
+ if ($comment->contextid != $comment_param->context->id) {
+ throw new comment_exception('invalidcontext');
+ }
+ if ($comment->itemid != $comment_param->itemid) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ } else {
+ throw new comment_exception('invalidcommentid');
+ }
+ }
+ return true;
+}
View
1  mod/glossary/lang/en/glossary.php
@@ -216,6 +216,7 @@
$string['nopermissiontodelinglossary'] = 'You can\'t comments in this glossary!';
$string['nopermissiontoviewresult'] = 'You can only look at results for your own entries';
$string['notcategorised'] = 'Not categorised';
+$string['notapproved'] = 'glossary entry is not approved yet.';
$string['numberofentries'] = 'Number of entries';
$string['onebyline'] = '(one per line)';
$string['pluginadministration'] = 'Glossary administration';
View
79 mod/glossary/lib.php
@@ -2712,3 +2712,82 @@ function glossary_extend_settings_navigation(settings_navigation $settings, navi
$glossarynode->add($string, $url, settings_navigation::TYPE_SETTING, null, null, new pix_icon('i/rss', ''));
}
}
+
+/**
+ * Running addtional permission check on plugin, for example, plugins
+ * may have switch to turn on/off comments option, this callback will
+ * affect UI display, not like pluginname_comment_validate only throw
+ * exceptions.
+ * Capability check has been done in comment->check_permissions(), we
+ * don't need to do it again here.
+ *
+ * @param stdClass $comment_param {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return array
+ */
+function glossary_comment_permissions($comment_param) {
+ return array('post'=>true, 'view'=>true);
+}
+
+/**
+ * Validate comment parameter before perform other comments actions
+ *
+ * @param stdClass $comment_param {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return boolean
+ */
+function glossary_comment_validate($comment_param) {
+ global $DB;
+ // validate comment area
+ if ($comment_param->commentarea != 'glossary_entry') {
+ throw new comment_exception('invalidcommentarea');
+ }
+ if (!$record = $DB->get_record('glossary_entries', array('id'=>$comment_param->itemid))) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ if (!$glossary = $DB->get_record('glossary', array('id'=>$record->glossaryid))) {
+ throw new comment_exception('invalidid', 'data');
+ }
+ if (!$course = $DB->get_record('course', array('id'=>$glossary->course))) {
+ throw new comment_exception('coursemisconf');
+ }
+ if (!$cm = get_coursemodule_from_instance('glossary', $glossary->id, $course->id)) {
+ throw new comment_exception('invalidcoursemodule');
+ }
+ $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+
+ if ($glossary->defaultapproval and !$record->approved and !has_capability('mod/glossary:approve', $context)) {
+ throw new comment_exception('notapproved', 'glossary');
+ }
+ // validate context id
+ if ($context->id != $comment_param->context->id) {
+ throw new comment_exception('invalidcontext');
+ }
+ // validation for comment deletion
+ if (!empty($comment_param->commentid)) {
+ if ($comment = $DB->get_record('comments', array('id'=>$comment_param->commentid))) {
+ if ($comment->commentarea != 'glossary_entry') {
+ throw new comment_exception('invalidcommentarea');
+ }
+ if ($comment->contextid != $comment_param->context->id) {
+ throw new comment_exception('invalidcontext');
+ }
+ if ($comment->itemid != $comment_param->itemid) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ } else {
+ throw new comment_exception('invalidcommentid');
+ }
+ }
+ return true;
+}
View
89 mod/wiki/lib.php
@@ -548,3 +548,92 @@ function wiki_extend_navigation(navigation_node $navref, $course, $module, $cm)
function wiki_get_extra_capabilities() {
return array('moodle/comment:view', 'moodle/comment:post', 'moodle/comment:delete');
}
+
+/**
+ * Running addtional permission check on plugin, for example, plugins
+ * may have switch to turn on/off comments option, this callback will
+ * affect UI display, not like pluginname_comment_validate only throw
+ * exceptions.
+ * Capability check has been done in comment->check_permissions(), we
+ * don't need to do it again here.
+ *
+ * @param stdClass $comment_param {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return array
+ */
+function wiki_comment_permissions($comment_param) {
+ return array('post'=>true, 'view'=>true);
+}
+
+/**
+ * Validate comment parameter before perform other comments actions
+ *
+ * @param stdClass $comment_param {
+ * context => context the context object
+ * courseid => int course id
+ * cm => stdClass course module object
+ * commentarea => string comment area
+ * itemid => int itemid
+ * }
+ * @return boolean
+ */
+function wiki_comment_validate($comment_param) {
+ global $DB, $CFG;
+ require_once($CFG->dirroot . '/mod/wiki/locallib.php');
+ // validate comment area
+ if ($comment_param->commentarea != 'wiki_page') {
+ throw new comment_exception('invalidcommentarea');
+ }
+ // validate itemid
+ if (!$record = $DB->get_record('wiki_pages', array('id'=>$comment_param->itemid))) {
+ throw new comment_exception('invalidcommentitemid');
+ }
+ if (!$subwiki = wiki_get_subwiki($record->subwikiid)) {
+ throw new comment_exception('invalidsubwikiid');
+ }
+ if (!$wiki = wiki_get_wiki_from_pageid($comment_param->itemid)) {
+ throw new comment_exception('invalidid', 'data');
+ }
+ if (!$course = $DB->get_record('course', array('id'=>$wiki-&g