Merge branch '1.10.x' into bootstrap

1.10.x
aragonc 10 years ago
commit 653a5ff3f7
  1. 20
      documentation/changelog.html
  2. 14
      main/admin/user_add.php
  3. 6
      main/course_home/course_home.php
  4. 2
      main/document/document.php
  5. 5
      main/exercice/exercise_result.php
  6. 5
      main/exercice/exercise_show.php
  7. 5
      main/exercice/result.php
  8. BIN
      main/img/play-circle-8x.png
  9. 8
      main/inc/ajax/message.ajax.php
  10. 6
      main/inc/lib/display.lib.php
  11. 42
      main/inc/lib/fixlinks.js
  12. 27
      main/inc/lib/formvalidator/Element/SelectAjax.php
  13. 2
      main/inc/lib/plugin.class.php
  14. 10
      main/inc/lib/social.lib.php
  15. 9
      main/inc/lib/template.lib.php
  16. 14
      main/inc/lib/usermanager.lib.php
  17. 2
      main/install/configuration.dist.php
  18. 1
      main/lang/english/trad4all.inc.php
  19. 8
      main/lang/french/trad4all.inc.php
  20. 1
      main/lang/spanish/trad4all.inc.php
  21. 54
      main/messages/new_message.php
  22. 28
      main/newscorm/embed.php
  23. 6
      main/newscorm/learnpath.class.php
  24. 17
      main/newscorm/lp_view.php
  25. 51
      main/newscorm/scorm_api.php
  26. 4
      main/survey/survey.lib.php
  27. 22
      main/template/default/chat/video.tpl
  28. 2
      main/template/default/learnpath/list.tpl
  29. 33
      main/template/default/learnpath/view.tpl
  30. 4
      main/template/default/social/home.tpl
  31. 4
      main/template/default/social/profile.tpl
  32. 5
      main/template/default/social/user_block.tpl
  33. 5
      main/work/work.lib.php
  34. 2
      main/work/work_list_all.php
  35. 2
      plugin/buycourses/CHANGELOG.md
  36. 26
      plugin/buycourses/database.php
  37. 36
      plugin/buycourses/js/buycourses.js
  38. 6
      plugin/buycourses/lang/english.php
  39. 8
      plugin/buycourses/lang/french.php
  40. 6
      plugin/buycourses/lang/spanish.php
  41. 356
      plugin/buycourses/src/buy_course_plugin.class.php
  42. 2
      plugin/buycourses/src/configuration.php
  43. 220
      plugin/buycourses/src/configure_course.php
  44. 85
      plugin/buycourses/src/function.php
  45. 1
      plugin/buycourses/src/index.buycourses.php
  46. 45
      plugin/buycourses/src/sales_report.php
  47. 8
      plugin/buycourses/view/catalog.tpl
  48. 52
      plugin/buycourses/view/configuration.tpl
  49. 135
      plugin/buycourses/view/index.tpl
  50. 44
      plugin/buycourses/view/sales_report.tpl
  51. 7
      tests/features/courseTools.feature
  52. 2
      tests/features/createUser.feature
  53. 139
      tests/scripts/delete_old_tasks.php

@ -1068,6 +1068,8 @@ All security issues are published and patches are attached on <a href="https://s
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d64a02c156c7adf3983807be860a7848311dbfb3">d64a02c1</a> - <a href="https://support.chamilo.org/issues/7272">#7272</a>) Fix SQL injection threats and replace SESSION variable with api_get_user_id</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/587961662a8f9d035e52f14cd0aa4fee3aee68d8">58796166</a> - <a href="https://support.chamilo.org/issues/7275">#7275</a>) Add security token to course copy tool</li>
<li>(<a href="https://support.chamilo.org/issues/7440">#7440</a>) Fix a series of SQL injection vulnerabilities due to integer filtering</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1307b662d2b5ba011b98518caa91e6714d8e3367">1307b662</a> - <a href="https://task.beeznest.com/issues/10295">BT#10295</a>) Remove XSS when add/edit career</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1b320e57725135eb8c8eff9a8367de90addd0ece">1b320e57</a> - <a href="https://task.beeznest.com/issues/10298">BT#10298</a>) Avoid XSS when event is created on agenda</li>
</ul>
<h3>Possibly breaking changes</h3>
@ -1131,6 +1133,24 @@ All security issues are published and patches are attached on <a href="https://s
<h3>Improvements (minor features) and debug</h3>
<ul>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e406e2ee8cfb597951ccac4f1ec2b77875b1f77d">e406e2ee</a> - <a href="https://support.chamilo.org/issues/7768">#7768</a>) Fix install process to avoid re-install plugin</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/edf83bdc0d778d347dcf3e37425369eaaecb1335">edf83bdc</a> - <a href="https://support.chamilo.org/issues/7768">#7768</a>) Add filter by user on sales report</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fa29e02ac31a3461ed002e32ec04b650b0ba1479">fa29e02a</a> - <a href="https://support.chamilo.org/issues/7841">#7841</a>) Remove chat button from elfinder popup file selector for 1.10.x</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/90e2852223d5aad04802f282b7919379084ec624">90e28522</a>) If chamilo exercise added in LP has pass % then change status to passed/failed</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fa9b35e8d0a0c2b3aa40a3447dc8e24c33c379dd">fa9b35e8</a> - <a href="https://support.chamilo.org/issues/7558">#7558</a>) Show messages for status from video chat connection</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4c9a8d4a65ff1331d7a21714678969f07b0f957c">4c9a8d4a</a>) Update FontAwesome version</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d357cb23264f02fc73d532cdd96cba68fabfd52a">d357cb23</a> - <a href="https://support.chamilo.org/issues/7181">#7181</a>) Added new lib to upgrade to webcamJS from JPEGCam</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b91733cc167c69e09bfd49c63308e338fa8fa41d">b91733cc</a> - <a href="https://support.chamilo.org/issues/7835">#7835</a>) Avoid blocked icons by ad blockers</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0829fd8804aed5dd612d4dcfef32ec339f7ded3b">0829fd88</a>) Move constant in api.lib.php</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d1aa7a96feef449f8e4811f674e35c107c306420">d1aa7a96</a> - <a href="https://support.chamilo.org/issues/279">#279</a>) Added new lib for vCard Exports</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ed50ffd65266b047ad193a5b887ad11f44c8bfa5">ed50ffd6</a> - <a href="https://task.beeznest.com/issues/10311">BT#10311</a>) add jquery.timelinr and img</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/249f7c9cd3a7343a68e1c6f54434a6c0610c1703">249f7c9c</a> - <a href="https://task.beeznest.com/issues/10311">BT#10311</a>) fix timeline panel</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a20b8fc767010b5593a43d93df49d48afc406bb2">a20b8fc7</a> - <a href="https://task.beeznest.com/issues/10281">BT#10281</a>) Apply format to session dates on session list</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fdb647460c957d6f69fbcc362e645b2bff9627ab">fdb64746</a> - <a href="https://task.beeznest.com/issues/10308">BT#10308</a>) Improve send message on social network</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f2a03393774e8dd02f1d33acc69022f3cd6fb133">f2a03393</a> - <a href="https://support.chamilo.org/issues/7558">#7558</a>) Add method to get a HTML code for a icon by Font Awesome</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e94602ec57b374c05e4acc78142889fbea36fdb3">e94602ec</a> - <a href="https://support.chamilo.org/issues/7837">#7837</a>) Replace old code with api_get_user_info</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4e0fb4a3087664a5431c481035af83c00371e781">4e0fb4a3</a> - <a href="https://task.beeznest.com/issues/10217">BT#10217</a>) Replace http with https</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/57f99efbdc9224512a242096482998bef0df4cf7">57f99efb</a> - <a href="https://task.beeznest.com/issues/10253">BT#10253</a>) Add dropbox_hide_general_coach setting</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/110060be24244a8f8cfb9837bf9500aaddf2bc3a">110060be</a> - <a href="https://support.chamilo.org/issues/7462">#7462</a>) Fix pages blocked due to course restriction</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/299ba994390549c0193348c498760e727236609c">299ba994</a> - <a href="https://support.chamilo.org/issues/7477">#7477</a>) Restore admin view in reports (was lost in 1.9.8)</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7f55f83751bd8d0e641afb85f05093f5e42c8bd6">7f55f837</a>) Rename the custompages php files in order to avoid overwrites</li>

@ -25,8 +25,8 @@ if ($checkPass == 'true') {
$htmlHeadXtra[] = '
<script>
$(document).ready(function() {
$("input[name=\'password[password_auto]\']").each(function(index, value) {
$(this).click(function() {
$("#password").keypress(function() {
$("#password").each(function(index, value) {
var value = $(this).attr("value");
if (value == 0) {
$("#password_progress").show();
@ -176,7 +176,13 @@ if (isset($extAuthSource) && count($extAuthSource) > 0) {
}
}
$group[] = $form->createElement('radio', 'password_auto', get_lang('Password'), get_lang('AutoGeneratePassword').'<br />', 1);
$group[] = $form->createElement(
'radio',
'password_auto',
get_lang('Password'),
get_lang('AutoGeneratePassword').'<br />',
1
);
$group[] = $form->createElement(
'radio',
'password_auto',
@ -197,7 +203,7 @@ $group[] = $form->createElement(
);
$form->addGroup($group, 'password', get_lang('Password'), '');
$form->addGroupRule('password', get_lang('EnterPassword'), 'required', null, 2);
$form->addGroupRule('password', get_lang('EnterPassword'), 'required', null, 1);
if ($checkPass) {
$passwordStrengthLabels = '

@ -172,7 +172,11 @@ if (isset($_GET['action']) && $_GET['action'] == 'subscribe') {
$auth = new Auth();
$msg = $auth->subscribe_user($course_code);
if (!empty($msg)) {
$show_message .= Display::return_message(get_lang($msg));
$show_message .= Display::return_message(
get_lang($msg['message']),
'info',
false
);
}
}
}

@ -352,7 +352,7 @@ switch ($action) {
);
}
$parent_id = $document_info['parent_id'];
$my_path = UserManager::getUserPathById(api_get_user_id());
$my_path = UserManager::getUserPathById(api_get_user_id(), 'system');
$user_folder = $my_path.'my_files/';
$my_path = null;

@ -79,6 +79,11 @@ if ($origin != 'learnpath') {
// So we are not in learnpath tool
Display::display_header($nameTools, get_lang('Exercise'));
} else {
$htmlHeadXtra[] = "
<style>
body { background: none;}
</style>
";
Display::display_reduced_header();
}

@ -123,6 +123,11 @@ $this_section = SECTION_COURSES;
if ($origin != 'learnpath') {
Display::display_header('');
} else {
$htmlHeadXtra[] = "
<style>
body { background: none;}
</style>
";
Display::display_reduced_header();
}
?>

@ -62,6 +62,11 @@ if ($show_headers) {
$this_section = SECTION_COURSES;
Display::display_header();
} else {
$htmlHeadXtra[] = "
<style>
body { background: none;}
</style>
";
Display::display_reduced_header();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

@ -41,7 +41,7 @@ switch ($action) {
$tbl_my_user_friend = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
$tbl_user = Database::get_main_table(TABLE_MAIN_USER);
$tbl_access_url_rel_user = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
$search = Database::escape_string($_REQUEST['tag']);
$search = Database::escape_string($_REQUEST['q']);
$access_url_id = api_get_multiple_access_url() == 'true' ? api_get_current_access_url_id() : 1;
$user_id = api_get_user_id();
@ -128,9 +128,9 @@ switch ($action) {
if ($showEmail == 'true') {
$name .= ' ('.$row['email'].')';
}
$return[] = array(
'caption' => $name,
'value' => $row['id']
$return['items'][] = array(
'text' => $name,
'id' => $row['id']
);
}
}

@ -2151,14 +2151,14 @@ class Display
$html .= '<div id="' . $id . '" class="actions">';
$html .= '<div class="row">';
if ($col > 4) {
$html = '<div class="alert alert-warning" role="alert">Not exceeding four columns</div>';
$html = '<div class="alert alert-warning" role="alert">Action toolbar design does not work when exceeding four columns - check Display::toolbarAction()</div>';
} else {
for ( $i = 0; $i < $col; $i++ ) {
$html .= '<div class="col-md-' . $columns . '">';
if ( $col == 2 && $i == 1 ) {
if($right === true){
if ($right === true) {
$html .= '<div class="pull-right">';
$html .= $content[$i];
$html .= (isset($content[$i])?$content[$i]:'');
$html .= '</div>';
} else {
$html .= $content[$i];

@ -0,0 +1,42 @@
$(document).ready(function() {
var objects = $(document).find('object');
var pathname = location.pathname;
var coursePath = pathname.substr(0, pathname.indexOf('/courses/'));
var url = "http://"+location.host + coursePath+"/courses/proxy.php?";
objects.each(function (value, obj) {
var dialogId = this.id +'_dialog';
var openerId = this.id +'_opener';
var link = '<a id="'+openerId+'" href="#">If video does not work, try clicking here.</a>';
var embed = $("#"+this.id).find('embed').first();
var height = embed.attr('height');
var width = embed.attr('width');
var src = embed.attr('src').replace('https', 'http');
var completeUrl = url + 'width='+embed.attr('width')+
'&height='+height+
'&id='+this.id+
'&flashvars='+encodeURIComponent(embed.attr('flashvars'))+
'&src='+src+
'&width='+width;
/*var iframe = '<iframe ' +
'style="border: 0px;" width="100%" height="100%" ' +
'src="'+completeUrl+
'">' +
'</iframe>';
var content = '<div id="'+dialogId+'">' + iframe+'</div>';*/
var result = $("#"+this.id).find('#'+openerId);
if (result.length == 0) {
$("#" + this.id).append('<br />' + link);
$('#' + openerId).click(function () {
var window = window.open(completeUrl, "Video", "width=" + width + ", " + "height=" + height + "");
window.document.title = 'Video';
});
}
});
});

@ -62,10 +62,17 @@ class SelectAjax extends HTML_QuickForm_select
$plHolder = get_lang('SelectAnOption');
}
$id = $this->getAttribute('id');
if (empty($id)) {
$id = $this->getAttribute('name');
$this->setAttribute('id', $id);
}
$html .= <<<JS
<script>
$(function(){
$('#{$this->getAttribute('name')}').select2({
$('#{$this->getAttribute('id')}').select2({
$languageCondition
placeholder: '$plHolder',
allowClear: true,
@ -93,14 +100,22 @@ class SelectAjax extends HTML_QuickForm_select
</script>
JS;
$this->removeAttribute('class');
$this->removeAttribute('url');
$this->setAttribute('style', 'width: 100%;');
$attrs = $this->getAttributes();
$selectName = $this->getAttribute('name');
if ($this->getAttribute('multiple')) {
$selectName = "{$this->getAttribute('name')}[]";
}
$html .= Display::select(
$this->getAttribute('name'),
$selectName,
$defaultValues,
array_keys($defaultValues),
[
'id' => $this->getAttribute('name'),
'style' => 'width: 100%;'
],
$attrs,
false
);
return $html;

@ -321,7 +321,7 @@ class Plugin
$interfaceLanguageId = api_get_language_id($language_interface);
$interfaceLanguageInfo = api_get_language_info($interfaceLanguageId);
$languageParentId = intval($interfaceLanguageInfo['parent_id']);
$languageParentId = (!empty($interfaceLanguageInfo['parent_id'])?intval($interfaceLanguageInfo['parent_id']):0);
//1. Loading english if exists
$english_path = $root.$plugin_name."/lang/english.php";

@ -1808,7 +1808,7 @@ class SocialManager extends UserManager
if ($number_friends != 0) {
$friendHtml.= '<ul class="list-group">';
$friendHtml.= '<div class="list-group">';
$j = 1;
for ($k=0; $k < $number_friends; $k++) {
if ($j > $number_of_images) break;
@ -1826,7 +1826,6 @@ class SocialManager extends UserManager
$status=0;
}
$friendHtml.= '<li class="list-group-item">';
$friendAvatarMedium = UserManager::getUserPicture($friend['friend_user_id'], USER_IMAGE_SIZE_MEDIUM);
$friendAvatarSmall = UserManager::getUserPicture($friend['friend_user_id'], USER_IMAGE_SIZE_SMALL);
$friend_avatar = '<img src="'.$friendAvatarMedium.'" id="imgfriend_'.$friend['friend_user_id'].'" title="'.$name_user.'" class="user-image"/>';
@ -1834,21 +1833,20 @@ class SocialManager extends UserManager
$friend['friend_user_id'] != api_get_user_id();
if ($showLinkToChat){
$friendHtml .= '<a onclick="javascript:chatWith(\''.$friend['friend_user_id'].'\', \''.$name_user.'\', \''.$status.'\',\''.$friendAvatarSmall.'\')" href="javascript:void(0);">';
$friendHtml .= '<a onclick="javascript:chatWith(\''.$friend['friend_user_id'].'\', \''.$name_user.'\', \''.$status.'\',\''.$friendAvatarSmall.'\')" href="javascript:void(0);" class="list-group-item">';
$friendHtml .= $friend_avatar.' <span class="username">' . $name_user . '</span>';
$friendHtml .= '<span class="status">' . $statusIcon . '</span>';
} else {
$link_shared = (empty($link_shared)) ? '' : '&'.$link_shared;
$friendHtml .= '<a href="profile.php?' .'u=' . $friend['friend_user_id'] . $link_shared . '">';
$friendHtml .= '<a href="profile.php?' .'u=' . $friend['friend_user_id'] . $link_shared . '" class="list-group-item">';
$friendHtml .= $friend_avatar.' <span class="username-all">' . $name_user . '</span>';
}
$friendHtml .= '</a>';
$friendHtml.= '</li>';
}
$j++;
}
$friendHtml.='</ul>';
$friendHtml.='</div>';
} else {
$friendHtml.= '<div class="help">'.get_lang('NoFriendsInYourContactList').' '
.'<a href="'.api_get_path(WEB_PATH).'whoisonline.php"><i class="fa fa-search"></i> '. get_lang('TryAndFindSomeFriends').'</a></div>';

@ -617,11 +617,16 @@ class Template
$isoCode = api_get_language_isocode();
//JS files
$selectLink = 'bootstrap-select/js/i18n/defaults-' . $isoCode . '_' . strtoupper($isoCode) . '.min.js';
if ($isoCode == 'en') {
$selectLink = 'bootstrap-select/js/i18n/defaults-' . $isoCode . '_US.min.js';
}
// JS files
$js_files = array(
'chosen/chosen.jquery.min.js',
'bootstrap-select/js/bootstrap-select.min.js',
'bootstrap-select/js/i18n/defaults-' . $isoCode . '_' . strtoupper($isoCode) . '.min.js'
$selectLink
);
$viewBySession = api_get_setting('my_courses_view_by_session') === 'true';

@ -259,7 +259,9 @@ class UserManager
$num = self::get_number_of_users();
if ($num >= $_configuration[$access_url_id]['hosting_limit_users']) {
api_warn_hosting_contact('hosting_limit_users');
return api_set_failure('portal users limit reached');
Display::addFlash(Display::return_message(get_lang('PortalUsersLimitReached'), 'warning'));
return false;
}
}
@ -270,13 +272,17 @@ class UserManager
) {
$num = self::get_number_of_users(1);
if ($num >= $_configuration[$access_url_id]['hosting_limit_teachers']) {
Display::addFlash(Display::return_message(get_lang('PortalTeachersLimitReached'), 'warning'));
api_warn_hosting_contact('hosting_limit_teachers');
return api_set_failure('portal teachers limit reached');
return false;
}
}
if (empty($password)) {
return api_set_failure('ThisFieldIsRequired');
Display::addFlash(Display::return_message(get_lang('ThisFieldIsRequired').': '.get_lang('Password') , 'warning'));
return false;
}
// database table definition
@ -575,7 +581,7 @@ class UserManager
a user has 4 different sized photos to be deleted. */
$user_info = api_get_user_info($user_id);
if (strlen($user_info['picture_uri']) > 0) {
$path = self::getUserPathById($user_id);
$path = self::getUserPathById($user_id, 'system');
$img_path = $path.$user_info['picture_uri'];
if (file_exists($img_path))
unlink($img_path);

@ -224,3 +224,5 @@ $_configuration['system_stable'] = NEW_VERSION_STABLE;
// 0 = No link (not clickable)
// 2 = Link to the course if there is only one course
//$_configuration['courses_list_session_title_link'] = 1;
// Fix embedded videos inside lps, adding an optional popup
//$_configuration['lp_fix_embed_content'] = false;

@ -7528,4 +7528,5 @@ $ConnectionFailed = "Connection failed";
$ConnectionClosed = "Connection closed";
$LocalConnectionFailed = "Local connection failed";
$RemoteConnectionFailed = "Remote connection failed";
$ViewStudents = "View students";
?>

@ -7508,4 +7508,12 @@ $CourseCategory = "Catégorie de cours";
$VideoChatBetweenUserXAndUserY = "Appel vidéo entre %s et %s";
$Enable = "Activer";
$Disable = "Désactiver";
$AvoidChangingPageAsThisWillCutYourCurrentVideoChatSession = "Évitez de changer de page durant la conférence pour éviter de couper la communication (vous pouvez toutefois ouvrir de nouveaux onglets).";
$ConnectingToPeer = "En cours de connexion...";
$ConnectionEstablished = "Connexion établie";
$ConnectionFailed = "Connexion échouée";
$ConnectionClosed = "Connexion terminée";
$LocalConnectionFailed = "Échec de la connexion locale";
$RemoteConnectionFailed = "Échec de la connexion distante";
$ViewStudents = "Voir apprenants";
?>

@ -7553,4 +7553,5 @@ $ConnectionFailed = "Conexión fallida";
$ConnectionClosed = "Conexión cerrada";
$LocalConnectionFailed = "Conexión local fallida";
$RemoteConnectionFailed = "Conexión remota fallida";
$ViewStudents = "Ver estudiantes";
?>

@ -38,49 +38,6 @@ function validate(form, list) {
</script>';
$htmlHeadXtra[] = '<script>
$(document).ready(function () {
$("#users").fcbkcomplete({
json_url: "'.api_get_path(WEB_AJAX_PATH).'message.ajax.php?a=find_users",
cache: false,
filter_case: false,
filter_hide: true,
complete_text:"'.get_lang('StartToType').'",
firstselected: true,
//onremove: "testme",
onselect:"check_users",
filter_selected: true,
newel: true
});
});
function check_users() {
//selecting only selected users
$("#users option:selected").each(function() {
var user_id = $(this).val();
if (user_id != "" ) {
$.ajax({
url: "'.api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=user_id_exists",
data: "user_id="+user_id,
success: function(return_value) {
if (return_value == 0 ) {
alert("'.get_lang('UserDoesNotExist').'");
//Deleting select option tag
$("#users option[value="+user_id+"]").remove();
//Deleting holder
$(".holder li").each(function () {
if ($(this).attr("rel") == user_id) {
$(this).remove();
}
});
}
}
});
}
});
}
var counter_image = 1;
/*
function remove_image_form(id_elem1) {
@ -179,7 +136,16 @@ function manage_form($default, $select_from_user_list = null, $sent_to = null)
}
if (empty($default['users'])) {
//fb select
$form->addElement('select', 'users', get_lang('SendMessageTo'), array(), array('id' => 'users'));
$form->addElement(
'select_ajax',
'users',
get_lang('SendMessageTo'),
array(),
[
'multiple' => 'multiple',
'url' => api_get_path(WEB_AJAX_PATH) . 'message.ajax.php?a=find_users'
]
);
} else {
$form->addElement('hidden','hidden_user',$default['users'][0],array('id'=>'hidden_user'));
}

@ -24,17 +24,21 @@ switch ($type) {
$iframe .= '</div>';
break;
case 'nonhttps':
$iframe = '<a href="' . $src . '" target="_blank" style="font-family: arial; color: #666;">' . $src . '</a>';
$icon = '&nbsp;<i class="icon-external-link icon-2x"></i>';
$iframe = Display::return_message(
Display::url($src.$icon, $src, ['class' => 'btn', 'target' => '_blank']),
'normal',
false
);
break;
}
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<?php echo $iframe; ?>
</body>
</html>
$htmlHeadXtra[] = "
<style>
body { background: none;}
</style>
";
Display::display_reduced_header();
echo $iframe;
Display::display_footer();

@ -3356,10 +3356,10 @@ class learnpath
if ($lp_item_type == 'link') {
if (Link::is_youtube_link($file)) {
$src = Link::get_youtube_video_id($file);
$file = 'embed.php?type=youtube&source='.$src;
$file = api_get_path(WEB_CODE_PATH).'newscorm/embed.php?type=youtube&source='.$src;
} elseif (Link::isVimeoLink($file)) {
$src = Link::getVimeoLinkId($file);
$file = 'embed.php?type=vimeo&source='.$src;
$file = api_get_path(WEB_CODE_PATH).'newscorm/embed.php?type=vimeo&source='.$src;
} else {
// If the current site is HTTPS and the link is
// HTTP, browsers will refuse opening the link
@ -3370,7 +3370,7 @@ class learnpath
$linkProtocol = substr($file, 0, 5);
if ($linkProtocol === 'http:') {
//this is the special intervention case
$file = 'embed.php?type=nonhttps&source=' . urlencode($file);
$file = api_get_path(WEB_CODE_PATH).'newscorm/embed.php?type=nonhttps&source=' . urlencode($file);
}
}
}

@ -78,8 +78,13 @@ $user_id = api_get_user_id();
$platform_theme = api_get_setting('stylesheets'); // Platform's css.
$my_style = $platform_theme;
$htmlHeadXtra[] = '<script src="' . api_get_path(WEB_LIBRARY_PATH) .
'javascript/jquery.lp_minipanel.js" type="text/javascript" language="javascript"></script>';
$htmlHeadXtra[] = '<script type="text/javascript">
<!--
var jQueryFrameReadyConfigPath = \''.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.min.js\';
-->
</script>';
$htmlHeadXtra[] = '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.frameready.js"></script>';
$htmlHeadXtra[] = '<script src="' . api_get_path(WEB_LIBRARY_PATH) .'javascript/jquery.lp_minipanel.js" type="text/javascript" language="javascript"></script>';
$htmlHeadXtra[] = '<script>
$(document).ready(function() {
$("div#log_content_cleaner").bind("click", function() {
@ -429,6 +434,14 @@ $gamificationMode = api_get_setting('gamification_mode');
$template = new Template('title', false, false, true, true, false);
$template->assign('glossary_extra_tools', api_get_setting('show_glossary_in_extra_tools'));
$fixLinkSetting = api_get_configuration_value('lp_fix_embed_content');
$fixLink = '';
if ($fixLinkSetting) {
$fixLink = '{type:"script", id:"_fr10", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/fixlinks.js"}';
}
$template->assign('fix_link', $fixLink);
$template->assign(
'glossary_tool_availables',
['true', 'lp', 'exercise_and_lp']

@ -338,6 +338,7 @@ function LMSInitialize() {
<?php
$glossaryExtraTools = api_get_setting('show_glossary_in_extra_tools');
$fixLinkSetting = api_get_configuration_value('lp_fix_embed_content');
$showGlossary = in_array($glossaryExtraTools, array('true', 'lp', 'exercise_and_lp'));
if ($showGlossary) {
if (api_get_setting('show_glossary_in_documents') == 'ismanual') {
@ -351,6 +352,10 @@ function LMSInitialize() {
attach_glossary_into_scorm('automatic');
<?php } ?>
<?php } ?>
<?php if ($fixLinkSetting) { ?>
attach_glossary_into_scorm('fix_links');
<?php } ?>
return('true');
}
}
@ -2079,7 +2084,7 @@ function attach_glossary_into_scorm(type) {
}
});
} else {
if ('manual') {
if (type == 'manual') {
$("iframe").contents().find("body").on("click", ".glossary", function() {
is_glossary_name = $(this).html();
@ -2124,5 +2129,49 @@ function attach_glossary_into_scorm(type) {
});
});
}
if (type == 'fix_links') {
$(document).ready(function() {
var objects = $("iframe").contents().find('object');
var pathname = location.pathname;
var coursePath = pathname.substr(0, pathname.indexOf('/main/'));
var url = "http://"+location.host + coursePath+"/courses/proxy.php?";
objects.each(function (value, obj) {
var dialogId = this.id +'_dialog';
var openerId = this.id +'_opener';
var link = '<a id="'+openerId+'" href="#" class="btn">'+
'<div style="text-align: center"><img src="<?php echo api_get_path(WEB_CODE_PATH).'img/play-circle-8x.png'; ?>"/><br />If video does not work, try clicking here.</div></a>';
var embed = $("iframe").contents().find("#"+this.id).find('embed').first();
var height = embed.attr('height');
var width = embed.attr('width');
var src = embed.attr('src').replace('https', 'http');
var completeUrl = url + 'width='+embed.attr('width')+
'&height='+height+
'&id='+this.id+
'&flashvars='+encodeURIComponent(embed.attr('flashvars'))+
'&src='+src+
'&width='+width;
var iframe = '<iframe ' +
'style="border: 0px;" width="100%" height="100%" ' +
'src="'+completeUrl+
'">' +
'</iframe>';
$("iframe").contents().find("#"+this.id).append('<br />' + link);
$("iframe").contents().find('#' + openerId).click(function() {
var w = window.open(completeUrl, "Video", "width="+width+", "+"height="+height+"");
w = window.document.title = 'Video';
});
});
});
}
}
}

@ -503,7 +503,9 @@ class SurveyManager
} else {
// Delete everything of the gradebook for this $linkId
GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id);
exit;
//comenting this line to correctly return the function msg
//exit;
}
return $return;

@ -9,7 +9,15 @@
</p>
</div>
<div class="row">
<div class="col-md-4">
<div class="col-md-8 col-sm-7">
<div class="thumbnail video-chat-user">
<div id="chat-remote-video"></div>
<div class="caption">
<p class="text-muted text-center">{{ "ChatWithXUser"|get_lang|format(chat_user.complete_name) }}</p>
</div>
</div>
</div>
<div class="col-md-4 col-sm-5">
<div class="thumbnail">
<div id="chat-local-video"></div>
<div class="caption">
@ -28,22 +36,12 @@
</h4>
</div>
<div id="listFriends" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
{{ block_friends }}
</div>
{{ block_friends }}
</div>
</div>
</div>
</div>
</div>
<div class="col-md-8">
<div class="thumbnail video-chat-user">
<div id="chat-remote-video"></div>
<div class="caption">
<p class="text-muted text-center">{{ "ChatWithXUser"|get_lang|format(chat_user.complete_name) }}</p>
</div>
</div>
</div>
</div>
</div>
<script>

@ -1,6 +1,6 @@
<script>
function confirmation(name) {
if (confirm(" {{ "AreYouSureToDelete"|get_lang }} name ?")) {
if (confirm("{{ "AreYouSureToDelete"|get_lang }} \"" + name + "\" ?")) {
return true;
} else {
return false;

@ -54,7 +54,7 @@
{% if lp_author == '' %}
<div class="col-md-12">
{{ lp_preview_image }}
</div>
</div>
{% else %}
<div class="col-md-4">
{{ lp_preview_image }}
@ -63,7 +63,7 @@
<div class="description-autor"> {{ lp_author }} </div>
</div>
{% endif %}
</div>
</div>
<div id="progress_bar">
@ -151,7 +151,8 @@
{ type:"script", id:"_fr1", src:"{{ jquery_web_path }}"},
{ type:"script", id:"_fr4", src:"{{ jquery_ui_js_web_path }}"},
{ type:"stylesheet", id:"_fr5", src:"{{ jquery_ui_css_web_path }}"},
{ type:"script", id:"_fr2", src:"{{ _p.web_lib }}javascript/jquery.highlight.js"}
{ type:"script", id:"_fr2", src:"{{ _p.web_lib }}javascript/jquery.highlight.js"},
{{ fix_link }}
]
}
);
@ -166,14 +167,30 @@
{ type:"script", id:"_fr1", src:"{{ jquery_web_path }}"},
{ type:"script", id:"_fr4", src:"{{ jquery_ui_js_web_path }}"},
{ type:"stylesheet", id:"_fr5", src:"{{ jquery_ui_css_web_path }}"},
{ type:"script", id:"_fr2", src:"{{ _p.web_lib }}javascript/jquery.highlight.js"}
{ type:"script", id:"_fr2", src:"{{ _p.web_lib }}javascript/jquery.highlight.js"},
{{ fix_link }}
]
}
);
{% elseif fix_link != '' %}
$.frameReady(
function(){
// $("<div>I am a div courses</div>").prependTo("body");
},
"top.content_name",
{
load: [
{ type:"script", id:"_fr1", src:"{{ jquery_web_path }}"},
{ type:"script", id:"_fr4", src:"{{ jquery_ui_js_web_path }}"},
{ type:"stylesheet", id:"_fr5", src:"{{ jquery_ui_css_web_path }}"},
{{ fix_link }}
]
}
);
{% endif %}
{% endif %}
};
$(document).ready(function() {
updateContentHeight();
@ -184,11 +201,8 @@
$(window).resize(function() {
updateContentHeight();
});
});
window.onload = updateContentHeight();
window.onresize = updateContentHeight();
@ -210,5 +224,4 @@
});
});
});
</script>

@ -31,9 +31,7 @@
</h4>
</div>
<div id="listFriends" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
{{ social_friend_block }}
</div>
{{ social_friend_block }}
</div>
</div>
</div>

@ -26,9 +26,7 @@
</h4>
</div>
<div id="listFriends" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
{{ social_friend_block }}
</div>
{{ social_friend_block }}
</div>
</div>
</div>

@ -19,7 +19,10 @@
</li>
{% if chat_enabled == 1 %}
<li>
{% if user.user_is_online_in_chat != 0 %}
{% if user.id == _u.id %}
<img src="{{ "online.png" | icon }}" alt="{{ "Online" | get_lang }}">
{{ "Chat" | get_lang }} ({{ "Online" | get_lang }})
{% elseif user.user_is_online_in_chat != 0 %}
<a onclick="javascript:chatWith('{{ user.id }}', '{{ user.complete_name }}', '{{ user.user_is_online }}','{{ user.avatar_small }}')" href="javascript:void(0);">
<img src="{{ "online.png" | icon }}" alt="{{ "Online" | get_lang }}">
{{ "Chat" | get_lang }} ({{ "Online" | get_lang }})

@ -49,7 +49,7 @@ function display_action_links($id, $cur_dir_path, $action)
$display_output .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=settings&origin='.$origin.'&gradebook='.$gradebook.'">';
$display_output .= Display::return_icon('settings.png', get_lang('EditToolOptions'),'',ICON_SIZE_MEDIUM).'</a>';
}
$display_output .= '<a id="open-view-list" href="#">' . Display::return_icon('listwork.png', get_lang('viewStudents'),'',ICON_SIZE_MEDIUM) . '</a>';
$display_output .= '<a id="open-view-list" href="#">' . Display::return_icon('listwork.png', get_lang('ViewStudents'),'',ICON_SIZE_MEDIUM) . '</a>';
}
@ -70,11 +70,12 @@ function display_action_links($id, $cur_dir_path, $action)
}
/**
* Displays all options for this tool.
* Returns a form displaying all options for this tool.
* These are
* - make all files visible / invisible
* - set the default visibility of uploaded files
* @param $defaults
* @return string The HTML form
*/
function settingsForm($defaults)
{

@ -172,7 +172,7 @@ if (api_is_allowed_to_session_edit(false, true) && !empty($workId) && !$isDrhOfC
$count = get_count_work($workId);
if ($count > 0) {
$display_output .= '<a href="downloadfolder.inc.php?id='.$workId.'&'.api_get_cidreq().'">'.
Display::return_icon('save_pack.png', get_lang('Save'), array('style' => 'float:right;'), ICON_SIZE_MEDIUM).'</a>';
Display::return_icon('save_pack.png', get_lang('Save'), null, ICON_SIZE_MEDIUM).'</a>';
}
$actionsLeft .= $display_output;

@ -12,6 +12,7 @@ in a currency other than the others courses or sessions
Allowing filter the sales by its status
- The plugin Registration page was removed. Instead the Chamilo LMS
registrarion page is used.
- Added the ability to record beneficiaries with the sale of courses/sessions
##Changes in database structure
@ -40,6 +41,7 @@ The __new database__ structure is formed for the tables:
- `plugin_buycourses_currency` The list of countries with their currencies
- `plugin_buycourses_item` The registered courses and sessions in the platform
- `plugin_buycourses_item_re_beneficiary` The beneficiaries users with the sale of courses
- `plugin_buycourses_paypal_account` The PayPal account info
- `plugin_buycourses_sale` The sales of courses and sessions that were made
- `plugin_buycourses_transfer` The bank accounts for transfers

@ -97,6 +97,30 @@ $itemTable->addForeignKeyConstraint(
['onDelete' => 'CASCADE']
);
$itemBeneficiary = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_ITEM_BENEFICIARY);
$itemBeneficiary->addColumn(
'id',
\Doctrine\DBAL\Types\Type::INTEGER,
['autoincrement' => true, 'unsigned' => true]
);
$itemBeneficiary->addColumn(
'item_id',
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true]
);
$itemBeneficiary->addColumn(
'user_id',
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true]
);
$itemBeneficiary->setPrimaryKey(['id']);
$itemBeneficiary->addForeignKeyConstraint(
$itemTable,
['item_id'],
['id'],
['onDelete' => 'CASCADE']
);
$saleTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_SALE);
$saleTable->addColumn(
'id',
@ -104,7 +128,7 @@ $saleTable->addColumn(
['autoincrement' => true, 'unsigned' => true]
);
$saleTable->addColumn('reference', \Doctrine\DBAL\Types\Type::STRING);
$saleTable->addColumn('date', \Doctrine\DBAL\Types\Type::DATE);
$saleTable->addColumn('date', \Doctrine\DBAL\Types\Type::DATETIME);
$saleTable->addColumn(
'user_id',
\Doctrine\DBAL\Types\Type::INTEGER,

@ -1,36 +0,0 @@
/* For licensing terms, see /license.txt */
/**
* JS library for the Chamilo buy-courses plugin
* @package chamilo.plugin.buycourses
*/
$(document).ready(function () {
$(".bc-button-save").click(function () {
var currentRow = $(this).closest("tr");
var courseOrSessionObject = {
tab: "save_mod",
visible: currentRow.find("[name='visible']").is(':checked') ? 1 : 0,
price: currentRow.find("[name='price']").val()
};
var itemField = currentRow.data('type') + '_id';
courseOrSessionObject[itemField] = currentRow.data('item') || 0;
$.post(
"function.php",
courseOrSessionObject,
function (data) {
if (!data.status) {
return;
}
currentRow.addClass('success');
window.setTimeout(function () {
currentRow.removeClass('success');
}, 3000);
},
"json"
);
});
});

@ -1,6 +1,6 @@
<?php
$strings['plugin_title'] = "Sell courses";
$strings['plugin_comment'] = "Sell courses directly through your Chamilo portal, using a PayPal account to receive funds. This plugin is in beta version. Neither the Chamilo association nor the developers involved could be considered responsible of any issue you might suffer using this plugin.";
$strings['plugin_comment'] = "Sell courses directly through your Chamilo portal, using a PayPal account to receive funds. Neither the Chamilo association nor the developers involved could be considered responsible of any issue you might suffer using this plugin.";
$strings['show_main_menu_tab'] = "Show tab in main menu";
$strings['show_main_menu_tab_help'] = "In case of not wanting to show the tab, you can create this link in your Chamilo homepage : %s";
$strings['include_sessions'] = "Include sessions";
@ -84,3 +84,7 @@ $strings['InfoApiStepOne'] = "Go to your PayPal account, <strong>Summary</strong
$strings['InfoApiStepTwo'] = "In paragraph <strong>API access</strong>, click <strong>Update</strong>";
$strings['InfoApiStepThree'] = "In Option 2 (Request API credentials to create your own API username and password), click the <strong>View API Signature</strong> link, and copy the credentials shown right into the BuyCourses plugin form";
$strings['ErrorOccurred'] = "<strong>An error ocurred</strong>. Code: %s. Message: %s. Please contact to platform admin";
$strings['VisibleInCatalog'] = "Visible in catalog";
$strings['Beneficiaries'] = "Beneficiaries";
$strings['AvailableCourse'] = "Available course";
$strings['ShowOnCourseCatalog'] = "Show on course catalog";

@ -1,6 +1,6 @@
<?php
$strings['plugin_title'] = "Vente de cours";
$strings['plugin_comment'] = "Vendez vos cours directement depuis votre portail Chamilo, au travers d'un compte PayPal. Plugin en version beta, à utiliser avec précaution. Ni l'association Chamilo ni les développeurs impliqués dans le développement de ce plugin ne sauraient être tenus responsables d'un quelconque inconvénient causé par celui-ci.";
$strings['plugin_comment'] = "Vendez vos cours directement depuis votre portail Chamilo, au travers d'un compte PayPal. Ni l'association Chamilo ni les développeurs impliqués dans le développement de ce plugin ne sauraient être tenus responsables d'un quelconque inconvénient causé par celui-ci.";
$strings['show_main_menu_tab'] = "Montrer l'onglet dans le menu principal";
$strings['show_main_menu_tab_help'] = "Dans le cas où vous ne souhaitez pas montrer l'onglet, il est possible de rajouter le lien suivant à votre portail Chamilo: %s";
$strings['include_sessions'] = "Inclure les sessions";
@ -18,7 +18,7 @@ $strings['Price'] = "Prix";
$strings['SearchFilter'] = "Filtre de recherche";
$strings['MinimumPrice'] = "Prix minimum";
$strings['MaximumPrice'] = "Prix maximum";
$strings['AvailableCourses'] = "Configuration des cours disponibles";
$strings['AvailableCoursesConfiguration'] = "Configuration des cours disponibles";
$strings['PaymentsConfiguration'] = "Configuration des paiements";
$strings['TheUserIsAlreadyRegisteredInTheCourse'] = "L'utilisateur est déjà inscrit au cours";
$strings['SeeDescription'] = "Voir description";
@ -84,3 +84,7 @@ $strings['InfoApiStepOne'] = "Aller dans l\'option <strong>profil</strong> de Pa
$strings['InfoApiStepTwo'] = "Dans la section <strong>API d\'accès</strong>, cloquer sur l\'option <strong>Mettre à jour</strong>";
$strings['InfoApiStepThree'] = "Dans l\'option 2 de Configuration des données et permissions API, cliquer sur <strong>Voir signature API</strong>. Copier ces donées dans le formulaire de configuration de ce plugin";
$strings['ErrorOccurred'] = "<strong>Une erreur est survenue</strong>. Code: %s. Message: %s. Veuillez contacter l'administrateur de la plateforme";
$strings['VisibleInCatalog'] = "Visible dans le catalogue";
$strings['Beneficiaries'] = "Bénéficiaires";
$strings['AvailableCourse'] = "Cours disponibles";
$strings['ShowOnCourseCatalog'] = "Afficher dans le catalogue de cours";

@ -1,6 +1,6 @@
<?php
$strings['plugin_title'] = "Venta de cursos";
$strings['plugin_comment'] = "Vender cursos a través de PayPal directamente desde su portal Chamilo. Plugin en versión Beta, a usar con mucha precaución. La asociación Chamilo y los desarrolladores involucrados no pueden ser considerados responsables de cualquier inconveniente que se presente.";
$strings['plugin_comment'] = "Vender cursos a través de PayPal directamente desde su portal Chamilo. La asociación Chamilo y los desarrolladores involucrados no pueden ser considerados responsables de cualquier inconveniente que se presente.";
$strings['show_main_menu_tab'] = "Mostrar pestaña en el menu principal";
$strings['show_main_menu_tab_help'] = "En caso de no querer mostrar la pestaña, puede agregar el siguiente enlace a su portal Chamilo: %s";
$strings['include_sessions'] = "Incluir sesiones";
@ -84,3 +84,7 @@ $strings['InfoApiStepOne'] = "Ir a la opción de <strong>Perfil de PayPal</stron
$strings['InfoApiStepTwo'] = "En el apartado <strong>Acceso API</strong>, dar clic en la opción <strong>Actualizar</strong>";
$strings['InfoApiStepThree'] = "En la opción 2, de Configuración de credenciales y permisos de API, dar clic en <strong>Ver firma de API</strong>. Copiar los datos de las credenciales en el formulario de configuración de este plugin";
$strings['ErrorOccurred'] = "<strong>Ocurrio un error</strong>. Codigo: %s. Mensaje: %s. Por favor, contacta al administrador de la plataforma.";
$strings['VisibleInCatalog'] = "Visible en el catálogo";
$strings['Beneficiaries'] = "Beneficiarios";
$strings['AvailableCourse'] = "Curso disponible";
$strings['ShowOnCourseCatalog'] = "Mostrar en el catálogo de cursos";

@ -16,6 +16,7 @@ class BuyCoursesPlugin extends Plugin
const TABLE_PAYPAL = 'plugin_buycourses_paypal_account';
const TABLE_CURRENCY = 'plugin_buycourses_currency';
const TABLE_ITEM = 'plugin_buycourses_item';
const TABLE_ITEM_BENEFICIARY = 'plugin_buycourses_item_rel_beneficiary';
const TABLE_SALE = 'plugin_buycourses_sale';
const TABLE_TRANSFER = 'plugin_buycourses_transfer';
const PRODUCT_TYPE_COURSE = 1;
@ -44,7 +45,7 @@ class BuyCoursesPlugin extends Plugin
Jose Angel Ruiz - NoSoloRed (original author),
Francis Gonzales and Yannick Warnier - BeezNest (integration),
Alex Aragón - BeezNest (Design icons and css styles),
Imanol Losada - BeezNest (introduction of sessions purchase)
Imanol Losada - BeezNest (introduction of sessions purchase),
Angel Fernando Quiroz Campos - BeezNest
",
array(
@ -62,6 +63,13 @@ class BuyCoursesPlugin extends Plugin
*/
function install()
{
$appPlugin = new AppPlugin();
$installedPlugins = $appPlugin->get_installed_plugins();
if (in_array($this->get_name(), $installedPlugins)) {
return false;
}
require_once api_get_path(SYS_PLUGIN_PATH) . 'buycourses/database.php';
}
@ -73,6 +81,7 @@ class BuyCoursesPlugin extends Plugin
$tablesToBeDeleted = array(
self::TABLE_PAYPAL,
self::TABLE_TRANSFER,
self::TABLE_ITEM_BENEFICIARY,
self::TABLE_ITEM,
self::TABLE_SALE,
self::TABLE_CURRENCY
@ -285,26 +294,7 @@ class BuyCoursesPlugin extends Plugin
$currency = $this->getSelectedCurrency();
foreach ($courses as $course) {
$courseItem = [
'course_id' => $course->getId(),
'course_visual_code' => $course->getVisualCode(),
'course_code' => $course->getCode(),
'course_title' => $course->getTitle(),
'course_visibility' => $course->getVisibility(),
'visible' => false,
'currency' => empty($currency) ? null : $currency['iso_code'],
'price' => 0.00
];
$item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
if ($item !== false) {
$courseItem['visible'] = true;
$courseItem['currency'] = $item['iso_code'];
$courseItem['price'] = $item['price'];
}
$configurationCourses[] = $courseItem;
$configurationCourses[] = $this->getCourseForConfiguration($course, $currency);
}
return $configurationCourses;
@ -316,9 +306,6 @@ class BuyCoursesPlugin extends Plugin
*/
public function getSessionsForConfiguration()
{
$buyItemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
$buyCurrencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
$auth = new Auth();
$sessions = $auth->browseSessions();
@ -326,55 +313,8 @@ class BuyCoursesPlugin extends Plugin
$items = [];
$fakeItemFrom = "
$buyItemTable i
INNER JOIN $buyCurrencyTable c
ON i.currency_id = c.id
";
foreach ($sessions as $session) {
$sessionItem = [
'session_id' => $session->getId(),
'session_name' => $session->getName(),
'session_visibility' => $session->getVisibility(),
'session_display_start_date' => null,
'session_display_end_date' => null,
'visible' => false,
'currency' => empty($currency) ? null : $currency['iso_code'],
'price' => 0.00
];
if (!empty($session->getDisplayStartDate())) {
$sessionItem['session_display_start_date'] = api_format_date(
$session->getDisplayStartDate()->format('Y-m-d h:i:s')
);
}
if (!empty($session->getDisplayEndDate())) {
$sessionItem['session_display_end_date'] = api_format_date(
$session->getDisplayEndDate()->format('Y-m-d h:i:s')
);
}
$item = Database::select(
['i.*', 'c.iso_code'],
$fakeItemFrom,
[
'where' => [
'i.product_id = ? AND ' => $session->getId(),
'i.product_type = ?' => self::PRODUCT_TYPE_SESSION
]
],
'first'
);
if ($item !== false) {
$sessionItem['visible'] = true;
$sessionItem['currency'] = $item['iso_code'];
$sessionItem['price'] = $item['price'];
}
$items[] = $sessionItem;
$items[] = $this->getSessionForConfiguration($session, $currency);
}
return $items;
@ -540,10 +480,6 @@ class BuyCoursesPlugin extends Plugin
return 'NO';
}
/**
* Lists current user course details
* @return array
*/
/**
* Lists current user course details
* @param string $name Optional. The name filter
@ -915,8 +851,8 @@ class BuyCoursesPlugin extends Plugin
/**
* Get a list of sales by the status
* @param type $status
* @return type
* @param int $status The status to filter
* @return array The sale list. Otherwise return false
*/
public function getSaleListByStatus($status = self::SALE_STATUS_PENDING)
{
@ -925,10 +861,8 @@ class BuyCoursesPlugin extends Plugin
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$innerJoins = "
INNER JOIN $currencyTable c
ON s.currency_id = c.id
INNER JOIN $userTable u
ON s.user_id = u.id
INNER JOIN $currencyTable c ON s.currency_id = c.id
INNER JOIN $userTable u ON s.user_id = u.id
";
return Database::select(
@ -1127,4 +1061,262 @@ class BuyCoursesPlugin extends Plugin
);
}
/**
* Get a list of sales by the user
* @param string $term The search term
* @return array The sale list. Otherwise return false
*/
public function getSaleListByUser($term)
{
$term = trim($term);
if (empty($term)) {
return [];
}
$saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
$currencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$innerJoins = "
INNER JOIN $currencyTable c ON s.currency_id = c.id
INNER JOIN $userTable u ON s.user_id = u.id
";
return Database::select(
['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
"$saleTable s $innerJoins",
[
'where' => [
'u.username LIKE %?% OR ' => $term,
'u.lastname LIKE %?% OR ' => $term,
'u.firstname LIKE %?%' => $term
],
'order' => 'id DESC'
]
);
}
/**
* Convert the course info to array with necessary course data for save item
* @param \Chamilo\CoreBundle\Entity\Course $course
* @param array $defaultCurrency Optional. Currency data
* @return array
*/
public function getCourseForConfiguration(\Chamilo\CoreBundle\Entity\Course $course, $defaultCurrency = null)
{
$courseItem = [
'item_id' => null,
'course_id' => $course->getId(),
'course_visual_code' => $course->getVisualCode(),
'course_code' => $course->getCode(),
'course_title' => $course->getTitle(),
'course_visibility' => $course->getVisibility(),
'visible' => false,
'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
'price' => 0.00
];
$item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
if ($item !== false) {
$courseItem['item_id'] = $item['id'];
$courseItem['visible'] = true;
$courseItem['currency'] = $item['iso_code'];
$courseItem['price'] = $item['price'];
}
return $courseItem;
}
/**
* Convert the session info to array with necessary session data for save item
* @param Chamilo\CoreBundle\Entity\Session $session The session data
* @param array $defaultCurrency Optional. Currency data
* @return array
*/
public function getSessionForConfiguration(Chamilo\CoreBundle\Entity\Session $session, $defaultCurrency = null)
{
$buyItemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
$buyCurrencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
$fakeItemFrom = "
$buyItemTable i
INNER JOIN $buyCurrencyTable c ON i.currency_id = c.id
";
$sessionItem = [
'item_id' => null,
'session_id' => $session->getId(),
'session_name' => $session->getName(),
'session_visibility' => $session->getVisibility(),
'session_display_start_date' => null,
'session_display_end_date' => null,
'visible' => false,
'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
'price' => 0.00
];
if (!empty($session->getDisplayStartDate())) {
$sessionItem['session_display_start_date'] = api_format_date(
$session->getDisplayStartDate()->format('Y-m-d h:i:s')
);
}
if (!empty($session->getDisplayEndDate())) {
$sessionItem['session_display_end_date'] = api_format_date(
$session->getDisplayEndDate()->format('Y-m-d h:i:s'),
DATE_TIME_FORMAT_LONG_24H
);
}
$item = Database::select(
['i.*', 'c.iso_code'],
$fakeItemFrom,
[
'where' => [
'i.product_id = ? AND ' => $session->getId(),
'i.product_type = ?' => self::PRODUCT_TYPE_SESSION
]
],
'first'
);
if ($item !== false) {
$sessionItem['item_id'] = $item['id'];
$sessionItem['visible'] = true;
$sessionItem['currency'] = $item['iso_code'];
$sessionItem['price'] = $item['price'];
}
return $sessionItem;
}
/**
* Get all beneficiaries for a item
* @param int $itemId The item ID
* @return array The beneficiries. Otherwise return false
*/
public function getItemBeneficiaries($itemId)
{
$beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
return Database::select(
'*',
$beneficiaryTable,
['where' => [
'item_id = ?' => intval($itemId)
]]
);
}
/**
* Delete a item with its beneficiaries
* @param int $itemId The item ID
* @return int The number of affected rows. Otherwise return false
*/
public function deleteItem($itemId)
{
$itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
$affectedRows = Database::delete(
$itemTable,
['id = ?' => intval($itemId)]
);
if (!$affectedRows) {
return false;
}
return $this->deleteItemBeneficiaries($itemId);
}
/**
* Register a item
* @param array $itemData The item data
* @return int The item ID. Otherwise return false
*/
public function registerItem(array $itemData)
{
$itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
return Database::insert($itemTable, $itemData);
}
/**
* Update the item data by product
* @param array $itemData The item data to be updated
* @param int $productId The product ID
* @param int $productType The type of product
* @return int The number of affected rows. Otherwise return false
*/
public function updateItem(array $itemData, $productId, $productType)
{
$itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
return Database::update(
$itemTable,
$itemData,
[
'product_id = ? AND ' => intval($productId),
'product_type' => $productType
]
);
}
/**
* Remove all beneficiaries for a item
* @param int $itemId The user ID
* @return int The number of affected rows. Otherwise return false
*/
public function deleteItemBeneficiaries($itemId)
{
$beneficiaryTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM_BENEFICIARY);
return Database::delete(
$beneficiaryTable,
['item_id = ?' => intval($itemId)]
);
}
/**
* Register the beneficiaries users with the sale of item
* @param int $itemId The item ID
* @param array $userIds The beneficiary user ID
*/
public function registerItemBeneficiaries($itemId, array $userIds)
{
$beneficiaryTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM_BENEFICIARY);
$this->deleteItemBeneficiaries($itemId);
foreach ($userIds as $userId) {
Database::insert(
$beneficiaryTable,
[
'item_id' => intval($itemId),
'user_id' => intval($userId)
]
);
}
}
/**
* Check if a course is valid for sale
* @param Chamilo\CoreBundle\Entity\Course $course The course
* @return boolean
*/
public function isValidCourse(Chamilo\CoreBundle\Entity\Course $course)
{
$courses = $this->getCourses();
foreach ($courses as $_c) {
if ($_c->getCode() === $course->getCode()) {
return true;
}
}
return false;
}
}

@ -30,6 +30,8 @@ $interbreadcrumb[] = [
$templateName = $plugin->get_lang('AvailableCourses');
$tpl = new Template($templateName);
$tpl->assign('product_type_course', BuyCoursesPlugin::PRODUCT_TYPE_COURSE);
$tpl->assign('product_type_session', BuyCoursesPlugin::PRODUCT_TYPE_SESSION);
$tpl->assign('courses', $courses);
$tpl->assign('sessions_are_included', $includeSession);

@ -0,0 +1,220 @@
<?php
/* For license terms, see /license.txt */
/**
* Configuration script for the Buy Courses plugin
* @package chamilo.plugin.buycourses
*/
/**
* Initialization
*/
$cidReset = true;
require_once '../config.php';
api_protect_admin_script();
if (!isset($_REQUEST['t'], $_REQUEST['i'])) {
die;
}
$plugin = BuyCoursesPlugin::create();
$includeSession = $plugin->get('include_sessions') === 'true';
$editingCourse = intval($_REQUEST['t']) === BuyCoursesPlugin::PRODUCT_TYPE_COURSE;
$editingSession = intval($_REQUEST['t']) === BuyCoursesPlugin::PRODUCT_TYPE_SESSION;
$entityManager = Database::getManager();
$userRepo = $entityManager->getRepository('ChamiloUserBundle:User');
$currency = $plugin->getSelectedCurrency();
$currencyIso = null;
if ($editingCourse) {
$course = $entityManager->find('ChamiloCoreBundle:Course', $_REQUEST['i']);
if (!$course) {
api_not_allowed(true);
}
if (!$plugin->isValidCourse($course)) {
api_not_allowed(true);
}
$courseItem = $plugin->getCourseForConfiguration($course, $currency);
$defaultBeneficiaries = [];
$teachers = $course->getTeachers();
$teachersOptions = [];
foreach ($teachers as $courseTeacher) {
$teacher = $courseTeacher->getUser();
$teachersOptions[] = [
'text' => $teacher->getCompleteName(),
'value' => $teacher->getId()
];
$defaultBeneficiaries[] = $teacher->getId();
}
$currentBeneficiaries = $plugin->getItemBeneficiaries($courseItem['item_id']);
if (!empty($currentBeneficiaries)) {
$defaultBeneficiaries = array_column($currentBeneficiaries, 'user_id');
}
$currencyIso = $courseItem['currency'];
$formDefaults = [
'product_type' => get_lang('Course'),
'i' => $courseItem['course_id'],
't' => BuyCoursesPlugin::PRODUCT_TYPE_COURSE,
'name' => $courseItem['course_title'],
'visible' => $courseItem['visible'],
'price' => $courseItem['price'],
'beneficiaries' => $defaultBeneficiaries
];
} elseif ($editingSession) {
if (!$includeSession) {
api_not_allowed(true);
}
$session = $entityManager->find('ChamiloCoreBundle:Session', $_REQUEST['i']);
if (!$session) {
api_not_allowed(true);
}
$sessionItem = $plugin->getSessionForConfiguration($session, $currency);
$generalCoach = $session->getGeneralCoach();
$generalCoachOption = [
'text' => $generalCoach->getCompleteName(),
'value' => $generalCoach->getId()
];
$defaultBeneficiaries = [
$generalCoach->getId()
];
$courseCoachesOptions = [];
$sessionCourses = $session->getCourses();
foreach ($sessionCourses as $sessionCourse) {
$courseCoaches = $userRepo->getCoachesForSessionCourse($session, $sessionCourse->getCourse());
foreach ($courseCoaches as $courseCoach) {
if ($generalCoach->getId() === $courseCoach->getId()) {
continue;
}
$courseCoachesOptions[] = [
'text' => $courseCoach->getCompleteName(),
'value' => $courseCoach->getId()
];
$defaultBeneficiaries[] = $courseCoach->getId();
}
}
$currentBeneficiaries = $plugin->getItemBeneficiaries($sessionItem['item_id']);
if (!empty($currentBeneficiaries)) {
$defaultBeneficiaries = array_column($currentBeneficiaries, 'user_id');
}
$currencyIso = $sessionItem['currency'];
$formDefaults = [
'product_type' => get_lang('Session'),
'i' => $session->getId(),
't' => BuyCoursesPlugin::PRODUCT_TYPE_SESSION,
'name' => $sessionItem['session_name'],
'visible' => $sessionItem['visible'],
'price' => $sessionItem['price'],
'beneficiaries' => $defaultBeneficiaries
];
} else {
api_not_allowed(true);
}
$form = new FormValidator('beneficiaries');
$form->addText('product_type', $plugin->get_lang('ProductType'), false);
$form->addText('name', get_lang('Name'), false);
$visibleCheckbox = $form->addCheckBox(
'visible',
$plugin->get_lang('VisibleInCatalog'),
$plugin->get_lang('ShowOnCourseCatalog')
);
$form->addElement(
'number',
'price',
[$plugin->get_lang('Price'), null, $currencyIso],
['step' => 0.01]
);
$beneficiariesSelect = $form->addSelect(
'beneficiaries',
$plugin->get_lang('Beneficiaries'),
null,
['multiple' => 'multiple']
);
if ($editingCourse) {
$beneficiariesSelect->addOptGroup($teachersOptions, get_lang('Teachers'));
} elseif ($editingSession) {
$beneficiariesSelect->addOptGroup([$generalCoachOption], get_lang('SessionGeneralCoach'));
$beneficiariesSelect->addOptGroup($courseCoachesOptions, get_lang('SessionCourseCoach'));
}
$form->addHidden('t', null);
$form->addHidden('i', null);
$form->addButtonSave(get_lang('Save'));
$form->freeze(['product_type', 'name']);
if ($form->validate()) {
$formValues = $form->exportValues();
$productItem = $plugin->getItemByProduct($formValues['i'], $formValues['t']);
if (isset($formValues['visible'])) {
if (!empty($productItem)) {
$plugin->updateItem(
['price' => floatval($formValues['price'])],
$formValues['i'],
$formValues['t']
);
} else {
$itemId = $plugin->registerItem([
'currency_id' => $currency['id'],
'product_type' => $formValues['t'],
'product_id' => intval($formValues['i']),
'price' => floatval($_POST['price'])
]);
$productItem['id'] = $itemId;
}
$plugin->deleteItemBeneficiaries($productItem['id']);
if (isset($formValues['beneficiaries'])) {
$plugin->registerItemBeneficiaries($productItem['id'], $formValues['beneficiaries']);
}
} else {
$plugin->deleteItem($productItem['id']);
}
header('Location: ' . api_get_path(WEB_PLUGIN_PATH) . 'buycourses/src/configuration.php');
exit;
}
$form->setDefaults($formDefaults);
//View
$templateName = $plugin->get_lang('AvailableCourse');
$interbreadcrumb[] = [
'url' => 'paymentsetup.php',
'name' => get_lang('Configuration')
];
$interbreadcrumb[] = [
'url' => 'configuration.php',
'name' => $plugin->get_lang('AvailableCourses')
];
$template = new Template($templateName);
$template->assign('header', $templateName);
$template->assign('content', $form->returnForm());
$template->display_one_col_template();

@ -1,85 +0,0 @@
<?php
/* For license terms, see /license.txt */
/**
* Functions for the Buy Courses plugin
* @package chamilo.plugin.buycourses
*/
/**
* Init
*/
require_once '../config.php';
$itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
$plugin = BuyCoursesPlugin::create();
$currency = $plugin->getSelectedCurrency();
if ($_REQUEST['tab'] == 'save_mod') {
if (isset($_REQUEST['course_id'])) {
$productId = $_REQUEST['course_id'];
$productType = BuyCoursesPlugin::PRODUCT_TYPE_COURSE;
} else {
$productId = $_REQUEST['session_id'];
$productType = BuyCoursesPlugin::PRODUCT_TYPE_SESSION;
}
$affectedRows = false;
if ($_POST['visible'] == 1) {
$item = Database::select(
'COUNT(1) AS qty',
$itemTable,
[
'where' => [
'product_id = ? AND ' => intval($productId),
'product_type = ?' => $productType
]
],
'first'
);
if ($item['qty'] > 0) {
$affectedRows = Database::update(
$itemTable,
['price' => floatval($_POST['price'])],
[
'product_id = ? AND ' => intval($productId),
'product_type' => $productType
]
);
} else {
$affectedRows = Database::insert(
$itemTable,
[
'currency_id' => $currency['id'],
'product_type' => $productType,
'product_id' => intval($productId),
'price' => floatval($_POST['price'])
]
);
}
} else {
$affectedRows = Database::delete(
$itemTable,
[
'product_id = ? AND ' => intval($productId),
'product_type = ?' => $productType
]
);
}
if ($affectedRows > 0) {
$jsonResult = [
"status" => true,
"itemId" => $productId
];
} else {
$jsonResult = [
"status" => false,
"content" => $plugin->get_lang('ItemNotSaved')
];
}
echo json_encode($jsonResult);
exit;
}

@ -21,7 +21,6 @@ if ($guess_enable == "true" || isset($_SESSION['_user'])) {
$content = $tpl->fetch('buycourses/view/index.tpl');
$tpl->assign('header', $plugin->get_lang('plugin_title'));
$tpl->assign('content', $content);
$tpl->display_one_col_template();

@ -1,4 +1,5 @@
<?php
/* For license terms, see /license.txt */
/**
* List of pending payments of the Buy Courses plugin
@ -35,7 +36,7 @@ if (isset($_GET['order'])) {
$urlToRedirect .= http_build_query([
'status' => BuyCoursesPlugin::SALE_STATUS_COMPLETED,
'sale' => $sale['id']
'sale' => $sale['id']
]);
break;
case 'cancel':
@ -50,7 +51,7 @@ if (isset($_GET['order'])) {
$urlToRedirect .= http_build_query([
'status' => BuyCoursesPlugin::SALE_STATUS_CANCELED,
'sale' => $sale['id']
'sale' => $sale['id']
]);
break;
}
@ -61,24 +62,55 @@ if (isset($_GET['order'])) {
$productTypes = $plugin->getProductTypes();
$saleStatuses = $plugin->getSaleStatuses();
$paymentTypes = $plugin->getPaymentTypes();
$selectedFilterType = '0';
$selectedStatus = isset($_GET['status']) ? $_GET['status'] : BuyCoursesPlugin::SALE_STATUS_PENDING;
$selectedSale = isset($_GET['sale']) ? intval($_GET['sale']) : 0;
$searchTerm = '';
$form = new FormValidator('search', 'get');
if ($form->validate()) {
$selectedFilterType = $form->getSubmitValue('filter_type');
$selectedStatus = $form->getSubmitValue('status');
$searchTerm = $form->getSubmitValue('user');
if ($selectedStatus === false) {
$selectedStatus = BuyCoursesPlugin::SALE_STATUS_PENDING;
}
if ($selectedFilterType === false) {
$selectedFilterType = '0';
}
}
$form->addRadio(
'filter_type',
get_lang('FilterBy'),
[$plugin->get_lang('ByStatus'), $plugin->get_lang('ByUser')]
);
$form->addHtml('<div id="report-by-status" ' . ($selectedFilterType !== '0' ? 'style="display:none"' : '') . '>');
$form->addSelect('status', $plugin->get_lang('OrderStatus'), $saleStatuses);
$form->addHtml('</div>');
$form->addHtml('<div id="report-by-user" ' . ($selectedFilterType !== '1' ? 'style="display:none"' : '') . '>');
$form->addText('user', get_lang('UserName'), false);
$form->addHtml('</div>');
$form->addButtonFilter($plugin->get_lang('SearchByStatus'));
$form->setDefaults(['status' => $selectedStatus]);
$form->setDefaults([
'filter_type' => $selectedFilterType,
'status' => $selectedStatus
]);
switch ($selectedFilterType) {
case '0':
$sales = $plugin->getSaleListByStatus($selectedStatus);
break;
case '1':
$sales = $plugin->getSaleListByUser($searchTerm);
break;
}
$sales = $plugin->getSaleListByStatus($selectedStatus);
$saleList = [];
foreach ($sales as $sale) {
@ -86,12 +118,13 @@ foreach ($sales as $sale) {
'id' => $sale['id'],
'reference' => $sale['reference'],
'status' => $sale['status'],
'date' => api_format_date($sale['date'], DATE_FORMAT_LONG_NO_DAY),
'date' => api_format_date($sale['date'], DATE_TIME_FORMAT_LONG_24H),
'currency' => $sale['iso_code'],
'price' => $sale['price'],
'product_name' => $sale['product_name'],
'product_type' => $productTypes[$sale['product_type']],
'complete_user_name' => api_get_person_name($sale['firstname'], $sale['lastname'])
'complete_user_name' => api_get_person_name($sale['firstname'], $sale['lastname']),
'payment_type' => $paymentTypes[$sale['payment_type']]
];
}

@ -23,7 +23,7 @@
{% if showing_courses %}
{% for course in courses %}
<div class="col-md-4 col-sm-6">
<div class="thumbnail">
<article class="thumbnail">
<img alt="{{ course.title }}" class="img-responsive" src="{{ course.course_img ? course.course_img : 'session_default.png'|icon() }}">
<div class="caption">
{% set course_description_url = _p.web_ajax ~ 'course_home.ajax.php?' ~ {'code': course.code, 'a': 'show_course_information'}|url_encode() %}
@ -53,7 +53,7 @@
<div class="alert alert-info">{{ 'WaitingToReceiveThePayment'|get_plugin_lang('BuyCoursesPlugin') }}</div>
{% endif %}
</div>
</div>
</article>
</div>
{% endfor %}
{% endif %}
@ -61,7 +61,7 @@
{% if showing_sessions %}
{% for session in sessions %}
<div class="col-md-4 col-sm-6">
<div class="thumbnail">
<article class="thumbnail">
<img alt="{{ session.name }}" class="img-responsive" src="{{ session.image ? session.image : 'session_default.png'|icon() }}">
<div class="caption">
<h3>
@ -100,7 +100,7 @@
<div class="alert alert-info">{{ 'WaitingToReceiveThePayment'|get_plugin_lang('BuyCoursesPlugin') }}</div>
{% endif %}
</div>
</div>
</article>
</div>
{% endfor %}
{% endif %}

@ -21,9 +21,9 @@
<tr>
<th>{{ 'Title'|get_lang }}</th>
<th class="text-center">{{ 'OfficialCode'|get_lang }}</th>
<th class="text-center">{{ 'Visible'|get_lang }}</th>
<th class="text-center">{{ 'VisibleInCatalog'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-right" width="200">{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-right">{{ 'Option'|get_lang }}</th>
<th class="text-right">{{ 'Options '|get_lang }}</th>
</tr>
</thead>
@ -50,26 +50,19 @@
{{ item.course_code }}
</td>
<td class="text-center">
{% if item.visible == 1 %}
<input type="checkbox" name="visible" value="1" checked="checked" size="6">
{% if item.visible %}
<i class="fa fa-fw fa-check-square-o"></i>
{% else %}
<input type="checkbox" name="visible" value="1" size="6">
<i class="fa fa-fw fa-square-o"></i>
{% endif %}
</td>
<td width="200">
{% if item.currency %}
<div class="input-group">
<span class="input-group-addon" id="price-{{ item.course_id }}">{{ item.currency }}</span>
<input type="number" name="price" value="{{ item.price }}" step="0.01" min="0" class="text-right form-control" aria-describedby="price-{{ item.course_id }}">
</div>
{% else %}
<input type="number" name="price" value="{{ item.price }}" step="0.01" min="0" class="text-right form-control">
{% endif %}
<td width="200" class="text-right">
{{ "#{item.price} #{tem.currency ?: item.currency}" }}
</td>
<td class="text-right">
<button class="btn btn-success btn-sm bc-button-save" type="button">
<i class="fa fa-save"></i> {{ 'Save'|get_lang }}
</button>
<a href="{{ _p.web_plugin ~ 'buycourses/src/configure_course.php?' ~ {'i': item.course_id, 't':product_type_course}|url_encode() }}" class="btn btn-info btn-sm">
<i class="fa fa-wrench fa-fw"></i> {{ 'Configure'|get_lang }}
</a>
</td>
</tr>
{% endfor %}
@ -87,9 +80,9 @@
<th>{{ 'Title'|get_lang }}</th>
<th class="text-center">{{ 'StartDate'|get_lang }}</th>
<th class="text-center">{{ 'EndDate'|get_lang }}</th>
<th class="text-center">{{ 'Visible'|get_lang }}</th>
<th class="text-center">{{ 'VisibleInCatalog'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-right">{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-right">{{ 'Option'|get_lang }}</th>
<th class="text-right">{{ 'Options'|get_lang }}</th>
</tr>
</thead>
<tbody>
@ -118,25 +111,18 @@
</td>
<td class="text-center">
{% if item.visible %}
<input type="checkbox" name="visible" value="1" checked="checked" size="6" />
<i class="fa fa-fw fa-check-square-o"></i>
{% else %}
<input type="checkbox" name="visible" value="1" size="6" />
<i class="fa fa-fw fa-square-o"></i>
{% endif %}
</td>
<td class="text-right" width="200">
{% if item.currency %}
<div class="input-group">
<span class="input-group-addon" id="price-{{ item.session_id }}">{{ item.currency }}</span>
<input type="number" name="price" value="{{ item.price }}" step="0.01" min="0" class="text-right form-control" aria-describedby="price-{{ item.session_id }}">
</div>
{% else %}
<input type="number" name="price" value="{{ item.price }}" step="0.01" min="0" class="text-right form-control">
{% endif %}
{{ "#{item.price} #{tem.currency ?: item.currency}" }}
</td>
<td class=" text-center" id="session{{ item.session_id }}">
<button class="btn btn-success btn-sm bc-button-save" type="button">
<i class="fa fa-save"></i> {{ 'Save'|get_lang }}
</button>
<td class="text-right">
<a href="{{ _p.web_plugin ~ 'buycourses/src/configure_course.php?' ~ {'i': item.session_id, 't': product_type_session}|url_encode() }}" class="btn btn-info btn-sm">
<i class="fa fa-wrench fa-fw"></i> {{ 'Configure'|get_lang }}
</a>
</td>
</tr>
{% endfor %}

@ -1,80 +1,75 @@
<link rel="stylesheet" type="text/css" href="resources/css/style.css"/>
{% if _u.is_admin %}
<div class="row">
<div class="col-md-12">
<article class="jumbotron">
<h3>{{ 'TitlePlugin'|get_plugin_lang('BuyCoursesPlugin') }}</h3>
<p>{{ 'PluginPresentation'|get_plugin_lang('BuyCoursesPlugin') }}</p>
<ul class="list-unstyled">
<li>
{{ 'Instructions'|get_plugin_lang('BuyCoursesPlugin') }}
<ul>
<li>{{ 'InstructionsStepOne'|get_plugin_lang('BuyCoursesPlugin') }}</li>
<li>{{ 'InstructionsStepTwo'|get_plugin_lang('BuyCoursesPlugin') }}</li>
<li>{{ 'InstructionsStepThree'|get_plugin_lang('BuyCoursesPlugin') }}</li>
</ul>
</li>
</ul>
</article>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-md-12">
{% if _u.is_admin %}
<div class="help-bycourse">
<div class="row">
<div class="col-md-7">
<div class="panel panel-default">
<div class="panel-body">
<h3>{{ 'TitlePlugin'|get_plugin_lang('BuyCoursesPlugin') }}</h3>
<p>{{ 'PluginPresentation'|get_plugin_lang('BuyCoursesPlugin') }}</p>
<p>&nbsp;</p>
</div>
</div>
</div>
<div class="col-md-5">
<div class="panel panel-default">
<div class="panel-heading">
{{ 'Instructions'|get_plugin_lang('BuyCoursesPlugin') }}
</div>
<div class="panel-body">
<ul>
<li>{{ 'InstructionsStepOne'|get_plugin_lang('BuyCoursesPlugin') }}</li>
<li>{{ 'InstructionsStepTwo'|get_plugin_lang('BuyCoursesPlugin') }}</li>
<li>{{ 'InstructionsStepThree'|get_plugin_lang('BuyCoursesPlugin') }}</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="thumbnail">
<a href="src/course_catalog.php">
<img src="resources/img/128/buycourses.png">
</a>
<div class="caption">
<p class="text-center">
<a class="btn btn-default btn-sm" href="src/course_catalog.php">{{ 'BuyCourses'|get_plugin_lang('BuyCoursesPlugin') }}</a>
</p>
</div>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="thumbnail">
<a href="src/course_catalog.php">
<img src="resources/img/128/buycourses.png">
</a>
<div class="caption" align="center">
<a class="btn btn-default btn-sm" href="src/course_catalog.php">{{ 'BuyCourses'|get_plugin_lang('BuyCoursesPlugin') }}</a>
</div>
{% if _u.is_admin %}
<div class="col-md-3">
<div class="thumbnail">
<a href="src/configuration.php">
<img src="resources/img/128/settings.png">
</a>
<div class="caption">
<p class="text-center">
<a class="btn btn-default btn-sm" href="src/configuration.php">{{ 'ConfigurationOfCoursesAndPrices'|get_plugin_lang('BuyCoursesPlugin') }}</a>
</p>
</div>
</div>
{% if _u.is_admin %}
<div class="col-md-3">
<div class="thumbnail">
<a href="src/configuration.php">
<img src="resources/img/128/settings.png">
</a>
<div class="caption" align="center">
<a class="btn btn-default btn-sm" href="src/configuration.php">{{ 'ConfigurationOfCoursesAndPrices'|get_plugin_lang('BuyCoursesPlugin') }}</a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="thumbnail">
<a href="src/paymentsetup.php">
<img src="resources/img/128/paymentsettings.png">
</a>
<div class="caption" align="center">
<a class="btn btn-default btn-sm" href="src/paymentsetup.php">{{ 'PaymentsConfiguration'|get_plugin_lang('BuyCoursesPlugin') }} </a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="thumbnail">
<a href="src/paymentsetup.php">
<img src="resources/img/128/paymentsettings.png">
</a>
<div class="caption">
<p class="text-center">
<a class="btn btn-default btn-sm" href="src/paymentsetup.php">{{ 'PaymentsConfiguration'|get_plugin_lang('BuyCoursesPlugin') }}</a>
</p>
</div>
<div class="col-md-3">
<div class="thumbnail">
<a href="src/sales_report.php">
<img src="resources/img/128/backlogs.png">
</a>
<div class="caption" align="center">
<a class="btn btn-default btn-sm" href="src/sales_report.php"> {{ 'SalesReport'|get_plugin_lang('BuyCoursesPlugin') }} </a>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="thumbnail">
<a href="src/sales_report.php">
<img src="resources/img/128/backlogs.png">
</a>
<div class="caption">
<p class="text-center">
<a class="btn btn-default btn-sm" href="src/sales_report.php"> {{ 'SalesReport'|get_plugin_lang('BuyCoursesPlugin') }}</a>
</p>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
</div>

@ -7,13 +7,12 @@
<th class="text-center">{{ 'OrderReference'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-center">{{ 'OrderStatus'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-center">{{ 'OrderDate'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-center">{{ 'PaymentMethod'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-center">{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-center">{{ 'ProductType'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th>{{ 'Name'|get_lang }}</th>
<th>{{ 'UserName'|get_lang }}</th>
{% if selected_status == sale_status_pending %}
<th class="text-center">{{ 'Options'|get_lang }}</th>
{% endif %}
<th class="text-center">{{ 'Options'|get_lang }}</th>
</tr>
</thead>
<tbody>
@ -30,24 +29,39 @@
{% endif %}
</td>
<td class="text-center">{{ sale.date }}</td>
<td class="text-center">{{ sale.payment_type }}</td>
<td class="text-right">{{ sale.currency ~ ' ' ~ sale.price }}</td>
<td class="text-center">{{ sale.product_type }}</td>
<td>{{ sale.product_name }}</td>
<td>{{ sale.complete_user_name }}</td>
{% if selected_status == sale_status_pending %}
<td class="text-center">
{% if sale.status == sale_status_pending %}
<a href="{{ _p.web_self ~ '?' ~ {'order': sale.id, 'action': 'confirm'}|url_encode() }}" class="btn btn-success btn-sm">
<i class="fa fa-user-plus fa-fw"></i> {{ 'SubscribeUser'|get_plugin_lang('BuyCoursesPlugin') }}
</a>
<a href="{{ _p.web_self ~ '?' ~ {'order': sale.id, 'action': 'cancel'}|url_encode() }}" class="btn btn-danger btn-sm">
<i class="fa fa-times fa-fw"></i> {{ 'DeleteOrder'|get_plugin_lang('BuyCoursesPlugin') }}
</a>
{% endif %}
</td>
{% endif %}
<td class="text-center">
{% if sale.status == sale_status_pending %}
<a href="{{ _p.web_self ~ '?' ~ {'order': sale.id, 'action': 'confirm'}|url_encode() }}" class="btn btn-success btn-sm">
<i class="fa fa-user-plus fa-fw"></i> {{ 'SubscribeUser'|get_plugin_lang('BuyCoursesPlugin') }}
</a>
<a href="{{ _p.web_self ~ '?' ~ {'order': sale.id, 'action': 'cancel'}|url_encode() }}" class="btn btn-danger btn-sm">
<i class="fa fa-times fa-fw"></i> {{ 'DeleteOrder'|get_plugin_lang('BuyCoursesPlugin') }}
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
$(document).on('ready', function () {
$('[name="filter_type"]').on('change', function () {
var self = $(this);
if (self.val() === '0') {
$('#report-by-user').hide();
$('#report-by-status').show();
} else {
$('#report-by-status').hide();
$('#report-by-user').show();
}
});
});
</script>

@ -5,6 +5,13 @@ Feature: Course tools basic testing
As a teacher
I need to be able to enter a course and each of its tools
Scenario: Create a course before testing
Given I am a platform administrator
And I am on "/main/admin/course_add.php"
When I fill in "title" with "TEMP"
And I press "submit"
Then I should see "Course list"
Scenario: Make sure the course exists
Given I am a platform administrator
Given course "TEMP" exists

@ -27,7 +27,7 @@ Feature: Users management as admin
Scenario: Search and delete a user
Given I am a platform administrator
And I am on "/main/admin/user_list.php"
And I fill in "user-search-keyword" with "smarshall"
And I fill in "keyword" with "smarshall"
And I press "submit"
When I follow "Delete"
Then I should see "The user has been deleted"

@ -0,0 +1,139 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script removes previous tasks from disk to clear space.
* Configure the date on lines 22-23 to change the dates after/before which
* to delete.
* This works based on sessions dates (it will not delete tasks from
* base courses).
* This script should be located inside the tests/scripts/ folder to work
* @author Paul Patrocinio <ppatrocino@icpna.edu.pe>
* @author Percy Santiago <psantiago@icpna.edu.pe>
* @author Yannick Warnier <yannick.warnier@beeznest.com>
*/
exit(); //remove this line to execute from the command line
if (PHP_SAPI !== 'cli') {
die('This script can only be executed from the command line');
}
require __DIR__.'/../../main/inc/conf/configuration.php';
// Dates
$expiryDate = '2015-06-01'; //session start date must be < to be considered
$fromDate = '2011-01-01'; //session start date must be > to be considered
$sessionCourses = array();
$coursesCodes = array();
$coursesDirs = array();
if (!$conexion = mysql_connect($_configuration['db_host'], $_configuration['db_user'], $_configuration['db_password'])) {
echo 'Could not connect to database';
exit;
}
if (!mysql_select_db($_configuration['main_database'], $conexion)) {
echo 'Could not select database '.$_configuration['main_database'];
exit;
}
echo "[".time()."] Querying sessions\n";
$sql = "SELECT id FROM session where access_start_date < '$expiryDate' AND access_start_date > '$fromDate'";
$res = mysql_query($sql, $conexion);
if ($res === false) {
//die("Error querying sessions: ".Database::error($res)."\n");
}
$countSessions = mysql_num_rows($res);
$sql = "SELECT count(*) FROM session";
$resc = mysql_query($sql, $conexion);
if ($resc === false) {
//die("Error querying sessions: ".Database::error($res)."\n");
}
$countAllSessions = mysql_result($resc, 0, 0);
echo "[".time()."] Found $countSessions sessions between $fromDate and $expiryDate on a total of $countAllSessions sessions."."\n";
while ($session = mysql_fetch_assoc($res)) {
$sql2 = "SELECT c.id AS cid, c.code as ccode, c.directory as cdir
FROM course c, session_rel_course s
WHERE s.id_session = ".$session['id']."
AND s.course_code = c.code";
$res2 = mysql_query($sql2, $conexion); //Database::query($sql2);
if ($res2 === false) {
die("Error querying courses for session ".$session['id'].": ".mysql_error($res2)."\n");
}
if (mysql_num_rows($res2) > 0) {
while ($course = mysql_fetch_assoc($res2)) {
$sessionCourses[$session['id']] = $course['cid'];
//$_SESSION['session_course'] = $sessionCourses;
if (empty($coursesCodes[$course['cid']])) {
$coursesCodes[$course['cid']] = $course['ccode'];
}
if (empty($coursesDirs[$course['cid']])) {
$coursesDirs[$course['cid']] = $course['cdir'];
}
}
}
}
echo "[".time()."] Filled courses arrays. Now checking tasks...\n";
/**
* Locate and destroy the expired tasks
*/
//$sessionCourse = $_SESSION['session_course'];
$totalSize = 0;
foreach ($sessionCourses as $sid => $cid) {
// Check if a folder already exists in this session
// Folders are exclusive to sessions. If a folder already exists in
// another session, you will not be allowed to create the same folder in
// another session. As such, folders belong to one and only one session.
$sql = "SELECT id, url FROM c_student_publication
WHERE filetype = 'folder'
AND c_id = $cid
AND session_id = $sid
AND active = 1
AND url LIKE '%ALP%'";
$resCarpetas = mysql_query($sql, $conexion); //Database::query($sql);
if (mysql_num_rows($resCarpetas) > 0) {
while ($rowDemo = mysql_fetch_assoc($resCarpetas)) {
$carpetaAlpElimina = $_configuration['root_sys'].'courses/'.$coursesDirs[$cid].'/work'.$rowDemo['url'];
//echo "rm -rf ".$carpetaAlpElimina."\n";
$size = folderSize($carpetaAlpElimina);
$totalSize += $size;
echo "Freeing $size of a total $totalSize bytes in $carpetaAlpElimina\n";
exec('rm -rf '.$carpetaAlpElimina);
}
$sqldel = "DELETE FROM c_student_publication
WHERE
c_id = $cid
AND session_id = $sid AND active = 1;";
$resdel = mysql_query($sqldel);
if ($resdel === false) {
echo "Error querying sessions: ".Database::error($resdel)."\n";
}
}
}
echo "[".time()."] Deleted tasks from $countSessions sessions between $fromDate and $expiryDate on a total of $countAllSessions sessions."."\n";
/**
* Helper function to calculate size of a folder
* @author See php.net comments on filesize()
*/
function folderSize($dir) {
$size = 0;
$contents = glob(rtrim($dir, '/').'/*', GLOB_NOSORT);
foreach ($contents as $contents_value) {
if (is_file($contents_value)) {
$size += filesize($contents_value);
} else {
$size += folderSize($contents_value);
}
}
return $size;
}
Loading…
Cancel
Save