Merge pull request #1273 from dnos/chamilo-pr/1.11.x

New feature to let choose which users can see or not which courses in the catalogue
remotes/angel/1.11.x
Yannick Warnier 8 years ago committed by GitHub
commit 7c9d14b81b
  1. 42
      app/Migrations/Schema/V111/Version20160706182000.php
  2. 2
      main/auth/courses.php
  3. 5
      main/auth/courses_controller.php
  4. 7
      main/inc/lib/auth.lib.php
  5. 194
      main/inc/lib/course.lib.php
  6. 17
      main/inc/lib/course_category.lib.php
  7. 1
      main/inc/lib/database.constants.inc.php
  8. 220
      main/webservices/registration.soap.php
  9. 171
      src/Chamilo/CoreBundle/Entity/CourseRelUserCatalogue.php

@ -0,0 +1,42 @@
<?php
/* For licensing terms, see /license.txt */
namespace Application\Migrations\Schema\V111;
use Application\Migrations\AbstractMigrationChamilo;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Type;
/**
* Class Version20160706182000
* Add new table to save user visibility on courses in the catalogue
* @package Application\Migrations\Schema\V111
*/
class Version20160706182000 extends AbstractMigrationChamilo
{
/**
* @param Schema $schema
*
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function up(Schema $schema)
{
$this->addSql(
'CREATE TABLE course_rel_user_catalogue (id int NOT NULL AUTO_INCREMENT, user_id int DEFAULT NULL, c_id int DEFAULT NULL, visible int NOT NULL, PRIMARY KEY (id), KEY (user_id), KEY (c_id), CONSTRAINT FOREIGN KEY (c_id) REFERENCES course (id) ON DELETE CASCADE, CONSTRAINT FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
);
}
/**
* @param Schema $schema
*
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function down(Schema $schema)
{
$this->addSql(
'DROP TABLE course_rel_user_catalogue'
);
}
}

@ -144,7 +144,7 @@ if (isset($_POST['create_course_category']) &&
// search courses
if (isset($_REQUEST['search_course'])) {
if ($ctok == $_REQUEST['sec_token']) {
$courses_controller->search_courses($_REQUEST['search_term'], null, null, null, $limit);
$courses_controller->search_courses($_REQUEST['search_term'], null, null, null, $limit, true);
}
}

@ -163,15 +163,16 @@ class CoursesController
* @param string $error
* @param string $content
* @param $limit
* @param boolean $justVisible Whether to search only in courses visibles in the catalogue
*/
public function search_courses($search_term, $message = '', $error = '', $content = null, $limit = array())
public function search_courses($search_term, $message = '', $error = '', $content = null, $limit = array(), $justVisible = false)
{
$data = array();
$limit = !empty($limit) ? $limit : CourseCategory::getLimitArray();
$browse_course_categories = $this->model->browse_course_categories();
$data['countCoursesInCategory'] = $this->model->count_courses_in_category('ALL', $search_term);
$data['browse_courses_in_category'] = $this->model->search_courses($search_term, $limit);
$data['browse_courses_in_category'] = $this->model->search_courses($search_term, $limit, $justVisible);
$data['browse_course_categories'] = $browse_course_categories;
$data['search_term'] = Security::remove_XSS($search_term); //filter before showing in template

@ -403,9 +403,10 @@ class Auth
* The search is done on the code, title and tutor field of the course table.
* @param string $search_term The string that the user submitted, what we are looking for
* @param array $limit
* @param boolean $justVisible search only on visible courses in the catalogue
* @return array An array containing a list of all the courses matching the the search term.
*/
public function search_courses($search_term, $limit)
public function search_courses($search_term, $limit, $justVisible=false)
{
$courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
$extraFieldTable = Database :: get_main_table(TABLE_EXTRA_FIELD);
@ -433,6 +434,8 @@ class Auth
$without_special_courses = ' AND course.code NOT IN (' . implode(',', $special_course_list) . ')';
}
$visibilityCondition = ($justVisible?CourseManager::getCourseVisibilitySQLCondition('course'):'');
$search_term_safe = Database::escape_string($search_term);
$sql_find = "SELECT * FROM $courseTable
WHERE (
@ -441,6 +444,7 @@ class Auth
tutor_name LIKE '%" . $search_term_safe . "%'
)
$without_special_courses
$visibilityCondition
ORDER BY title, visual_code ASC
$limitFilter
";
@ -460,6 +464,7 @@ class Auth
tutor_name LIKE '%" . $search_term_safe . "%'
)
$without_special_courses
$visibilityCondition
ORDER BY title, visual_code ASC
$limitFilter
";

@ -739,6 +739,107 @@ class CourseManager
return $insertId;
}
/**
* Add the user $userId visibility to the course $courseCode in the catalogue.
* @author David Nos (https://github.com/dnos)
*
* @param int $userId the id of the user
* @param string $courseCode the course code
* @param int $visible (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
*
* @return boolean true if added succesfully, false otherwise.
*/
public static function addUserVisibilityToCourseInCatalogue($userId, $courseCode, $visible = 1)
{
$debug = false;
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
return false;
}
$courseCode = Database::escape_string($courseCode);
$courseInfo = api_get_course_info($courseCode);
$courseId = $courseInfo['real_id'];
// Check in advance whether the user has already been registered on the platform.
$sql = "SELECT status FROM " . $userTable . " WHERE user_id = $userId ";
if (Database::num_rows(Database::query($sql)) == 0) {
if ($debug) {
error_log('The user has not been registered to the platform');
}
return false; // The user has not been registered to the platform.
}
// Check whether the user has already been registered to the course visibility in the catalogue.
$sql = "SELECT * FROM $courseUserTable
WHERE
user_id = $userId AND
visible = " . $visible . " AND
c_id = $courseId";
if (Database::num_rows(Database::query($sql)) > 0) {
if ($debug) {
error_log('The user has been already registered to the course visibility in the catalogue');
}
return true; // The visibility of the user to the course in the catalogue does already exist.
}
// Register the user visibility to course in catalogue.
$params = [
'user_id' => $userId,
'c_id' => $courseId,
'visible' => $visible
];
$insertId = Database::insert($courseUserTable, $params);
return $insertId;
}
/**
* Remove the user $userId visibility to the course $courseCode in the catalogue.
* @author David Nos (https://github.com/dnos)
*
* @param int $userId the id of the user
* @param string $courseCode the course code
* @param int $visible (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
*
* @return boolean true if removed succesfully or register not found, false otherwise.
*/
public static function removeUserVisibilityToCourseInCatalogue($userId, $courseCode, $visible = 1)
{
$courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
return false;
}
$courseCode = Database::escape_string($courseCode);
$courseInfo = api_get_course_info($courseCode);
$courseId = $courseInfo['real_id'];
// Check whether the user has already been registered to the course visibility in the catalogue.
$sql = "SELECT * FROM $courseUserTable
WHERE
user_id = $userId AND
visible = " . $visible . " AND
c_id = $courseId";
if (Database::num_rows(Database::query($sql)) > 0) {
$cond = array(
'user_id = ? AND c_id = ? AND visible = ? ' => array(
$userId,
$courseId,
$visible
)
);
return Database::delete($courseUserTable, $cond);
} else {
return true; // Register does not exist
}
}
/**
* Checks wether a parameter exists.
* If it doesn't, the function displays an error message.
@ -2496,6 +2597,58 @@ class CourseManager
return $courseList;
}
/**
* Get the course codes that have been restricted in the catalogue, and if byUserId is set
* then the courses that the user is allowed or not to see in catalogue
*
* @param boolean allowed Either if the courses have some users that are or are not allowed to see in catalogue
* @param boolean byUserId if the courses are or are not allowed to see to the user
* @return array Course codes allowed or not to see in catalogue by some user or the user
*/
public static function getCatalogueCourseList($allowed = true, $byUserId = -1)
{
$courseTable = Database:: get_main_table(TABLE_MAIN_COURSE);
$tblCourseRelUserCatalogue = Database:: get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
$visibility = ($allowed?1:0);
// Restriction by user id
$currentUserRestriction = "";
if ($byUserId > 0) {
$currentUserRestriction = " AND tcruc.user_id = $byUserId ";
}
//we filter the courses from the URL
$joinAccessUrl = '';
$whereAccessUrl = '';
if (api_get_multiple_access_url()) {
$accessUrlId = api_get_current_access_url_id();
if ($accessUrlId != -1) {
$tblUrlCourse = Database:: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
$joinAccessUrl = "LEFT JOIN $tblUrlCourse url_rel_course
ON url_rel_course.c_id = c.id ";
$whereAccessUrl = " AND access_url_id = $accessUrlId ";
}
}
// get course list auto-register
$sql = "SELECT DISTINCT(c.code)
FROM $tblCourseRelUserCatalogue tcruc
INNER JOIN $courseTable c
ON (c.id = tcruc.c_id) $joinAccessUrl
WHERE tcruc.visible = $visibility $currentUserRestriction $whereAccessUrl";
$result = Database::query($sql);
$courseList = array();
if (Database::num_rows($result) > 0) {
while ($resultRow = Database::fetch_array($result)) {
$courseList[] = $resultRow['code'];
}
}
return $courseList;
}
/**
* Get list of courses for a given user
* @param int $user_id
@ -4784,6 +4937,39 @@ class CourseManager
return $row[0];
}
/**
* Returns the SQL conditions to filter course only visible by the user in the catalogue
*
* @param $courseTableAlias Alias of the course table
* @return string SQL conditions
*/
public static function getCourseVisibilitySQLCondition($courseTableAlias) {
$visibilityCondition = '';
$hidePrivate = api_get_setting('course_catalog_hide_private');
if ($hidePrivate === 'true') {
$visibilityCondition = ' AND '.$courseTableAlias.'.visibility <> 1';
}
// Check if course have users allowed to see it in the catalogue, then show only if current user is allowed to see it
$currentUserId = api_get_user_id();
$restrictedCourses = self::getCatalogueCourseList(true);
$allowedCoursesToCurrentUser = self::getCatalogueCourseList(true, $currentUserId);
if (!empty($restrictedCourses)) {
$visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("' . implode('","', $restrictedCourses) . '")';
$visibilityCondition .= ' OR '.$courseTableAlias.'.code IN ("' . implode('","', $allowedCoursesToCurrentUser) . '"))';
}
// Check if course have users denied to see it in the catalogue, then show only if current user is not denied to see it
$restrictedCourses = self::getCatalogueCourseList(false);
$notAllowedCoursesToCurrentUser = self::getCatalogueCourseList(false, $currentUserId);
if (!empty($restrictedCourses)) {
$visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("' . implode('","', $restrictedCourses) . '")';
$visibilityCondition .= ' OR '.$courseTableAlias.'.code NOT IN ("' . implode('","', $notAllowedCoursesToCurrentUser) . '"))';
}
return $visibilityCondition;
}
/**
* Get available le courses count
* @param int Access URL ID (optional)
@ -4801,14 +4987,8 @@ class CourseManager
$withoutSpecialCourses = ' AND c.code NOT IN ("' . implode('","', $specialCourseList) . '")';
}
$visibilityCondition = null;
$visibilityCondition = self::getCourseVisibilitySQLCondition('c');
$hidePrivate = api_get_setting('course_catalog_hide_private');
if ($hidePrivate === 'true') {
$courseInfo = api_get_course_info();
$courseVisibility = $courseInfo['visibility'];
$visibilityCondition = ' AND c.visibility <> 1';
}
if (!empty($accessUrlId) && $accessUrlId == intval($accessUrlId)) {
$sql = "SELECT count(c.id) FROM $tableCourse c, $tableCourseRelAccessUrl u
WHERE

@ -592,13 +592,7 @@ class CourseCategory
$without_special_courses = ' AND course.code NOT IN ("'.implode('","', $specialCourseList).'")';
}
$visibilityCondition = null;
$hidePrivate = api_get_setting('course_catalog_hide_private');
if ($hidePrivate === 'true') {
$courseInfo = api_get_course_info();
$courseVisibility = $courseInfo['visibility'];
$visibilityCondition = ' AND course.visibility <> 1';
}
$visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course');
if ($categoryCode == 'ALL') {
// Nothing to do
@ -664,13 +658,8 @@ class CourseCategory
if (!empty($specialCourseList)) {
$without_special_courses = ' AND course.code NOT IN ("'.implode('","', $specialCourseList).'")';
}
$visibilityCondition = null;
$hidePrivate = api_get_setting('course_catalog_hide_private');
if ($hidePrivate === 'true') {
$courseInfo = api_get_course_info();
$courseVisibility = $courseInfo['visibility'];
$visibilityCondition = ' AND course.visibility <> 1';
}
$visibilityCondition = CourseManager::getCourseVisibilitySQLCondition("course");
if (!empty($random_value)) {
$random_value = intval($random_value);

@ -26,6 +26,7 @@ define('TABLE_MAIN_CLASS', 'class_item');
define('TABLE_MAIN_ADMIN', 'admin');
define('TABLE_MAIN_COURSE_CLASS', 'course_rel_class');
define('TABLE_MAIN_COURSE_USER', 'course_rel_user');
define('TABLE_MAIN_COURSE_CATALOGUE_USER', 'course_rel_user_catalogue');
define('TABLE_MAIN_CLASS_USER', 'class_user');
define('TABLE_MAIN_CATEGORY', 'course_category');
define('TABLE_MAIN_COURSE_MODULE', 'course_module');

@ -6830,6 +6830,226 @@ function WSDeleteUserFromGroup($params)
/* Delete user from group Web Service end */
/** WSRegisterUserVisibilityToCourseCatalogue **/
// Register the data structures used by the service
$server->wsdl->addComplexType(
'user_course_visibility',
'complexType',
'struct',
'all',
'',
array (
'course_id' => array('name' => 'course_id', 'type' => 'tns:course_id'),
'user_id' => array('name' => 'user_id', 'type' => 'tns:user_id'),
'visible' => array('name' => 'status', 'type' => 'xsd:int')
)
);
$server->wsdl->addComplexType(
'user_course_visibility_array',
'complexType',
'array',
'',
'SOAP-ENC:Array',
array(),
array(
array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:user_course_visibility[]')
),
'tns:user_course_visibility'
);
$server->wsdl->addComplexType(
'registerUserToCourseCatalogue_arg',
'complexType',
'struct',
'all',
'',
array (
'userscourses' => array('name' => 'userscourses', 'type' => 'tns:user_course_visibility_array'),
'secret_key' => array('name' => 'secret_key', 'type' => 'xsd:string')
)
);
$server->wsdl->addComplexType(
'registerUserToCourseCatalogue_return',
'complexType',
'struct',
'all',
'',
array(
'original_user_id_value' => array('name' => 'original_user_id_value', 'type' => 'xsd:string'),
'original_course_id_value' => array('name' => 'original_course_id_value', 'type' => 'xsd:string'),
'visible' => array('name' => 'visible', 'type' => 'xsd:int'),
'result' => array('name' => 'result', 'type' => 'xsd:int')
)
);
$server->wsdl->addComplexType(
'registerUserToCourseCatalogue_return_global',
'complexType',
'array',
'',
'SOAP-ENC:Array',
array(),
array(array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:registerUserToCourseCatalogue_return[]')),
'tns:registerUserToCourseCatalogue_return'
);
// Register the method to expose
$server->register('WSAddUserVisibilityToCourseInCatalogue', // method name
array('registerUserToCourseCatalogue' => 'tns:registerUserToCourseCatalogue_arg'), // input parameters
array('return' => 'tns:registerUserToCourseCatalogue_return_global'),
'urn:WSRegistration', // namespace
'urn:WSRegistration#WSRegisterUserVisibilityToCourseCatalogue', // soapaction
'rpc', // style
'encoded', // use
'This service registers the visibility of users to course in catalogue' // documentation
);
// define the method WSRegisterUserVisibilityToCourseInCatalogue
function WSAddUserVisibilityToCourseInCatalogue($params) {
global $debug;
if (!WSHelperVerifyKey($params)) {
return returnError(WS_ERROR_SECRET_KEY);
}
if ($debug) error_log('WSAddUserVisibilityToCourseCatalogue params: '.print_r($params, 1));
$results = array();
$userscourses = $params['userscourses'];
foreach ($userscourses as $usercourse) {
$original_course_id = $usercourse['course_id'];
$original_user_id = $usercourse['user_id'];
$visible = $usercourse['visible'];
$resultValue = 0;
// Get user id
$userId = UserManager::get_user_id_from_original_id(
$original_user_id['original_user_id_value'],
$original_user_id['original_user_id_name']
);
if ($debug) error_log('WSAddUserVisibilityToCourseCatalogue userId: '.$userId);
if ($userId == 0) {
// If user was not found, there was a problem
$resultValue = 0;
} else {
// User was found
$courseInfo = CourseManager::getCourseInfoFromOriginalId(
$original_course_id['original_course_id_value'],
$original_course_id['original_course_id_name']
);
$courseCode = $courseInfo['code'];
if (empty($courseCode)) {
// Course was not found
$resultValue = 0;
} else {
if ($debug) error_log('WSAddUserVisibilityToCourseCatalogue courseCode: '.$courseCode);
$result = CourseManager::addUserVisibilityToCourseInCatalogue($userId, $courseCode, $visible);
if ($result) {
$resultValue = 1;
if ($debug) error_log('WSAddUserVisibilityToCourseCatalogue registered');
} else {
if ($debug) error_log('WSAddUserVisibilityToCourseCatalogue NOT registered: ');
}
}
}
$results[] = array(
'original_user_id_value' => $original_user_id['original_user_id_value'],
'original_course_id_value' => $original_course_id['original_course_id_value'],
'visible' => $visible,
'result' => $resultValue
);
}
return $results;
}
// Register the method to expose
$server->register('WSRemoveUserVisibilityToCourseInCatalogue', // method name
array('registerUserToCourseCatalogue' => 'tns:registerUserToCourseCatalogue_arg'), // input parameters
array('return' => 'tns:registerUserToCourseCatalogue_return_global'),
'urn:WSRegistration', // namespace
'urn:WSRegistration#WSRegisterUserVisibilityToCourseCatalogue', // soapaction
'rpc', // style
'encoded', // use
'This service removes the visibility of users to course in catalogue' // documentation
);
// define the method WSRemoveUserVisibilityToCourseInCatalogue
function WSRemoveUserVisibilityToCourseInCatalogue($params) {
global $debug;
if (!WSHelperVerifyKey($params)) {
return returnError(WS_ERROR_SECRET_KEY);
}
if ($debug) error_log('WSRemoveUserVisibilityToCourseInCatalogue params: '.print_r($params, 1));
$results = array();
$userscourses = $params['userscourses'];
foreach ($userscourses as $usercourse) {
$original_course_id = $usercourse['course_id'];
$original_user_id = $usercourse['user_id'];
$visible = $usercourse['visible'];
$resultValue = 0;
// Get user id
$userId = UserManager::get_user_id_from_original_id(
$original_user_id['original_user_id_value'],
$original_user_id['original_user_id_name']
);
if ($debug) error_log('WSRemoveUserVisibilityToCourseInCatalogue user_id: '.$userId);
if ($userId == 0) {
// If user was not found, there was a problem
$resultValue = 0;
} else {
// User was found
$courseInfo = CourseManager::getCourseInfoFromOriginalId(
$original_course_id['original_course_id_value'],
$original_course_id['original_course_id_name']
);
$courseCode = $courseInfo['code'];
if (empty($courseCode)) {
// Course was not found
$resultValue = 0;
} else {
if ($debug) error_log('WSRemoveUserVisibilityToCourseInCatalogue courseCode: '.$courseCode);
$result = CourseManager::removeUserVisibilityToCourseInCatalogue($userId, $courseCode, $visible);
if ($result) {
$resultValue = 1;
if ($debug) error_log('WSRemoveUserVisibilityToCourseInCatalogue removed');
} else {
if ($debug) error_log('WSRemoveUserVisibilityToCourseInCatalogue NOT removed: ');
}
}
}
$results[] = array(
'original_user_id_value' => $original_user_id['original_user_id_value'],
'original_course_id_value' => $original_course_id['original_course_id_value'],
'visible' => $visible,
'result' => $resultValue
);
}
return $results;
}
// Add more webservices through hooks from plugins
if (!empty($hook)) {
$hook->setEventData(array('server' => $server));

@ -0,0 +1,171 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
use Chamilo\UserBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
/**
* CourseRelUserCatalogue
*
* @ORM\Table(
* name="course_rel_user_catalogue",
* indexes={
* @ORM\Index(name="course_rel_user_catalogue_user_id", columns={"user_id"}),
* @ORM\Index(name="course_rel_user_catalogue_c_id", columns={"c_id"})
* }
* )
* @ORM\Entity
* @ORM\Table(name="course_rel_user_catalogue")
*/
class CourseRelUserCatalogue
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false)
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
/**
* @var boolean
*
* @ORM\Column(name="visible", type="integer", precision=0, scale=0, nullable=false, unique=false)
*/
private $visible;
/**
* @ORM\ManyToOne(targetEntity="Chamilo\UserBundle\Entity\User", inversedBy="courses", cascade={"persist"})
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course", inversedBy="users", cascade={"persist"})
* @ORM\JoinColumn(name="c_id", referencedColumnName="id")
*/
protected $course;
/**
* Constructor
*/
public function __construct()
{
}
/**
* @return string
*/
public function __toString()
{
return strval($this->getCourse()->getCode());
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* @param Course $course
* @return $this
*/
public function setCourse(Course $course)
{
$this->course = $course;
return $this;
}
/**
* Get Course
*
* @return Course
*/
public function getCourse()
{
return $this->course;
}
/**
* @param $user
* @return $this
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* Get User
*
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* Set relationType
*
* @param integer $relationType
* @return CourseRelUserCatalogue
*/
public function setRelationType($relationType)
{
$this->relationType = $relationType;
return $this;
}
/**
* Get relationType
*
* @return integer
*/
public function getRelationType()
{
return $this->relationType;
}
/**
* Set visible
*
* @param boolean $visible
* @return CourseRelUserCatalogue
*/
public function setVisible($visible)
{
$this->visible = $visible;
return $this;
}
/**
* Get visible
*
* @return boolean
*/
public function getVisible()
{
return $this->visible;
}
}
Loading…
Cancel
Save