Add custom course icons see #7614

1.10.x
Julio Montoya 11 years ago
parent 469955a29a
commit 56be49acb8
  1. 13
      main/course_home/course_home.php
  2. 120
      main/course_info/tools.php
  3. 12
      main/inc/ajax/course_home.ajax.php
  4. 222
      main/inc/lib/course_home.lib.php
  5. 29
      main/inc/lib/image.lib.php
  6. 29
      src/Chamilo/CoreBundle/Migrations/Schema/V110/Version20150610143426.php
  7. 52
      src/Chamilo/CourseBundle/Entity/CTool.php

@ -285,7 +285,18 @@ if (api_get_setting('homepage_view') == 'activity' ||
} elseif (api_get_setting('homepage_view') == 'vertical_activity') {
require 'vertical_activity.php';
}
$content = '<div id="course_tools">'.$content.'</div>';
$editIconButton = '';
if (api_is_allowed_to_edit()) {
$editIconButton = '<div class="pull-right">'.Display::url(
get_lang('EditIcons'),
api_get_path(WEB_CODE_PATH).'course_info/tools.php?'.api_get_cidreq(),
['class' => 'btn btn-default' ]
);
$editIconButton .= '</div>';
}
$content = '<div id="course_tools">'.$editIconButton.$content.'</div>';
$tpl = new Template(null);
$tpl->assign('message', $show_message);
$tpl->assign('content', $content);

@ -0,0 +1,120 @@
<?php
/* For licensing terms, see /license.txt */
require_once '../inc/global.inc.php';
// The section for the tabs
$this_section = SECTION_COURSES;
api_protect_course_script(true);
if (!api_is_allowed_to_edit()) {
api_not_allowed(true);
}
$action = isset($_GET['action']) ? $_GET['action'] : '';
$id = isset($_GET['id']) ? intval($_GET['id']) : '';
switch ($action) {
case 'delete_icon':
$tool = CourseHome::getTool($id);
if (empty($tool)) {
api_not_allowed(true);
}
$currentUrl = api_get_self().'?'.api_get_cidreq();
Display::addFlash(Display::return_message(get_lang('Updated')));
CourseHome::deleteIcon($id);
header('Location: '.$currentUrl);
exit;
break;
case 'edit_icon':
$tool = CourseHome::getTool($id);
if (empty($tool)) {
api_not_allowed(true);
}
$interbreadcrumb[] = array('url' => api_get_self().'?'.api_get_cidreq(), 'name' => get_lang('Tools'));
$toolName = $tool['name'];
$currentUrl = api_get_self().'?action=edit_icon&id=' . $id.'&'.api_get_cidreq();
$form = new FormValidator('icon_edit', 'post', $currentUrl);
$form->addElement('header', get_lang('EditIcon'));
$form->addElement('text', 'name', get_lang('Name'));
$form->addElement('text', 'link', get_lang('Links'));
if (isset($tool['custom_icon']) && !empty($tool['custom_icon'])) {
$form->addLabel(
get_lang('Icon'),
Display::img(
CourseHome::getCustomWebIconPath().$tool['custom_icon']
)
);
$form->addCheckBox('delete_icon', null, get_lang('DeletePicture'));
}
$allowed_picture_types = array ('jpg', 'jpeg', 'png');
$form->addElement('file', 'icon', get_lang('CustomIcon'));
$form->addRule('icon', get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')', 'filetype', $allowed_picture_types);
$form->addElement('select', 'target', get_lang('Target'), array('_self' => '_self', '_blank' => '_blank'));
$form->addElement('select', 'visibility', get_lang('Visibility'), array(1 => get_lang('Visible'), 0 => get_lang('Invisible')));
$form->addElement('textarea', 'description', get_lang('Description'),array ('rows' => '3', 'cols' => '40'));
$form->addButtonUpdate(get_lang('Update'));
$form->setDefaults($tool);
$content = $form->returnForm();
if ($form->validate()) {
$data = $form->getSubmitValues();
CourseHome::updateTool($id, $data);
Display::addFlash(Display::return_message(get_lang('Updated')));
if (isset($data['delete_icon'])) {
CourseHome::deleteIcon($id);
}
header('Location: '.$currentUrl);
exit;
}
break;
case 'list':
default:
$toolName = get_lang('Tools');
$toolList = CourseHome::toolsIconsAction(
api_get_course_int_id(),
api_get_session_id()
);
$table = '<table class="data_table">';
foreach ($toolList as $tool) {
$table .= '<tr>';
$table .= '<td><a href="' . api_get_path(WEB_CODE_PATH) . $tool['link'] . '?' . api_get_cidreq() . '">
<img src="' . api_get_path(WEB_IMG_PATH).$tool['image']. '"></a></td>';
$table .= '<td><a href="' . api_get_path(WEB_CODE_PATH) . $tool['link'] . '?' . api_get_cidreq() . '">' .
$tool['name']. '</a></td>';
$table .= '<td>
<a class="btn btn-primary" href="' . api_get_self() . '?action=edit_icon&id=' . $tool['iid'] . '&'.api_get_cidreq().'">' .
get_lang('Edit'). '</a></td>';
$delete = (!empty($tool['custom_icon'])) ? '<a class="btn btn-danger" href="' . api_get_self() . '?action=delete_icon&id=' . $tool['iid'] . '&'.api_get_cidreq().'">' .
get_lang('Delete'). '</a>' : '';
$table .= '<td>' . $delete . '</td>';
$table .= '</tr>';
}
$table .= '</table>';
$content = $table;
break;
}
$tpl = new Template($toolName);
$tpl->assign('content', $content);
$template = $tpl->get_template('layout/layout_1_col.tpl');
$tpl->display($template);

@ -15,12 +15,13 @@ switch ($action) {
$tool_info = api_get_tool_information($_GET['id']);
$tool_visibility = $tool_info['visibility'];
$tool_image = $tool_info['image'];
if (api_get_setting('homepage_view') != 'activity_big') {
$tool_image = Display::return_icon($tool_image, null, null, null, null, true);
$na_image = str_replace('.gif', '_na.gif', $tool_image);
} else {
// Display::return_icon() also checks in the app/Resources/public/css/themes/{theme}/icons folder
$tool_image = (substr($tool_info['image'], 0, strpos($tool_info['image'], '.'))).'.png';
$tool_image = (substr($tool_image, 0, strpos($tool_image, '.'))).'.png';
$tool_image = Display::return_icon(
$tool_image,
get_lang(ucfirst($tool_info['name'])),
@ -32,6 +33,11 @@ switch ($action) {
$na_image = str_replace('.png', '_na.png', $tool_image);
}
if (isset($tool_info['custom_icon']) && !empty($tool_info['custom_icon'])) {
$tool_image = CourseHome::getCustomWebIconPath().$tool_info['custom_icon'];
$na_image = CourseHome::getCustomWebIconPath().CourseHome::getDisableIcon($tool_info['custom_icon']);
}
$requested_image = ($tool_visibility == 0 ) ? $tool_image : $na_image;
$requested_class = ($tool_visibility == 0 ) ? 'visible' : 'invisible';
$requested_message = ($tool_visibility == 0 ) ? 'is_active' : 'is_inactive';
@ -60,7 +66,9 @@ switch ($action) {
} else $sql="UPDATE $tool_table SET visibility=$requested_visible WHERE id='".$_GET["id"]."'";
*/
$sql = "UPDATE $tool_table SET visibility=$requested_visible WHERE c_id = $course_id AND id='" . intval($_GET['id']) . "'";
$sql = "UPDATE $tool_table SET
visibility = $requested_visible
WHERE c_id = $course_id AND id='" . intval($_GET['id']) . "'";
Database::query($sql);
}
$response_data = array(

@ -805,17 +805,14 @@ class CourseHome
// If it's a link, we don't add the cidReq
if ($tool['image'] == 'file_html.png' || $tool['image'] == 'file_html_na.png') {
$tool['link'] = $tool['link'].$qm_or_amp;
} else {
$tool['link'] = $tool['link'].$qm_or_amp.api_get_cidreq();
}
$tool_link_params = array();
$toolId = isset($tool["id"]) ? $tool["id"] : null;
//$tool['link'] = htmlspecialchars($tool['link']) ;
//@todo this visio stuff should be removed
if (strpos($tool['name'], 'visio_') !== false) {
$tool_link_params = array(
@ -871,6 +868,18 @@ class CourseHome
false
);
/*if (!empty($tool['custom_icon'])) {
$image = self::getCustomWebIconPath().$tool['custom_icon'];
$icon = Display::img(
$image,
$tool['description'],
array(
'class' => 'tool-icon',
'id' => 'toolimage_'.$tool['id']
)
);
}*/
// Validation when belongs to a session
$session_img = api_get_session_image($tool['session_id'], (!empty($_user['status']) ? $_user['status'] : ''));
if ($studentview) {
@ -881,7 +890,11 @@ class CourseHome
$item['tool'] = $tool;
$item['name'] = $tool_name;
$tool_link_params['id'] = 'is'.$tool_link_params['id'];
$item['link'] = Display::url($tool_name.$session_img, $tool_link_params['href'], $tool_link_params);
$item['link'] = Display::url(
$tool_name.$session_img,
$tool_link_params['href'],
$tool_link_params
);
$items[] = $item;
@ -900,12 +913,24 @@ class CourseHome
$html .= '<div class="col-xs-6 col-md-3 course-tool">';
$image = (substr($item['tool']['image'], 0, strpos($item['tool']['image'], '.'))).'.png';
$toolId = isset($item['tool']['id']) ? $item['tool']['id'] : null;
if (isset($item['tool']['custom_image'])) {
$original_image = Display::img(
$item['tool']['custom_image'],
$item['name'],
array('id' => 'toolimage_'.$toolId)
);
} elseif (isset($item['tool']['custom_icon'])) {
$customIcon = $item['tool']['custom_icon'];
if ($item['tool']['visibility'] == '0') {
$fileInfo = pathinfo($item['tool']['custom_icon']);
$customIcon = self::getDisableIcon($item['tool']['custom_icon']);
}
$original_image = Display::img(
self::getCustomWebIconPath().$customIcon,
$item['name'],
array('id' => 'toolimage_'.$toolId)
);
} else {
$original_image = Display::return_icon(
$image,
@ -1205,4 +1230,193 @@ class CourseHome
}
return $html;
}
/**
* List course homepage tools from authoring and interaction sections
* @param int $courseId The course ID (guessed from context if not provided)
* @param int $sessionId The session ID (guessed from context if not provided)
* @return array List of all tools data from the c_tools table
*/
public static function toolsIconsAction($courseId = null, $sessionId = null)
{
if (empty($courseId)) {
$courseId = api_get_course_int_id();
} else {
$courseId = intval($courseId);
}
if (empty($sessionId)) {
$sessionId = api_get_session_id();
} else {
$sessionId = intval($sessionId);
}
if (empty($courseId)) {
// We shouldn't get here, but for some reason api_get_course_int_id()
// doesn't seem to get the course from the context, sometimes
return array();
}
$table = Database::get_course_table(TABLE_TOOL_LIST);
$sql = "SELECT * FROM $table
WHERE category in ('authoring','interaction')
AND c_id = $courseId
AND session_id = $sessionId
ORDER BY id";
$result = Database::query($sql);
$data = Database::store_result($result, 'ASSOC');
return $data;
}
/**
* @param int $editIcon
* @return array
*/
public static function getTool($editIcon)
{
$course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
$editIcon = intval($editIcon);
$sql = "SELECT * FROM $course_tool_table
WHERE iid = $editIcon";
$result = Database::query($sql);
$tool = Database::fetch_assoc($result, 'ASSOC');
return $tool;
}
/**
* @return string
*/
public static function getCustomSysIconPath()
{
// Check if directory exists or create it if it doesn't
$dir = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/course_home_icons/';
if (!is_dir($dir)) {
mkdir($dir, api_get_permissions_for_new_directories(), true);
}
return $dir;
}
/**
* @return string
*/
public static function getCustomWebIconPath()
{
// Check if directory exists or create it if it doesn't
$dir = api_get_path(WEB_COURSE_PATH).api_get_course_path().'/upload/course_home_icons/';
return $dir;
}
/**
* @param string $icon
* @return string
*/
public static function getDisableIcon($icon)
{
$fileInfo = pathinfo($icon);
return $fileInfo['filename'].'_na.'.$fileInfo['extension'];
}
/**
* @param int $id
* @param int $courseId
* @param int $sessionId
* @param $values
*/
public static function updateTool($id, $values)
{
$table = Database::get_course_table(TABLE_TOOL_LIST);
$params = [
'name' => $values['name'],
'link' => $values['link'],
'target' => $values['target'],
'visibility' => $values['visibility'],
'description' => $values['description'],
];
if (isset($_FILES['icon']['size']) && $_FILES['icon']['size'] !== 0) {
$dir = self::getCustomSysIconPath();
// Resize image if it is larger than 64px
$temp = new Image($_FILES['icon']['tmp_name']);
$picture_infos = $temp->get_image_info();
if ($picture_infos['width'] > 64) {
$thumbwidth = 64;
} else {
$thumbwidth = $picture_infos['width'];
}
if ($picture_infos['height'] > 64) {
$new_height = 64;
} else {
$new_height = $picture_infos['height'];
}
$temp->resize($thumbwidth, $new_height, 0);
//copy the image to the course upload folder
$path = $dir.$_FILES['icon']['name'];
$result = $temp->send_image($path);
$temp = new Image($path);
$r = $temp->convert2bw();
$ext = pathinfo($path, PATHINFO_EXTENSION);
$bwPath = substr($path,0,-(strlen($ext)+1)) . '_na.' . $ext;
if ($r === false) {
error_log('Conversion to B&W of '.$path.' failed in '.__FILE__.' at line '.__LINE__);
} else {
$temp->send_image($bwPath);
$iconName = $_FILES['icon']['name'];
$params['custom_icon'] = $iconName;
}
}
Database::update(
$table,
$params,
[' iid = ?' => [$id]]
);
}
/**
* @param int $id
*/
public static function deleteIcon($id)
{
$table = Database::get_course_table(TABLE_TOOL_LIST);
$tool = self::getTool($id);
if ($tool && !empty($tool['custom_icon'])) {
$file = self::getCustomSysIconPath().$tool['custom_icon'];
$fileInfo = pathinfo($file);
$fileGray = $fileInfo['filename'].'_na.'.$fileInfo['extension'];
$fileGray = self::getCustomSysIconPath().$fileGray;
if (file_exists($file) && is_file($file)) {
if (Security::check_abs_path($file, self::getCustomSysIconPath())) {
unlink($file);
}
}
if (file_exists($fileGray) && is_file($fileGray)) {
if (Security::check_abs_path($fileGray, self::getCustomSysIconPath())) {
unlink($fileGray);
}
}
$params = [
'custom_icon' => '',
];
Database::update(
$table,
$params,
[' iid = ?' => [$id]]
);
}
}
}

@ -62,6 +62,11 @@ class Image
{
return $this->image_wrapper->get_image_info();
}
public function convert2bw()
{
$this->image_wrapper->convert2bw();
}
}
/**
@ -203,6 +208,7 @@ class ImagickWrapper extends ImageWrapper {
return $result;
}
}
}
/**
@ -347,4 +353,27 @@ class GDWrapper extends ImageWrapper {
// TODO: Occupied memory is not released, because the following fragment of code is actually dead.
@imagedestroy($this->bg);
}
/**
* Convert image to black & white
*/
function convert2bw()
{
if (!$this->image_validated) return false;
$dest_img = imagecreatetruecolor(imagesx($this->bg), imagesy($this->bg));
/* copy ignore the transparent color
* so that we can use black (0,0,0) as transparent, which is what
* the image is filled with when created.
*/
$transparent = imagecolorallocate($dest_img, 0,0,0);
imagealphablending($dest_img, false);
imagesavealpha($dest_img, true);
imagecolortransparent($dest_img, $transparent);
imagecopy($dest_img, $this->bg, 0,0, 0, 0,imagesx($this->bg), imagesx($this->bg));
imagefilter($dest_img, IMG_FILTER_GRAYSCALE);
$this->bg = $dest_img;
return true;
}
}

@ -0,0 +1,29 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Migrations\Schema\V110;
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
use Doctrine\DBAL\Schema\Schema;
/**
* Tool changes
*/
class Version20150610143426 extends AbstractMigrationChamilo
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
$this->addSql('ALTER TABLE c_tool ADD description LONGTEXT DEFAULT NULL, ADD custom_icon VARCHAR(255) DEFAULT NULL');
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
$this->addSql('ALTER TABLE c_tool DROP description, DROP custom_icon');
}
}

@ -106,6 +106,20 @@ class CTool
*/
private $sessionId;
/**
* @var string
*
* @ORM\Column(name="description", type="text", nullable=true)
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="custom_icon", type="string", length=255, nullable=true)
*/
private $customIcon;
/**
* Set name
*
@ -382,4 +396,42 @@ class CTool
{
return $this->cId;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
* @return CTool
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @return string
*/
public function getCustomIcon()
{
return $this->customIcon;
}
/**
* @param string $customIcon
* @return CTool
*/
public function setCustomIcon($customIcon)
{
$this->customIcon = $customIcon;
return $this;
}
}

Loading…
Cancel
Save