Merge branch '1.10.x' of github.com:chamilo/chamilo-lms into 1.10.x

1.10.x
Yannick Warnier 9 years ago
commit 2208ae4927
  1. 7
      app/Resources/public/css/base.css
  2. 36
      main/badge/issued.php
  3. 165
      main/inc/lib/baker.lib.php
  4. 10
      main/social/skills_ranking.php
  5. 11
      main/template/default/skill/issued.tpl
  6. 9
      main/template/default/social/skills_block.tpl

@ -2643,7 +2643,9 @@ form .formw .freeze {
table#skill_holder {
margin-top: 15px;
}
.badges-sidebar{
height: 250px;
}
/* ****************************************************
END SKILL
**************************************************** */
@ -4008,7 +4010,7 @@ i.size-32.icon-new-work{
margin-right: 15px;
padding: 0;
vertical-align: top;
width: 120px;
width: 95px;
}
#skillList .list-badges .thumbnail img{
margin-bottom: 4px;
@ -4016,6 +4018,7 @@ i.size-32.icon-new-work{
}
#skillList .list-badges .thumbnail .caption{
background: #D9EDF7;
font-size: 12px;
}
#skillList .list-badges .thumbnail .caption p{
margin-bottom: 0;

@ -6,6 +6,7 @@
* @package chamilo.badge
*/
require_once '../inc/global.inc.php';
require_once '../inc/lib/baker.lib.php';
$userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
$skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
@ -101,11 +102,46 @@ if ($allowExport) {
$htmlHeadXtra[] = '<script src="' . $backpack . 'issuer.js"></script>';
}
$objSkill = new Skill();
$skills = $objSkill->get($skillId);
$unbakedBadge = api_get_path(SYS_UPLOAD_PATH) . "badges/".$skills['icon'];
$unbakedBadge = file_get_contents($unbakedBadge);
$badgeInfoError = false;
$personalBadge = "";
$png = new PNGImageBaker($unbakedBadge);
if ($png->checkChunks("tEXt", "openbadges")) {
$bakedInfo = $png->addChunk("tEXt", "openbadges", $assertionUrl);
$bakedBadge = UserManager::getUserPathById($userId, "system");
$bakedBadge = $bakedBadge.'badges';
if (!file_exists($bakedBadge)) {
mkdir($bakedBadge, api_get_permissions_for_new_directories(), true);
}
$skillRelUserId = $userSkills[0]->getId();
if (!file_exists($bakedBadge . "/badge_" . $skillRelUserId)) {
file_put_contents($bakedBadge . "/badge_" . $skillRelUserId . ".png", $bakedInfo);
}
//Process to validate a baked badge
$badgeContent = file_get_contents($bakedBadge . "/badge_" . $skillRelUserId . ".png");
$verifyBakedBadge = $png->extractBadgeInfo($badgeContent);
if (!is_array($verifyBakedBadge)) {
$badgeInfoError = true;
}
if (!$badgeInfoError) {
$personalBadge = UserManager::getUserPathById($userId, "web");
$personalBadge = $personalBadge."badges/badge_" . $skillRelUserId . ".png";
}
}
$template = new Template('');
$template->assign('skill_info', $skillInfo);
$template->assign('user_info', $userInfo);
$template->assign('allow_export', $allowExport);
$template->assign('badge_error', $badgeInfoError);
$template->assign('personal_badge', $personalBadge);
if ($allowExport) {
$template->assign('assertions', $badgeAssertions);

@ -0,0 +1,165 @@
<?php
/**
* Php library to Bake the PNG Images
*
*/
class PNGImageBaker
{
private $_contents;
private $_size;
private $_chunks;
/**
* Prepares file for handling metadata.
* Verifies that this file is a valid PNG file.
* Unpacks file chunks and reads them into an array.
*
* @param string $contents File content as a string
*/
public function __construct($contents) {
$this->_contents = $contents;
$png_signature = pack("C8", 137, 80, 78, 71, 13, 10, 26, 10);
// Read 8 bytes of PNG header and verify.
$header = substr($this->_contents, 0, 8);
if ($header != $png_signature) {
echo 'This is not a valid PNG image';
}
$this->_size = strlen($this->_contents);
$this->_chunks = array();
// Skip 8 bytes of IHDR image header.
$position = 8;
do {
$chunk = @unpack('Nsize/a4type', substr($this->_contents, $position, 8));
$this->_chunks[$chunk['type']][] = substr($this->_contents, $position + 8, $chunk['size']);
// Skip 12 bytes chunk overhead.
$position += $chunk['size'] + 12;
} while ($position < $this->_size);
}
/**
* Checks if a key already exists in the chunk of said type.
* We need to avoid writing same keyword into file chunks.
*
* @param string $type Chunk type, like iTXt, tEXt, etc.
* @param string $check Keyword that needs to be checked.
*
* @return boolean (true|false) True if file is safe to write this keyword, false otherwise.
*/
public function checkChunks($type, $check) {
if (array_key_exists($type, $this->_chunks)) {
foreach (array_keys($this->_chunks[$type]) as $typekey) {
list($key, $data) = explode("\0", $this->_chunks[$type][$typekey]);
if (strcmp($key, $check) == 0) {
echo 'Key "' . $check . '" already exists in "' . $type . '" chunk.';
return false;
}
}
}
return true;
}
/**
* Add a chunk by type with given key and text
*
* @param string $chunkType Chunk type, like iTXt, tEXt, etc.
* @param string $key Keyword that needs to be added.
* @param string $value Currently an assertion URL that is added to an image metadata.
*
* @return string $result File content with a new chunk as a string.
*/
public function addChunk($chunkType, $key, $value) {
$chunkData = $key . "\0" . $value;
$crc = pack("N", crc32($chunkType . $chunkData));
$len = pack("N", strlen($chunkData));
$newChunk = $len . $chunkType . $chunkData . $crc;
$result = substr($this->_contents, 0, $this->_size - 12)
. $newChunk
. substr($this->_contents, $this->_size - 12, 12);
return $result;
}
/**
* removes a chunk by type with given key and text
*
* @param string $chunkType Chunk type, like iTXt, tEXt, etc.
* @param string $key Keyword that needs to be deleted.
* @param string $png the png image.
*
* @return string $result New File content.
*/
public function removeChunks($chunkType, $key, $png) {
// Read the magic bytes and verify
$retval = substr($png,0,8);
$ipos = 8;
if ($retval != "\x89PNG\x0d\x0a\x1a\x0a")
throw new Exception('Is not a valid PNG image');
// Loop through the chunks. Byte 0-3 is length, Byte 4-7 is type
$chunkHeader = substr($png,$ipos,8);
$ipos = $ipos + 8;
while ($chunkHeader) {
// Extract length and type from binary data
$chunk = @unpack('Nsize/a4type', $chunkHeader);
$skip = false;
if ( $chunk['type'] == $chunkType ) {
$data = substr($png,$ipos,$chunk['size']);
$sections = explode("\0", $data);
print_r($sections);
if ( $sections[0] == $key ) $skip = true;
}
// Extract the data and the CRC
$data = substr($png,$ipos,$chunk['size']+4);
$ipos = $ipos + $chunk['size'] + 4;
// Add in the header, data, and CRC
if ( ! $skip ) $retval = $retval . $chunkHeader . $data;
// Read next chunk header
$chunkHeader = substr($png,$ipos,8);
$ipos = $ipos + 8;
}
return $retval;
}
/**
* Extracts the baked PNG info by the Key
*
* @param string $png the png image
* @param string $key Keyword that needs to be searched.
*
* @return mixed - If there is an error - boolean false is returned
* If there is PNG information that matches the key an array is returned
*
*/
public function extractBadgeInfo($png, $key='openbadges') {
// Read the magic bytes and verify
$retval = substr($png,0,8);
$ipos = 8;
if ($retval != "\x89PNG\x0d\x0a\x1a\x0a") {
return false;
}
// Loop through the chunks. Byte 0-3 is length, Byte 4-7 is type
$chunkHeader = substr($png,$ipos,8);
$ipos = $ipos + 8;
while ($chunkHeader) {
// Extract length and type from binary data
$chunk = @unpack('Nsize/a4type', $chunkHeader);
$skip = false;
if ($chunk['type'] == 'tEXt') {
$data = substr($png,$ipos,$chunk['size']);
$sections = explode("\0", $data);
if ($sections[0] == $key) {
return $sections;
}
}
// Extract the data and the CRC
$data = substr($png,$ipos,$chunk['size']+4);
$ipos = $ipos + $chunk['size'] + 4;
// Read next chunk header
$chunkHeader = substr($png,$ipos,8);
$ipos = $ipos + 8;
}
}
}

@ -40,35 +40,35 @@ $column_model = array(
'name' => 'firstname',
'index' => 'firstname',
'width' => '70',
'align' => 'left',
'align' => 'center',
'sortable' => 'false',
),
array(
'name' => 'lastname',
'index' => 'lastname',
'width' => '70',
'align' => 'left',
'align' => 'center',
'sortable' => 'false',
),
array(
'name' => 'skills_acquired',
'index' => 'skills_acquired',
'width' => '30 ',
'align' => 'left',
'align' => 'center',
'sortable' => 'false',
),
array(
'name' => 'currently_learning',
'index' => 'currently_learning',
'width' => '30',
'align' => 'left',
'align' => 'center',
'sortable' => 'false',
),
array(
'name' => 'rank',
'index' => 'rank',
'width' => '30',
'align' => 'left',
'align' => 'center',
'sortable' => 'false',
),
);

@ -19,7 +19,16 @@
</p>
{% endfor %}
</div>
</div>
</div>
{% if badge_error %}
<div class="alert alert-danger"> {{ 'BakedBadgeProblem'|get_lang }}</div>
{% else %}
<p class="text-center">
<a href="{{ personal_badge }}" class="btn btn-primary" target="_new" download="badge">
<em class="fa fa-download fa-fw"></em> {{ 'DownloadBadge'|get_lang }}
</a>
</p>
{% endif %}
{% if allow_export %}
<p class="text-center">
<a href="#" class="btn btn-success" id="badge-export-button">

@ -26,9 +26,16 @@
</div>
</h4>
</div>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery('.scrollbar-inner').scrollbar();
});
</script>
<div id="skillList" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
{% if skills %}
<div class="scrollbar-inner badges-sidebar">
<ul class="list-unstyled list-badges">
{% for skill in skills %}
<li class="thumbnail">
@ -41,6 +48,8 @@
</li>
{% endfor %}
</ul>
</div>
{% else %}
<p>{{ 'WithoutAchievedSkills'|get_lang }}</p>
<p>

Loading…
Cancel
Save