From d1648dedc4c5a63d4f3bdfdac28b5325055770bf Mon Sep 17 00:00:00 2001 From: aragonc Date: Fri, 18 Dec 2015 18:46:28 -0500 Subject: [PATCH 1/3] fix badges red social skill BT#7683 --- app/Resources/public/css/base.css | 7 +++++-- main/social/skills_ranking.php | 10 +++++----- main/template/default/social/skills_block.tpl | 9 +++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/Resources/public/css/base.css b/app/Resources/public/css/base.css index 8b49366f78..0aa1eea7fb 100644 --- a/app/Resources/public/css/base.css +++ b/app/Resources/public/css/base.css @@ -2643,7 +2643,9 @@ form .formw .freeze { table#skill_holder { margin-top: 15px; } - +.badges-siderbar{ + 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; diff --git a/main/social/skills_ranking.php b/main/social/skills_ranking.php index 5e8dcc4abb..60a17480c0 100755 --- a/main/social/skills_ranking.php +++ b/main/social/skills_ranking.php @@ -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', ), ); diff --git a/main/template/default/social/skills_block.tpl b/main/template/default/social/skills_block.tpl index 0c7abe196a..997fdc5ffc 100644 --- a/main/template/default/social/skills_block.tpl +++ b/main/template/default/social/skills_block.tpl @@ -26,9 +26,16 @@ +
{% if skills %} + +
    {% for skill in skills %}
  • @@ -41,6 +48,8 @@
  • {% endfor %}
+
+ {% else %}

{{ 'WithoutAchievedSkills'|get_lang }}

From fa39498e7c4d684a875f327055536fbeac5e67cd Mon Sep 17 00:00:00 2001 From: aragonc Date: Fri, 18 Dec 2015 19:01:42 -0500 Subject: [PATCH 2/3] fix badges red social skill BT#7683 --- app/Resources/public/css/base.css | 2 +- main/template/default/social/skills_block.tpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Resources/public/css/base.css b/app/Resources/public/css/base.css index 0aa1eea7fb..433e971a62 100644 --- a/app/Resources/public/css/base.css +++ b/app/Resources/public/css/base.css @@ -2643,7 +2643,7 @@ form .formw .freeze { table#skill_holder { margin-top: 15px; } -.badges-siderbar{ +.badges-sidebar{ height: 250px; } /* **************************************************** diff --git a/main/template/default/social/skills_block.tpl b/main/template/default/social/skills_block.tpl index 997fdc5ffc..7c66d61a83 100644 --- a/main/template/default/social/skills_block.tpl +++ b/main/template/default/social/skills_block.tpl @@ -35,7 +35,7 @@

{% if skills %} -
+
    {% for skill in skills %}
  • From 5ce8a6ecc75958c55e3a8099a0a69cd8a5e43017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Loguercio?= Date: Fri, 18 Dec 2015 19:29:44 -0500 Subject: [PATCH 3/3] Badge Baker Offline Feature - Refs #7978 --- main/badge/issued.php | 36 ++++++ main/inc/lib/baker.lib.php | 165 +++++++++++++++++++++++++ main/template/default/skill/issued.tpl | 11 +- 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 main/inc/lib/baker.lib.php diff --git a/main/badge/issued.php b/main/badge/issued.php index bc371ab2bd..abd32048ae 100644 --- a/main/badge/issued.php +++ b/main/badge/issued.php @@ -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[] = ''; } +$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); diff --git a/main/inc/lib/baker.lib.php b/main/inc/lib/baker.lib.php new file mode 100644 index 0000000000..920f8d32cd --- /dev/null +++ b/main/inc/lib/baker.lib.php @@ -0,0 +1,165 @@ +_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; + } + } +} \ No newline at end of file diff --git a/main/template/default/skill/issued.tpl b/main/template/default/skill/issued.tpl index b201c3804b..334085f546 100644 --- a/main/template/default/skill/issued.tpl +++ b/main/template/default/skill/issued.tpl @@ -19,7 +19,16 @@

    {% endfor %}
-
+
+ {% if badge_error %} +
{{ 'BakedBadgeProblem'|get_lang }}
+ {% else %} +

+ + {{ 'DownloadBadge'|get_lang }} + +

+ {% endif %} {% if allow_export %}