Partial merge with 1.11.x see BT#15952

pull/3063/head
Julio Montoya 7 years ago
parent f5dfcef3a1
commit bdd6eb1b9e
  1. 2
      plugin/advanced_subscription/views/open_session.tpl
  2. 26
      plugin/azure_active_directory/README.md
  3. 28
      plugin/azure_active_directory/index.php
  4. 20
      plugin/azure_active_directory/lang/english.php
  5. 107
      plugin/azure_active_directory/src/AzureActiveDirectory.php
  6. 113
      plugin/azure_active_directory/src/callback.php
  7. 11
      plugin/azure_active_directory/view/block.tpl
  8. 6
      plugin/bbb/README.md
  9. 5
      plugin/bbb/lang/english.php
  10. 4
      plugin/bbb/lang/french.php
  11. 2
      plugin/bbb/lang/german.php
  12. 2
      plugin/bbb/lang/spanish.php
  13. 345
      plugin/bbb/lib/bbb.lib.php
  14. 171
      plugin/bbb/lib/bbb_api.php
  15. 22
      plugin/bbb/lib/bbb_plugin.class.php
  16. 101
      plugin/bbb/listing.php
  17. 2
      plugin/bbb/resources/utils.js
  18. 6
      plugin/bbb/start.php
  19. 7
      plugin/bbb/view/listing.tpl
  20. 10
      plugin/buycourses/CHANGELOG.md
  21. 87
      plugin/buycourses/database.php
  22. 2
      plugin/buycourses/lang/brazilian.php
  23. 2
      plugin/buycourses/lang/dutch.php
  24. 26
      plugin/buycourses/lang/english.php
  25. 2
      plugin/buycourses/lang/french.php
  26. 44
      plugin/buycourses/lang/spanish.php
  27. 9
      plugin/buycourses/resources/css/style.css
  28. 635
      plugin/buycourses/src/buy_course_plugin.class.php
  29. 8
      plugin/buycourses/src/buycourses.ajax.php
  30. 9
      plugin/buycourses/src/configuration.php
  31. 17
      plugin/buycourses/src/configure_course.php
  32. 16
      plugin/buycourses/src/index.buycourses.php
  33. 141
      plugin/buycourses/src/invoice.php
  34. 108
      plugin/buycourses/src/paymentsetup.php
  35. 12
      plugin/buycourses/src/process.php
  36. 52
      plugin/buycourses/src/process_confirm.php
  37. 11
      plugin/buycourses/src/sales_report.php
  38. 60
      plugin/buycourses/src/service_process_confirm.php
  39. 20
      plugin/buycourses/src/service_sales_report.php
  40. 9
      plugin/buycourses/src/services_add.php
  41. 8
      plugin/buycourses/src/services_edit.php
  42. 18
      plugin/buycourses/src/success.php
  43. 59
      plugin/buycourses/view/configuration.tpl
  44. 14
      plugin/buycourses/view/message_confirm.tpl
  45. 8
      plugin/buycourses/view/message_transfer.tpl
  46. 18
      plugin/buycourses/view/process.tpl
  47. 2
      plugin/buycourses/view/process_confirm.tpl
  48. 15
      plugin/buycourses/view/sales_report.tpl
  49. 10
      plugin/buycourses/view/service_information.tpl
  50. 2
      plugin/buycourses/view/service_panel.tpl
  51. 21
      plugin/buycourses/view/service_process.tpl
  52. 15
      plugin/buycourses/view/service_sales_report.tpl
  53. 4
      plugin/buycourses/view/success.tpl
  54. 2
      plugin/courseblock/CourseBlockPlugin.php
  55. 1
      plugin/customcertificate/config.php
  56. 1
      plugin/customcertificate/lang/english.php
  57. 1
      plugin/customcertificate/lang/spanish.php
  58. 21
      plugin/customcertificate/src/CustomCertificatePlugin.php
  59. 66
      plugin/customcertificate/src/index.php
  60. 123
      plugin/customcertificate/src/print_certificate.php
  61. 3
      plugin/dictionary/terms.php
  62. 2
      plugin/grading_electronic/view/grading.html.twig
  63. 305
      plugin/ims_lti/Entity/ImsLtiTool.php
  64. 105
      plugin/ims_lti/README.md
  65. 2
      plugin/ims_lti/admin.php
  66. 66
      plugin/ims_lti/create.php
  67. 57
      plugin/ims_lti/edit.php
  68. 215
      plugin/ims_lti/form.php
  69. 16
      plugin/ims_lti/lang/english.php
  70. 14
      plugin/ims_lti/lang/french.php
  71. 16
      plugin/ims_lti/lang/spanish.php
  72. 6
      plugin/ims_lti/start.php
  73. 80
      plugin/ims_lti/view/add.tpl
  74. 83
      plugin/ims_lti/view/admin.tpl
  75. 4
      plugin/ims_lti/view/start.tpl
  76. 2
      plugin/learning_calendar/LearningCalendarPlugin.php
  77. 4
      plugin/learning_calendar/lang/english.php
  78. 10
      plugin/learning_calendar/lang/french.php
  79. 17
      plugin/learning_calendar/lang/spanish.php
  80. 6
      plugin/learning_calendar/view/calendar.tpl
  81. 29
      plugin/notebookteacher/src/NotebookTeacherPlugin.php
  82. 4
      plugin/redirection/README.md
  83. 14
      plugin/redirection/RedirectionPlugin.php
  84. 25
      plugin/rss/index.php
  85. 1
      plugin/rss/lang/english.php
  86. 2
      plugin/search_course/lib/register_course_widget.class.php
  87. 4
      plugin/sepe/src/formative-action-edit.php
  88. 2
      plugin/sepe/src/formative-action.php
  89. 5
      plugin/sepe/src/formative-actions-list.php
  90. 57
      plugin/sepe/src/identification-data-edit.php
  91. 6
      plugin/sepe/src/participant-action-edit.php
  92. 4
      plugin/sepe/src/participant-specialty-edit.php
  93. 100
      plugin/sepe/src/sepe.lib.php
  94. 2
      plugin/sepe/src/sepe_plugin.class.php
  95. 4
      plugin/sepe/src/specialty-classroom-edit.php
  96. 6
      plugin/sepe/src/specialty-tutor-edit.php
  97. 44
      plugin/studentfollowup/StudentFollowUpPlugin.php
  98. 3
      plugin/studentfollowup/lang/dutch.php
  99. 108
      plugin/studentfollowup/my_students.php
  100. 4
      plugin/studentfollowup/view/my_students.html.twig
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,7 +1,7 @@
<link href="{{ _p.web_plugin }}advanced_subscription/views/css/style.css" rel="stylesheet" type="text/css">
<script>
$(document).on('ready', function () {
$(function () {
$('#asp-close-window').on('click', function (e) {
e.preventDefault();

@ -1,17 +1,21 @@
# The Azure Active Directory Plugin
Allow authentication with Microsoft's Azure Active Directory
Allow authentication (with OAuth2) with Microsoft's Azure Active Directory.
> This plugin use the [`thenetworg/oauth2-azure`](https://github.com/TheNetworg/oauth2-azure) package.
### To configure Azure Active Directory
* [Create an Azure AD B2C tenant](https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-get-started/)
* [Register your application](https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-app-registration/)
* [Configure Facebook, Google+, Microsoft account, Amazon, and LinkedIn accounts for use in your consumer-facing applications](https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-overview/#how-to-articles)
* Create and configure an application.
* In _Authentication_ section, set an _Reply URL_ with `https://{CHAMILO_URL}/plugin/azure_active_directory/src/callback.php`.
* In _Certificates & secrets_, create a secret string (or application password). And keep copied.
### To configure this plugin
* Enable
* Application ID: Enter the Application Id assinged to your app by the Azure portal, e.g. 580e250c-8f26-49d0-bee8-1c078add1609
* Tenant: Enter the name of your B2C directory, e.g. contoso.onmicrosoft.com
* Sign up policy: Enter your sign up policy name, e.g. b2c_1_sign_up
* Sign in policy: Enter your sign in policy name, e.g. b2c_1_sign_in
* Block name: (Optional) The name to show above the buttons
* _Enable_
* _Application ID_: Enter the Application Id assinged to your app by the Azure portal.
* _Application secret_: Enter the client secret created.
* _Block name_: (Optional) The name to show above the login button.
* _Force logout button_: (Optional) Add a button to force logout from Azure.
* _Management login_: (Optional) Disable the chamilo login and enable an alternative login page for users.
You will need copy the `/plugin/azure_active_directory/layout/login_form.tpl` file to `/main/template/overrides/layout/` directory.
* _Name for the management login_: A name for the management login. By default is "Management Login".
And assign a region. Preferably `login_bottom`
And assign a region. Preferably `login_bottom`.

@ -10,23 +10,25 @@
$activeDirectoryPlugin = AzureActiveDirectory::create();
if ($activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_ENABLE) === 'true') {
$signUp = $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_SIGNIN_POLICY);
$signIn = $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_SIGNUP_POLICY);
$signUnified = $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_SIGNUNIFIED_POLICY);
$_template['block_title'] = $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_BLOCK_NAME);
if ($signUp) {
$_template['signup_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_SIGNUP);
}
$_template['signin_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_AUTHORIZE);
if ($signIn) {
$_template['signin_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_SIGNIN);
if ('true' === $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_FORCE_LOGOUT_BUTTON)) {
$_template['signout_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_LOGOUT);
}
if ($signUnified) {
$_template['signunified_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_SIGNUNIFIED);
}
$managementLoginEnabled = 'true' === $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_MANAGEMENT_LOGIN_ENABLE);
$_template['management_login_enabled'] = $managementLoginEnabled;
$_template['signout_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_SIGNOUT);
if ($managementLoginEnabled) {
$managementLoginName = $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_MANAGEMENT_LOGIN_NAME);
if (empty($managementLoginName)) {
$managementLoginName = $activeDirectoryPlugin->get_lang('ManagementLogin');
}
$_template['management_login_name'] = $managementLoginName;
}
}

@ -13,13 +13,15 @@ $strings['plugin_comment'] = 'Allow authentication with Microsoft\'s Azure Activ
$strings['enable'] = 'Enable';
$strings['app_id'] = 'Application ID';
$strings['app_id_help'] = 'Enter the Application Id assinged to your app by the Azure portal, e.g. 580e250c-8f26-49d0-bee8-1c078add1609';
$strings['tenant'] = 'Tenant';
$strings['tenant_help'] = 'Enter the name of your B2C directory, e.g. contoso.onmicrosoft.com';
$strings['signup_policy'] = 'Sign up policy';
$strings['signup_policy_help'] = 'Enter your sign up policy name, e.g.g b2c_1_sign_up';
$strings['signin_policy'] = 'Sign in policy';
$strings['signin_policy_help'] = 'Enter your sign in policy name, e.g. b2c_1_sign_in';
$strings['signunified_policy'] = 'Unified sign in and sign up policy';
$strings['signunified_policy_help'] = 'Enter your name of unified sign in and sign up policy, e.g. b2c_1_sign_unified';
$strings['app_secret'] = 'Application secret';
$strings['force_logout'] = 'Force logout button';
$strings['force_logout_help'] = 'Show a button to force logout session from Azure.';
$strings['block_name'] = 'Block name';
$strings['SignUpAndSignIn'] = 'Sign up and sign in';
$strings['management_login_enable'] = 'Management login';
$strings['management_login_enable_help'] = 'Disable the chamilo login and enable an alternative login page for users.<br>'
.'You will need copy the <code>/plugin/azure_active_directory/layout/login_form.tpl</code> file to <code>/main/template/overrides/layout/</code> directory.';
$strings['management_login_name'] = 'Name for the management login';
$strings['management_login_name_help'] = 'By default is "Management Login".';
$strings['OrganisationEmail'] = 'Organisation e-mail';
$strings['AzureId'] = 'Azure ID (mailNickname)';
$strings['ManagementLogin'] = 'Management Login';

@ -1,6 +1,8 @@
<?php
/* For license terms, see /license.txt */
use TheNetworg\OAuth2\Client\Provider\Azure;
/**
* AzureActiveDirectory plugin class.
*
@ -12,15 +14,17 @@ class AzureActiveDirectory extends Plugin
{
const SETTING_ENABLE = 'enable';
const SETTING_APP_ID = 'app_id';
const SETTING_TENANT = 'tenant';
const SETTING_SIGNUP_POLICY = 'signup_policy';
const SETTING_SIGNIN_POLICY = 'signin_policy';
const SETTING_SIGNUNIFIED_POLICY = 'signunified_policy';
const SETTING_APP_SECRET = 'app_secret';
const SETTING_BLOCK_NAME = 'block_name';
const URL_TYPE_SIGNUP = 'sign-up';
const URL_TYPE_SIGNIN = 'sign-in';
const URL_TYPE_SIGNUNIFIED = 'sign-unified';
const URL_TYPE_SIGNOUT = 'sign-out';
const SETTING_FORCE_LOGOUT_BUTTON = 'force_logout';
const SETTING_MANAGEMENT_LOGIN_ENABLE = 'management_login_enable';
const SETTING_MANAGEMENT_LOGIN_NAME = 'management_login_name';
const URL_TYPE_AUTHORIZE = 'login';
const URL_TYPE_LOGOUT = 'logout';
const EXTRA_FIELD_ORGANISATION_EMAIL = 'organisationemail';
const EXTRA_FIELD_AZURE_ID = 'azure_id';
/**
* AzureActiveDirectory constructor.
@ -30,14 +34,14 @@ class AzureActiveDirectory extends Plugin
$settings = [
self::SETTING_ENABLE => 'boolean',
self::SETTING_APP_ID => 'text',
self::SETTING_TENANT => 'text',
self::SETTING_SIGNUP_POLICY => 'text',
self::SETTING_SIGNIN_POLICY => 'text',
self::SETTING_SIGNUNIFIED_POLICY => 'text',
self::SETTING_APP_SECRET => 'text',
self::SETTING_BLOCK_NAME => 'text',
self::SETTING_FORCE_LOGOUT_BUTTON => 'boolean',
self::SETTING_MANAGEMENT_LOGIN_ENABLE => 'boolean',
self::SETTING_MANAGEMENT_LOGIN_NAME => 'text',
];
parent::__construct('1.1', 'Angel Fernando Quiroz Campos', $settings);
parent::__construct('2.1', 'Angel Fernando Quiroz Campos', $settings);
}
/**
@ -63,52 +67,53 @@ class AzureActiveDirectory extends Plugin
}
/**
* @param $urlType Type of URL to generate
* @return Azure
*/
public function getProvider()
{
$provider = new Azure([
'clientId' => $this->get(self::SETTING_APP_ID),
'clientSecret' => $this->get(self::SETTING_APP_SECRET),
'redirectUri' => api_get_path(WEB_PLUGIN_PATH).'azure_active_directory/src/callback.php',
]);
return $provider;
}
/**
* @param string $urlType Type of URL to generate
*
* @return string
*/
public function getUrl($urlType)
{
$settingsInfo = $this->get_settings();
$settings = [];
if (self::URL_TYPE_LOGOUT === $urlType) {
$provider = $this->getProvider();
foreach ($settingsInfo as $settingInfo) {
$variable = str_replace($this->get_name().'_', '', $settingInfo['variable']);
$settings[$variable] = $settingInfo['selected_value'];
return $provider->getLogoutUrl(
api_get_path(WEB_PATH)
);
}
$url = "https://login.microsoftonline.com/{$settings[self::SETTING_TENANT]}/oauth2/v2.0/";
$callback = api_get_path(WEB_PLUGIN_PATH).$this->get_name().'/src/callback.php';
if ($urlType === self::URL_TYPE_SIGNOUT) {
$action = 'logout';
$urlParams = [
'p' => $settings[self::SETTING_SIGNIN_POLICY],
'post_logout_redirect_uri' => $callback,
];
} else {
$action = 'authorize';
$policy = $settings[self::SETTING_SIGNUP_POLICY];
if ($urlType === self::URL_TYPE_SIGNIN) {
$policy = $settings[self::SETTING_SIGNIN_POLICY];
} elseif ($urlType === self::URL_TYPE_SIGNUNIFIED) {
$policy = $settings[self::SETTING_SIGNUNIFIED_POLICY];
}
$urlParams = [
'client_id' => $settings[self::SETTING_APP_ID],
'response_type' => 'id_token',
'redirect_uri' => $callback,
'scope' => 'openid',
'response_mode' => 'form_post',
'state' => time(),
'nonce' => time(),
'p' => $policy,
];
}
return api_get_path(WEB_PLUGIN_PATH).$this->get_name().'/src/callback.php';
}
return $url.$action.'?'.http_build_query($urlParams);
/**
* Create extra fields for user when installing.
*/
public function install()
{
UserManager::create_extra_field(
self::EXTRA_FIELD_ORGANISATION_EMAIL,
ExtraField::FIELD_TYPE_TEXT,
$this->get_lang('OrganisationEmail'),
''
);
UserManager::create_extra_field(
self::EXTRA_FIELD_AZURE_ID,
ExtraField::FIELD_TYPE_TEXT,
$this->get_lang('AzureId'),
''
);
}
}

@ -2,56 +2,79 @@
/* For license terms, see /license.txt */
require __DIR__.'/../../../main/inc/global.inc.php';
require_once __DIR__.'/../../../main/auth/external_login/functions.inc.php';
if (isset($_POST['error']) || empty($_REQUEST)) {
header('Location: '.api_get_path(WEB_PATH).'index.php?logout=logout');
$plugin = AzureActiveDirectory::create();
$provider = $plugin->getProvider();
if (!isset($_GET['code'])) {
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
ChamiloSession::write('oauth2state', $provider->getState());
header('Location: '.$authUrl);
exit;
}
// Check given state against previously stored one to mitigate CSRF attack
if (empty($_GET['state']) || ($_GET['state'] !== ChamiloSession::read('oauth2state'))) {
ChamiloSession::erase('oauth2state');
exit;
}
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code'],
'resource' => 'https://graph.windows.net',
]);
$me = null;
try {
$me = $provider->get("me", $token);
} catch (Exception $e) {
exit;
}
list($jwtHeader, $jwtPayload, $jwtSignature) = explode('.', $_REQUEST['id_token']);
$jwtHeader = json_decode(
base64_decode($jwtHeader)
);
$jwtPayload = json_decode(
base64_decode($jwtPayload)
);
$u = [
'firstname' => $jwtPayload->given_name,
'lastname' => $jwtPayload->family_name,
'status' => STUDENT,
'email' => $jwtPayload->emails[0],
'username' => $jwtPayload->emails[0],
'language' => 'en',
'password' => 'azure_active_directory',
'auth_source' => 'azure_active_directory '.$jwtPayload->idp,
'extra' => [],
];
$userInfo = api_get_user_info_from_email($jwtPayload->emails[0]);
if ($userInfo === false) {
// we have to create the user
$chamilo_uid = external_add_user($u);
if ($chamilo_uid !== false) {
$_user['user_id'] = $chamilo_uid;
$_user['uidReset'] = true;
$_SESSION['_user'] = $_user;
}
} else {
// User already exists, update info and login
$chamilo_uid = $userInfo['user_id'];
$u['user_id'] = $chamilo_uid;
external_update_user($u);
$_user['user_id'] = $chamilo_uid;
$_user['uidReset'] = true;
$_SESSION['_user'] = $_user;
$userInfo = [];
if (!empty($me['email'])) {
$userInfo = api_get_user_info_from_email($me['email']);
}
if (empty($userInfo) && !empty($me['email'])) {
$extraFieldValue = new ExtraFieldValue('user');
$itemValue = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
'organisationemail',
$me['email']
);
$userInfo = api_get_user_info($itemValue['item_id']);
}
if (empty($userInfo) && !empty($me['mailNickname'])) {
$extraFieldValue = new ExtraFieldValue('user');
$itemValue = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
'azure_id',
$me['mailNickname']
);
$userInfo = api_get_user_info($itemValue['item_id']);
}
if (empty($userInfo)) {
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=user_password_incorrect');
exit;
}
$_user['user_id'] = $userInfo['user_id'];
$_user['uidReset'] = true;
ChamiloSession::write('_user', $_user);
ChamiloSession::write('_user_auth_source', 'azure_active_directory');
header('Location: '.api_get_path(WEB_PATH));
exit;

@ -8,12 +8,15 @@
<a href="{{ azure_active_directory.signin_url }}" class="btn btn-default">{{ 'SignIn'|get_lang }}</a>
{% endif %}
{% if not azure_active_directory.signup_url is empty %}
<a href="{{ azure_active_directory.signup_url }}" class="btn btn-success">{{ 'SignUp'|get_lang }}</a>
{% if not azure_active_directory.signout_url is empty %}
<a href="{{ azure_active_directory.signout_url }}" class="btn btn-danger">{{ 'Logout'|get_lang }}</a>
{% endif %}
{% if not azure_active_directory.signunified_url is empty %}
<a href="{{ azure_active_directory.signunified_url }}" class="btn btn-info">{{ 'SignUpAndSignIn'|get_plugin_lang('AzureActiveDirectory') }}</a>
{% if azure_active_directory.management_login_enabled %}
<hr>
<a href="{{ _p.web_plugin ~ 'azure_active_directory/login.php' }}">
{{ azure_active_directory.management_login_name }}
</a>
{% endif %}
</div>
{% endif %}

@ -56,4 +56,8 @@ ALTER TABLE plugin_bbb_meeting ADD COLUMN interface INT NOT NULL DEFAULT 0;
ALTER TABLE plugin_bbb_room ADD COLUMN interface INT NOT NULL DEFAULT 0;
ALTER TABLE plugin_bbb_room MODIFY COLUMN in_at datetime;
ALTER TABLE plugin_bbb_room MODIFY COLUMN out_at datetime;
```
```
For version 2.8
ALTER TABLE plugin_bbb_meeting ADD COLUMN internal_meeting_id VARCHAR(255) DEFAULT NULL;

@ -30,7 +30,8 @@ $strings['ServerIsNotConfigured'] = "Videoconference server is not configured";
$strings['XUsersOnLine'] = "%s user(s) online";
$strings['host'] = 'BigBlueButton host';
$strings['host_help'] = 'This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com).';
$strings['host_help'] = 'This is the name of the server where your BigBlueButton server is running.
Might be localhost, an IP address (e.g. http://192.168.13.54) or a domain name (e.g. http://my.video.com).';
$strings['salt'] = 'BigBlueButton salt';
$strings['salt_help'] = 'This is the security key of your BigBlueButton server, which will allow your server to authentify the Chamilo installation. Refer to the BigBlueButton documentation to locate it. Try bbb-conf --salt';
@ -74,3 +75,5 @@ $strings['ParticipantsWillUseSameInterface'] = 'Participants will use the same i
$strings['SetByStudent'] = 'Set by student';
$strings['SetByTeacher'] = 'Set by teacher';
$strings['SetByDefault'] = 'Set to default interface';
$strings['allow_regenerate_recording'] = 'Allow regenerate recording';
$strings['bbb_force_record_generation'] = 'Force record generation at the end of the meeting';

@ -30,7 +30,8 @@ $strings['ServerIsNotConfigured'] = "Le serveur de vidéoconférence n'est pas c
$strings['XUsersOnLine'] = "%s utilisateurs dans la salle";
$strings['host'] = 'Hôte de BigBlueButton';
$strings['host_help'] = "C'est le nom du serveur où le serveur de vidéoconférence a été habilité. Cela peut être localhost, une adresse IP (du genre 192.168.13.54) ou un nom de domaine (du genre ma.video.com).";
$strings['host_help'] = "C'est le nom du serveur où le serveur de vidéoconférence a été habilité.
Cela peut être localhost, une adresse IP (du genre http://192.168.13.54) ou un nom de domaine (du genre http://ma.video.com).";
$strings['salt'] = 'Clef BigBlueButton';
$strings['salt_help'] = "C'est la clef de sécurité de votre serveur BigBlueButton (appelée 'salt' en anglais) qui permet à votre serveur de vérifier l'identité de votre installation de Chamilo et ainsi l'autoriser à se connecter. Veuillez vous référer à la documentation de BigBlueButton pour la localiser, ou utilisez la commande 'bbb-conf --salt' si vous disposez d'un accès en ligne de commande au serveur de vidéoconférence.";
@ -72,3 +73,4 @@ $strings['ParticipantsWillUseSameInterface'] = 'Les apprenants utiliseront la m
$strings['SetByDefault'] = 'Lancement de l\'interface par défaut';
$strings['SetByTeacher'] = 'Choisi par le professeur';
$strings['SetByStudent'] = 'Choisi par l\'apprenant';
$strings['bbb_force_record_generation'] = 'Forcer la génération de l\'enregistrement à la fin de la session';

@ -30,7 +30,7 @@ $strings['ServerIsNotConfigured'] = "Videokonferenzserver ist nicht konfiguriert
$strings['XUsersOnLine'] = "%s Benutzer online";
$strings['host'] = 'BigBlueButton host';
$strings['host_help'] = 'This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com).';
$strings['host_help'] = 'This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. http://192.168.13.54) or a domain name (e.g. http://my.video.com).';
$strings['salt'] = 'BigBlueButton salt';
$strings['salt_help'] = 'This is the security key of your BigBlueButton server, which will allow your server to authentify the Chamilo installation. Refer to the BigBlueButton documentation to locate it. Try bbb-conf --salt';

@ -30,7 +30,7 @@ $strings['ServerIsNotConfigured'] = "El servidor de videoconferencia no está co
$strings['XUsersOnLine'] = "%s usuario(s) en la sala";
$strings['host'] = 'Host de BigBlueButton';
$strings['host_help'] = 'Este es el nombre del servidor donde su servidor BigBlueButton está corriendo. Puede ser localhost, una dirección IP (ej: 192.168.13.54) o un nombre de dominio (ej: mi.video.com).';
$strings['host_help'] = 'Este es el nombre del servidor donde su servidor BigBlueButton está corriendo. Puede ser localhost, una dirección IP (ej: http://192.168.13.54) o un nombre de dominio (ej: http://mi.video.com).';
$strings['salt'] = 'Clave BigBlueButton';
$strings['salt_help'] = 'Esta es la llave de seguridad de su servidor BigBlueButton (llamada "salt" en inglés), que permitirá a su servidor de autentifica la instalación de Chamilo (como autorizada). Refiérese a la documentación de BigBlueButton para ubicarla, o use el comando "bbb-conf --salt" si tiene acceso al servidor en línea de comando.';

@ -119,7 +119,8 @@ class bbb
$this->url = str_replace($this->protocol, '', $this->url);
$urlWithProtocol = $bbb_host;
} else {
$urlWithProtocol = '://'.$bbb_host;
// We asume it's an http, if user wants to use https host must include the protocol.
$urlWithProtocol = 'http://'.$bbb_host;
}
// Setting BBB api
@ -142,8 +143,8 @@ class bbb
public function forceCIdReq($courseCode, $sessionId = 0, $groupId = 0)
{
$this->courseCode = $courseCode;
$this->sessionId = intval($sessionId);
$this->groupId = intval($groupId);
$this->sessionId = (int) $sessionId;
$this->groupId = (int) $groupId;
}
/**
@ -264,39 +265,40 @@ class bbb
if ($max < 0) {
$max = 0;
}
$this->maxUsersLimit = intval($max);
$this->maxUsersLimit = (int) $max;
}
/**
* See this file in you BBB to set up default values
* @param array $params Array of parameters that will be completed if not containing all expected variables
/var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties
*
More record information:
http://code.google.com/p/bigbluebutton/wiki/RecordPlaybackSpecification
# Default maximum number of users a meeting can have.
# Doesn't get enforced yet but is the default value when the create
# API doesn't pass a value.
defaultMaxUsers=20
# Default duration of the meeting in minutes.
# Current default is 0 (meeting doesn't end).
defaultMeetingDuration=0
# Remove the meeting from memory when the end API is called.
# This allows 3rd-party apps to recycle the meeting right-away
# instead of waiting for the meeting to expire (see below).
removeMeetingWhenEnded=false
# The number of minutes before the system removes the meeting from memory.
defaultMeetingExpireDuration=1
# The number of minutes the system waits when a meeting is created and when
# a user joins. If after this period, a user hasn't joined, the meeting is
# removed from memory.
defaultMeetingCreateJoinDuration=5
* @param array $params Array of parameters that will be completed if not containing all expected variables
*
* /var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties
*
* More record information:
* http://code.google.com/p/bigbluebutton/wiki/RecordPlaybackSpecification
*
* Default maximum number of users a meeting can have.
* Doesn't get enforced yet but is the default value when the create
* API doesn't pass a value.
* defaultMaxUsers=20
*
* Default duration of the meeting in minutes.
* Current default is 0 (meeting doesn't end).
* defaultMeetingDuration=0
*
* Remove the meeting from memory when the end API is called.
* This allows 3rd-party apps to recycle the meeting right-away
* instead of waiting for the meeting to expire (see below).
* removeMeetingWhenEnded=false
*
* The number of minutes before the system removes the meeting from memory.
* defaultMeetingExpireDuration=1
*
* The number of minutes the system waits when a meeting is created and when
* a user joins. If after this period, a user hasn't joined, the meeting is
* removed from memory.
* defaultMeetingCreateJoinDuration=5
*
* @return mixed
*/
@ -330,11 +332,6 @@ class bbb
// Each simultaneous conference room needs to have a different
// voice_bridge composed of a 5 digits number, so generating a random one
$params['voice_bridge'] = rand(10000, 99999);
if ($this->debug) {
error_log("enter create_meeting ".print_r($params, 1));
}
$params['created_at'] = api_get_utc_datetime();
$params['access_url'] = $this->accessUrl;
@ -349,14 +346,10 @@ class bbb
$id = Database::insert($this->table, $params);
if ($id) {
if ($this->debug) {
error_log("create_meeting: $id ");
}
$meetingName = isset($params['meeting_name']) ? $params['meeting_name'] : $this->getCurrentVideoConferenceName();
$welcomeMessage = isset($params['welcome_msg']) ? $params['welcome_msg'] : null;
$record = isset($params['record']) && $params['record'] ? 'true' : 'false';
$duration = isset($params['duration']) ? intval($params['duration']) : 0;
//$duration = isset($params['duration']) ? intval($params['duration']) : 0;
// This setting currently limits the maximum conference duration,
// to avoid lingering sessions on the video-conference server #6261
$duration = 300;
@ -369,38 +362,31 @@ class bbb
'dialNumber' => '', // The main number to call into. Optional.
'voiceBridge' => $params['voice_bridge'], // PIN to join voice. Required.
'webVoice' => '', // Alphanumeric to join voice. Optional.
'logoutUrl' => $this->logoutUrl,
'logoutUrl' => $this->logoutUrl.'&action=logout&remote_id='.$params['remote_id'],
'maxParticipants' => $max, // Optional. -1 = unlimitted. Not supported in BBB. [number]
'record' => $record, // New. 'true' will tell BBB to record the meeting.
'duration' => $duration, // Default = 0 which means no set duration in minutes. [number]
//'meta_category' => '', // Use to pass additional info to BBB server. See API docs.
//'meta_category' => '', // Use to pass additional info to BBB server. See API docs.
);
if ($this->debug) {
error_log("create_meeting params: ".print_r($bbbParams, 1));
}
$status = false;
$meeting = null;
while ($status === false) {
$result = $this->api->createMeetingWithXmlResponseArray(
$bbbParams
);
$result = $this->api->createMeetingWithXmlResponseArray($bbbParams);
if (isset($result) && strval($result['returncode']) == 'SUCCESS') {
if ($this->debug) {
error_log(
"create_meeting result: ".print_r($result, 1)
);
if ($this->plugin->get('allow_regenerate_recording') === 'true') {
$internalId = Database::escape_string($result['internalMeetingID']);
$sql = "UPDATE $this->table SET internal_meeting_id = '".$internalId."'
WHERE id = $id";
Database::query($sql);
}
$meeting = $this->joinMeeting($meetingName, true);
return $meeting;
}
}
return false;
}
return false;
}
@ -578,7 +564,7 @@ class bbb
}
}
if (strval($meetingIsRunningInfo['returncode']) == 'SUCCESS' &&
if (strval($meetingIsRunningInfo['returncode']) === 'SUCCESS' &&
isset($meetingIsRunningInfo['meetingName']) &&
!empty($meetingIsRunningInfo['meetingName'])
) {
@ -605,6 +591,7 @@ class bbb
$url = $this->api->getJoinMeetingURL($joinParams);
$url = $this->protocol.$url;
}
if ($this->debug) {
error_log("return url :".$url);
}
@ -626,9 +613,8 @@ class bbb
if ($this->debug) {
error_log("Failed to get any response. Maybe we can't contact the BBB server.");
}
} else {
return $result;
}
return $result;
} catch (Exception $e) {
if ($this->debug) {
error_log('Caught exception: ', $e->getMessage(), "\n");
@ -732,6 +718,8 @@ class bbb
);
}
$conditions['order'] = 'created_at ASC';
$meetingList = Database::select(
'*',
$this->table,
@ -762,7 +750,7 @@ class bbb
);
if ($meetingBBB === false) {
//checking with the remote_id didn't work, so just in case and
// Checking with the remote_id didn't work, so just in case and
// to provide backwards support, check with the id
$params = array(
'meetingId' => $meetingDB['id'],
@ -779,7 +767,7 @@ class bbb
$meetingBBB['end_url'] = $this->endUrl($meetingDB);
if (isset($meetingBBB['returncode']) && (string) $meetingBBB['returncode'] == 'FAILED') {
if (isset($meetingBBB['returncode']) && (string) $meetingBBB['returncode'] === 'FAILED') {
if ($meetingDB['status'] == 1 && $this->isConferenceManager()) {
$this->endMeeting($meetingDB['id'], $courseCode);
}
@ -800,35 +788,35 @@ class bbb
}
$record = [];
if (empty($meetingDB['video_url'])) {
$recordingParams = ['meetingId' => $mId];
$records = $this->api->getRecordingsWithXmlResponseArray($recordingParams);
if (!empty($records)) {
if (!isset($records['messageKey']) || $records['messageKey'] != 'noRecordings') {
$record = end($records);
if (!is_array($record) || !isset($record['recordId'])) {
continue;
}
$recordingParams = ['meetingId' => $mId];
$records = $this->api->getRecordingsWithXmlResponseArray($recordingParams);
if (!empty($records)) {
if (!isset($records['messageKey']) || $records['messageKey'] !== 'noRecordings') {
$record = end($records);
if (!is_array($record) || !isset($record['recordId'])) {
continue;
}
if (!empty($record['playbackFormatUrl'])) {
$this->updateMeetingVideoUrl($meetingDB['id'], $record['playbackFormatUrl']);
}
if (!$this->isConferenceManager()) {
$record = [];
}
if (!$this->isConferenceManager()) {
$record = [];
}
}
} else {
$record['playbackFormatUrl'] = $meetingDB['video_url'];
}
$recordLink = isset($record['playbackFormatUrl']) && !empty($record['playbackFormatUrl'])
? Display::url(
if (isset($record['playbackFormatUrl']) && !empty($record['playbackFormatUrl'])) {
$recordLink = Display::url(
$this->plugin->get_lang('ViewRecord'),
$record['playbackFormatUrl'],
['target' => '_blank']
)
: $this->plugin->get_lang('NoRecording');
['target' => '_blank', 'class' => 'btn btn-default']
);
} else {
$recordLink = $this->plugin->get_lang('NoRecording');
}
if ($isAdminReport) {
$this->forceCIdReq(
@ -1013,7 +1001,8 @@ class bbb
}
/**
* Generated a moderator password for the meeting
* Generated a moderator password for the meeting.
*
* @param string $courseCode
*
* @return string A password for the moderation of the videoconference
@ -1034,7 +1023,8 @@ class bbb
}
/**
* Get users online in the current course room
* Get users online in the current course room.
*
* @return int The number of users currently connected to the videoconference
* @assert () > -1
*/
@ -1104,15 +1094,73 @@ class bbb
if (!empty($info) && isset($info['participantCount'])) {
return $info['participantCount'];
}
return 0;
}
/**
* Deletes a previous recording of a meeting
* @param int $id
* @param string $recordId
*
* @return bool
*/
public function regenerateRecording($id, $recordId = '')
{
if ($this->plugin->get('allow_regenerate_recording') !== 'true') {
return false;
}
if (empty($id)) {
return false;
}
$meetingData = Database::select(
'*',
$this->table,
array('where' => array('id = ?' => array($id))),
'first'
);
// Check if there are recordings for this meeting
$recordings = $this->api->getRecordings(['meetingId' => $meetingData['remote_id']]);
if (!empty($recordings) && isset($recordings['messageKey']) && $recordings['messageKey'] === 'noRecordings') {
// Regenerate the meeting id
if (!empty($meetingData['internal_meeting_id'])) {
return $this->api->generateRecording(['recordId' => $meetingData['internal_meeting_id']]);
}
/*$pass = $this->getModMeetingPassword();
$info = $this->getMeetingInfo(['meetingId' => $meetingData['remote_id'], 'password' => $pass]);
if (!empty($info) && isset($info['internalMeetingID'])) {
return $this->api->generateRecording(['recordId' => $meetingData['internal_meeting_id']]);
}*/
return false;
} else {
if (!empty($recordings['records'])) {
$recordExists = false;
foreach ($recordings['records'] as $record) {
if ($recordId == $record['recordId']) {
$recordExists = true;
break;
}
}
if ($recordExists) {
return $this->api->generateRecording(['recordId' => $recordId]);
}
}
}
return false;
}
/**
* Deletes a recording of a meeting
*
* @param int $id ID of the recording
* @return array ?
*
* @return bool
*
* @assert () === false
* @todo Also delete links and agenda items created from this recording
*/
@ -1131,24 +1179,20 @@ class bbb
$delete = false;
// Check if there are recordings for this meeting
$recordings = $this->api->getRecordingsWithXmlResponseArray(['meetingId' => $meetingData['remote_id']]);
$recordings = $this->api->getRecordings(['meetingId' => $meetingData['remote_id']]);
if (!empty($recordings) && isset($recordings['messageKey']) && $recordings['messageKey'] == 'noRecordings') {
$delete = true;
} else {
$recordingParams = array(
/*
* NOTE: Set the recordId below to a valid id after you have
* created a recorded meeting, and received a real recordID
* back from your BBB server using the
* getRecordingsWithXmlResponseArray method.
*/
// REQUIRED - We have to know which recording:
'recordId' => $meetingData['remote_id'],
);
$result = $this->api->deleteRecordingsWithXmlResponseArray($recordingParams);
if (!empty($result) && isset($result['deleted']) && $result['deleted'] === 'true') {
$delete = true;
$recordsToDelete = [];
if (!empty($recordings['records'])) {
foreach ($recordings['records'] as $record) {
$recordsToDelete[] = $record['recordId'];
}
$recordingParams = ['recordId' => implode(',', $recordsToDelete)];
$result = $this->api->deleteRecordingsWithXmlResponseArray($recordingParams);
if (!empty($result) && isset($result['deleted']) && $result['deleted'] === 'true') {
$delete = true;
}
}
}
@ -1384,6 +1428,49 @@ class bbb
return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=delete_record&id='.$meeting['id'];
}
/**
* @param array $meeting
* @param array $recordInfo
*
* @return string
*/
public function regenerateRecordUrl($meeting, $recordInfo)
{
if ($this->plugin->get('allow_regenerate_recording') !== 'true') {
return '';
}
if (!isset($meeting['id'])) {
return '';
}
if (empty($recordInfo) || (!empty($recordInfo['recordId']) && !isset($recordInfo['recordId']))) {
return '';
}
return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().
'&action=regenerate_record&id='.$meeting['id'].'&record_id='.$recordInfo['recordId'];
}
/**
* @param array $meeting
*
* @return string
*/
public function regenerateRecordUrlFromMeeting($meeting)
{
if ($this->plugin->get('allow_regenerate_recording') !== 'true') {
return '';
}
if (!isset($meeting['id'])) {
return '';
}
return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().
'&action=regenerate_record&id='.$meeting['id'];
}
/**
* @param array $meeting
* @return string
@ -1394,7 +1481,8 @@ class bbb
return '';
}
return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=copy_record_to_link_tool&id='.$meeting['id'];
return api_get_path(WEB_PLUGIN_PATH).
'bbb/listing.php?'.$this->getUrlParams().'&action=copy_record_to_link_tool&id='.$meeting['id'];
}
/**
@ -1433,6 +1521,25 @@ class bbb
return $meetingData;
}
/**
* Get the meeting info.
*
* @param int $id
*
* @return array
*/
public function getMeetingByRemoteId($id)
{
$meetingData = Database::select(
'*',
'plugin_bbb_meeting',
array('where' => array('remote_id = ?' => $id)),
'first'
);
return $meetingData;
}
/**
* @param int $meetingId
* @return array
@ -1491,8 +1598,9 @@ class bbb
/**
* @param array $meetingInfo
* @param array $recordInfo
* @param bool $isGlobal
* @param bool $isAdminReport
* @param bool $isGlobal
* @param bool $isAdminReport
*
* @return array
*/
private function getActionLinks(
@ -1513,14 +1621,29 @@ class bbb
);
$links = [];
if ($this->plugin->get('allow_regenerate_recording') === 'true' && $meetingInfo['record'] == 1) {
if (!empty($recordInfo)) {
$links[] = Display::url(
Display::return_icon('reload.png', get_lang('RegenerateRecord')),
$this->regenerateRecordUrl($meetingInfo, $recordInfo)
);
} else {
$links[] = Display::url(
Display::return_icon('reload.png', get_lang('RegenerateRecord')),
$this->regenerateRecordUrlFromMeeting($meetingInfo)
);
}
}
if (empty($recordInfo)) {
if (!$isAdminReport) {
$links[] = Display::url(
Display::return_icon('delete.png', get_lang('Delete')),
$this->deleteRecordUrl($meetingInfo)
);
$links[] = $linkVisibility;
if ($meetingInfo['status'] == 0) {
$links[] = Display::url(
Display::return_icon('delete.png', get_lang('Delete')),
$this->deleteRecordUrl($meetingInfo)
);
$links[] = $linkVisibility;
}
return $links;
} else {
@ -1566,6 +1689,7 @@ class bbb
}
}
if (!$isAdminReport) {
$links[] = Display::url(
Display::return_icon('delete.png', get_lang('Delete')),
@ -1579,6 +1703,7 @@ class bbb
);
}
return $links;
}

@ -37,32 +37,27 @@ Versions:
-- See included samples for usage examples
*/
/* _______________________________________________________________________*/
/* get the config values */
//require_once "config.php";
class BigBlueButtonBN {
class BigBlueButtonBN
{
private $_securitySalt;
private $_bbbServerBaseUrl;
/* ___________ General Methods for the BigBlueButton Class __________ */
function __construct() {
/*
Establish just our basic elements in the constructor:
*/
public function __construct()
{
/*
Establish just our basic elements in the constructor:
*/
// BASE CONFIGS - set these for your BBB server in config.php and they will
// simply flow in here via the constants:
$this->_securitySalt = CONFIG_SECURITY_SALT;
$this->_bbbServerBaseUrl = CONFIG_SERVER_BASE_URL;
}
private function _processXmlResponse($url){
/*
A private utility method used by other public methods to process XML responses.
*/
private function _processXmlResponse($url)
{
/*
A private utility method used by other public methods to process XML responses.
*/
if (extension_loaded('curl')) {
$ch = curl_init() or die ( curl_error($ch) );
$timeout = 10;
@ -74,7 +69,7 @@ class BigBlueButtonBN {
curl_close( $ch );
if($data)
return (@new SimpleXMLElement($data));
return (new SimpleXMLElement($data));
else
return false;
}
@ -143,7 +138,8 @@ class BigBlueButtonBN {
return ( $creationUrl.$params.'&checksum='.sha1("create".$params.$this->_securitySalt) );
}
public function createMeetingWithXmlResponseArray($creationParams) {
public function createMeetingWithXmlResponseArray($creationParams)
{
/*
USAGE:
$creationParams = array(
@ -165,27 +161,28 @@ class BigBlueButtonBN {
$xml = $this->_processXmlResponse($this->getCreateMeetingURL($creationParams));
if ($xml) {
if($xml->meetingID)
return array(
'returncode' => $xml->returncode->__toString(),
'message' => $xml->message->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'meetingId' => $xml->meetingID->__toString(),
'attendeePw' => $xml->attendeePW->__toString(),
'moderatorPw' => $xml->moderatorPW->__toString(),
'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded->__toString(),
'createTime' => $xml->createTime->__toString()
);
else
return array(
'returncode' => $xml->returncode->__toString(),
'message' => $xml->message->__toString(),
'messageKey' => $xml->messageKey->__toString()
);
}
else {
return null;
}
if ($xml->meetingID) {
return array(
'returncode' => $xml->returncode->__toString(),
'message' => $xml->message->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'meetingId' => $xml->meetingID->__toString(),
'attendeePw' => $xml->attendeePW->__toString(),
'moderatorPw' => $xml->moderatorPW->__toString(),
'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded->__toString(),
'createTime' => $xml->createTime->__toString(),
'internalMeetingID' => $xml->internalMeetingID->__toString()
);
} else {
return array(
'returncode' => $xml->returncode->__toString(),
'message' => $xml->message->__toString(),
'messageKey' => $xml->messageKey->__toString(),
);
}
} else {
return null;
}
}
public function getJoinMeetingURL($joinParams) {
@ -396,8 +393,7 @@ class BigBlueButtonBN {
'message' => $xml->message->__toString()
);
return $result;
}
else {
} else {
// In this case, we have success and meeting info:
$result = array(
'returncode' => $xml->returncode->__toString(),
@ -415,7 +411,9 @@ class BigBlueButtonBN {
'participantCount' => $xml->participantCount->__toString(),
'maxUsers' => $xml->maxUsers->__toString(),
'moderatorCount' => $xml->moderatorCount->__toString(),
'internalMeetingID' => $xml->internalMeetingID->__toString()
);
// Then interate through attendee results and return them as part of the array:
foreach ($xml->attendees->attendee as $a) {
$result[] = array(
@ -509,6 +507,69 @@ class BigBlueButtonBN {
}
}
/**
* @param $array recordingParams
*
* @return array|null
*/
public function getRecordings($recordingParams)
{
/* USAGE:
$recordingParams = array(
'meetingId' => '1234', -- OPTIONAL - comma separate if multiple ids
);
NOTE: 'duration' DOES work when creating a meeting, so if you set duration
when creating a meeting, it will kick users out after the duration. Should
probably be required in user code when 'recording' is set to true.
*/
$xml = $this->_processXmlResponse($this->getRecordingsUrl($recordingParams));
if($xml) {
// If we don't get a success code or messageKey, find out why:
if (($xml->returncode != 'SUCCESS') || ($xml->messageKey == null)) {
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
return $result;
}
else {
// In this case, we have success and recording info:
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
$result['records'] = [];
if (!empty($xml->recordings->recording)) {
foreach ($xml->recordings->recording as $r) {
$result['records'][] = array(
'recordId' => $r->recordID->__toString(),
'meetingId' => $r->meetingID->__toString(),
'name' => $r->name->__toString(),
'published' => $r->published->__toString(),
'startTime' => $r->startTime->__toString(),
'endTime' => $r->endTime->__toString(),
'playbackFormatType' => $r->playback->format->type->__toString(),
'playbackFormatUrl' => $r->playback->format->url->__toString(),
'playbackFormatLength' => $r->playback->format->length->__toString(),
'metadataTitle' => $r->metadata->title->__toString(),
'metadataSubject' => $r->metadata->subject->__toString(),
'metadataDescription' => $r->metadata->description->__toString(),
'metadataCreator' => $r->metadata->creator->__toString(),
'metadataContributor' => $r->metadata->contributor->__toString(),
'metadataLanguage' => $r->metadata->language->__toString(),
);
}
}
return $result;
}
}
return null;
}
public function getPublishRecordingsUrl($recordingParams) {
/* USAGE:
$recordingParams = array(
@ -577,8 +638,30 @@ class BigBlueButtonBN {
}
/** USAGE:
* $recordingParams = array(
* 'recordId' => '1234', -- REQUIRED - comma separate if multiple ids
* );
*/
public function generateRecording($recordingParams)
{
if (empty($recordingParams)) {
return false;
}
$recordingsUrl = $this->_bbbServerBaseUrl.'../demo/regenerateRecord.jsp?';
$params = 'recordID='.urlencode($recordingParams['recordId']);
$url = $recordingsUrl.$params.'&checksum='.sha1('regenerateRecord'.$params.$this->_securitySalt);
} // END OF BIGBLUEBUTTON CLASS
$ch = curl_init() or die ( curl_error($ch) );
$timeout = 10;
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec( $ch );
curl_close( $ch );
?>
return true;
}
}

@ -33,6 +33,10 @@ class BBBPlugin extends Plugin
[
'name' => 'bbb_enable_conference_in_groups',
'type' => 'checkbox',
],
[
'name' => 'bbb_force_record_generation',
'type' => 'checkbox',
]
];
@ -42,7 +46,7 @@ class BBBPlugin extends Plugin
protected function __construct()
{
parent::__construct(
'2.7',
'2.8.1',
'Julio Montoya, Yannick Warnier, Angel Fernando Quiroz Campos',
[
'tool_enable' => 'boolean',
@ -79,7 +83,8 @@ class BBBPlugin extends Plugin
self::LAUNCH_TYPE_SET_BY_STUDENT => 'SetByStudent',
],
'translate_options' => true, // variables will be translated using the plugin->get_lang
]
],
'allow_regenerate_recording' => 'boolean',
]
);
@ -95,9 +100,9 @@ class BBBPlugin extends Plugin
if ($variable === 'bbb_enable_conference_in_groups') {
if ($this->get('enable_conference_in_course_groups') === 'true') {
return true;
} else {
return false;
}
return false;
}
return true;
@ -133,12 +138,13 @@ class BBBPlugin extends Plugin
welcome_msg VARCHAR(255) NOT NULL DEFAULT '',
session_id INT unsigned DEFAULT 0,
remote_id CHAR(30),
internal_meeting_id VARCHAR(255) DEFAULT NULL,
visibility TINYINT NOT NULL DEFAULT 1,
voice_bridge INT NOT NULL DEFAULT 1,
access_url INT NOT NULL DEFAULT 1,
video_url TEXT NULL,
has_video_m4v TINYINT NOT NULL DEFAULT 0,
interface INT NOT NULL DEFAULT 0
interface INT NOT NULL DEFAULT 0
)";
Database::query($sql);
@ -280,7 +286,7 @@ class BBBPlugin extends Plugin
{
$data = [
'text' => $this->get_lang('EnterConferenceFlash'),
'url' => $conferenceUrl . '&interface=' . self::INTERFACE_FLASH,
'url' => $conferenceUrl.'&interface='.self::INTERFACE_FLASH,
'icon' => 'resources/img/64/videoconference_flash.png'
];
return $data;
@ -295,8 +301,8 @@ class BBBPlugin extends Plugin
{
$data = [
'text' => $this->get_lang('EnterConferenceHTML5'),
'url' => $conferenceUrl . '&interface=' . self::INTERFACE_HTML5,
'icon' => 'resources/img/64/videoconference_html5.png'
'url' => $conferenceUrl.'&interface='.self::INTERFACE_HTML5,
'icon' => 'resources/img/64/videoconference_html5.png',
];
return $data;
}

@ -27,6 +27,9 @@ if ($bbb->isGlobalConference()) {
api_protect_course_script(true);
}
$courseInfo = api_get_course_info();
$courseCode = isset($courseInfo['code']) ? $courseInfo['code'] : '';
$message = '';
if ($conferenceManager) {
switch ($action) {
@ -62,6 +65,22 @@ if ($conferenceManager) {
$message = Display::return_message(get_lang('Error'), 'error');
}
break;
case 'regenerate_record':
if ($plugin->get('allow_regenerate_recording') !== 'true') {
api_not_allowed(true);
}
$recordId = isset($_GET['record_id']) ? $_GET['record_id'] : '';
$result = $bbb->regenerateRecording($_GET['id'], $recordId);
if ($result) {
$message = Display::return_message(get_lang('Success'), 'success');
} else {
$message = Display::return_message(get_lang('Error'), 'error');
}
Display::addFlash($message);
header('Location: '.$bbb->getListingUrl());
exit;
break;
case 'delete_record':
$result = $bbb->deleteRecording($_GET['id']);
if ($result) {
@ -77,9 +96,7 @@ if ($conferenceManager) {
case 'end':
$bbb->endMeeting($_GET['id']);
$message = Display::return_message(
$plugin->get_lang('MeetingClosed').'<br />'.$plugin->get_lang(
'MeetingClosedComment'
),
$plugin->get_lang('MeetingClosed').'<br />'.$plugin->get_lang('MeetingClosedComment'),
'success',
false
);
@ -101,10 +118,35 @@ if ($conferenceManager) {
exit;
break;
case 'publish':
$result = $bbb->publishMeeting($_GET['id']);
$bbb->publishMeeting($_GET['id']);
Display::addFlash(Display::return_message(get_lang('Updated')));
header('Location: '.$bbb->getListingUrl());
exit;
break;
case 'unpublish':
$result = $bbb->unpublishMeeting($_GET['id']);
$bbb->unpublishMeeting($_GET['id']);
Display::addFlash(Display::return_message(get_lang('Updated')));
header('Location: '.$bbb->getListingUrl());
exit;
break;
case 'logout':
if ($plugin->get('allow_regenerate_recording') !== 'true') {
api_not_allowed(true);
}
$allow = api_get_course_setting('bbb_force_record_generation', $courseCode) == 1 ? true : false;
if ($allow) {
$result = $bbb->getMeetingByRemoteId($_GET['remote_id']);
if (!empty($result)) {
$result = $bbb->regenerateRecording($result['id']);
if ($result) {
Display::addFlash(Display::return_message(get_lang('Success')));
} else {
Display::addFlash(Display::return_message(get_lang('Error'), 'error'));
}
}
}
header('Location: '.$bbb->getListingUrl());
exit;
break;
default:
break;
@ -137,7 +179,6 @@ if (($meetingExists || $userCanSeeJoinButton) && ($maxUsers == 0 || $maxUsers >
$showJoinButton = true;
}
$conferenceUrl = $bbb->getConferenceUrl();
$courseInfo = api_get_course_info();
$formToString = '';
@ -148,7 +189,7 @@ if ($bbb->isGlobalConference() === false &&
) {
$url = api_get_self().'?'.api_get_cidreq(true, false).'&gidReq=';
$htmlHeadXtra[] = '<script>
$(document).ready(function(){
$(document).ready(function() {
$("#group_select").on("change", function() {
var groupId = $(this).find("option:selected").val();
var url = "'.$url.'";
@ -180,18 +221,6 @@ if ($bbb->isGlobalConference() === false &&
}
}
$tpl = new Template($tool_name);
$tpl->assign('allow_to_edit', $conferenceManager);
$tpl->assign('meetings', $meetings);
$tpl->assign('conference_url', $conferenceUrl);
$tpl->assign('users_online', $usersOnline);
$tpl->assign('conference_manager', $conferenceManager);
$tpl->assign('max_users_limit', $maxUsers);
$tpl->assign('bbb_status', $status);
$tpl->assign('show_join_button', $showJoinButton);
$tpl->assign('message', $message);
$tpl->assign('form', $formToString);
// Default URL
$urlList[] = Display::url(
$plugin->get_lang('EnterConference'),
@ -200,7 +229,7 @@ $urlList[] = Display::url(
);
$type = $plugin->get('launch_type');
$warningIntefaceMessage = '';
$warningInterfaceMessage = '';
$showClientOptions = false;
switch ($type) {
@ -215,7 +244,7 @@ switch ($type) {
case BBBPlugin::LAUNCH_TYPE_SET_BY_TEACHER:
if ($conferenceManager) {
$urlList = $plugin->getUrlInterfaceLinks($conferenceUrl);
$warningIntefaceMessage = Display::return_message($plugin->get_lang('ParticipantsWillUseSameInterface'));
$warningInterfaceMessage = Display::return_message($plugin->get_lang('ParticipantsWillUseSameInterface'));
$showClientOptions = true;
} else {
$meetingInfo = $bbb->getMeetingByName($videoConferenceName);
@ -235,35 +264,31 @@ switch ($type) {
$showClientOptions = true;
} else {
if ($meetingExists) {
$meetingInfo = $bbb->getMeetingByName($videoConferenceName);
$meetinUserInfo = $bbb->getMeetingParticipantInfo($meetingInfo['id'], api_get_user_id());
$urlList = $plugin->getUrlInterfaceLinks($conferenceUrl);
$showClientOptions = true;
/*if (empty($meetinUserInfo)) {
$url = $plugin->getUrlInterfaceLinks($conferenceUrl);
} else {
switch ($meetinUserInfo['interface']) {
case BBBPlugin::INTERFACE_FLASH:
$url = $plugin->getFlashUrl($conferenceUrl);
break;
case BBBPlugin::INTERFACE_HTML5:
$url = $plugin->getHtmlUrl($conferenceUrl);
break;
}
}*/
}
}
break;
}
$tpl = new Template($tool_name);
$tpl->assign('allow_to_edit', $conferenceManager);
$tpl->assign('meetings', $meetings);
$tpl->assign('conference_url', $conferenceUrl);
$tpl->assign('users_online', $usersOnline);
$tpl->assign('conference_manager', $conferenceManager);
$tpl->assign('max_users_limit', $maxUsers);
$tpl->assign('bbb_status', $status);
$tpl->assign('show_join_button', $showJoinButton);
$tpl->assign('message', $message);
$tpl->assign('form', $formToString);
$tpl->assign('enter_conference_links', $urlList);
$tpl->assign('warning_inteface_msg', $warningIntefaceMessage);
$tpl->assign('warning_inteface_msg', $warningInterfaceMessage);
$tpl->assign('show_client_options', $showClientOptions);
$listing_tpl = 'bbb/view/listing.tpl';
$content = $tpl->fetch($listing_tpl);
$actionLinks = '';
if (api_is_platform_admin()) {
$actionLinks .= Display::toolbarButton(

@ -1,4 +1,4 @@
$(document).on('ready', function () {
$(function () {
$('.check-meeting-video').on('click', function (e) {
e.preventDefault();

@ -11,6 +11,11 @@ require_once __DIR__.'/../../vendor/autoload.php';
$course_plugin = 'bbb'; //needed in order to load the plugin lang variables
require_once __DIR__.'/config.php';
$logInfo = [
'tool' => 'Videoconference',
];
Event::registerLog($logInfo);
$tool_name = get_lang('Videoconference');
$tpl = new Template($tool_name);
@ -59,7 +64,6 @@ if ($bbb->pluginEnabled) {
$meetingParams = [];
$meetingParams['meeting_name'] = $bbb->getCurrentVideoConferenceName();
$meetingParams['interface'] = $interface;
if ($bbb->meetingExists($meetingParams['meeting_name'])) {
$joinUrl = $bbb->joinMeeting($meetingParams['meeting_name']);
if ($joinUrl) {

@ -118,15 +118,12 @@
<table class="table">
<tr>
<!-- th>#</th -->
<th>{{ 'CreatedAt'| get_plugin_lang('BBBPlugin') }}</th>
<th>{{ 'Status'| get_lang }}</th>
<th>{{ 'Records'| get_plugin_lang('BBBPlugin') }}</th>
{% if allow_to_edit %}
<th>{{ 'Actions'| get_lang }}</th>
{% endif %}
</tr>
{% for meeting in meetings %}
<tr>
@ -151,7 +148,6 @@
{{ 'NoRecording'|get_plugin_lang('BBBPlugin') }}
{% endif %}
</td>
{% if allow_to_edit %}
<td>
{% if meeting.status == 1 %}
@ -159,8 +155,9 @@
{{ 'CloseMeeting'|get_plugin_lang('BBBPlugin') }}
</a>
{% else %}
{{ meeting.action_links }}
{% endif %}
{{ meeting.action_links }}
</td>
{% endif %}

@ -1,3 +1,13 @@
v5.0 - 2019-02-06
====
This version includes two additional modules (taxes and invoices),
which can be enabled from the configuration.
The file update.php must be executed to update the structure of the tables
in the database.
v4.0 - 2017-04-25
====

@ -90,6 +90,11 @@ $itemTable->addColumn(
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true]
);
$itemTable->addColumn(
'tax_perc',
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true, 'notnull' => false]
);
$itemTable->setPrimaryKey(['id']);
$itemTable->addForeignKeyConstraint(
$currencyTable,
@ -195,6 +200,21 @@ $saleTable->addColumn(
\Doctrine\DBAL\Types\Type::DECIMAL,
['scale' => 2]
);
$saleTable->addColumn(
'price_without_tax',
\Doctrine\DBAL\Types\Type::DECIMAL,
['scale' => 2, 'notnull' => false]
);
$saleTable->addColumn(
'tax_perc',
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true, 'notnull' => false]
);
$saleTable->addColumn(
'tax_amount',
\Doctrine\DBAL\Types\Type::DECIMAL,
['scale' => 2, 'notnull' => false]
);
$saleTable->addColumn(
'currency_id',
\Doctrine\DBAL\Types\Type::INTEGER,
@ -202,6 +222,7 @@ $saleTable->addColumn(
);
$saleTable->addColumn('status', \Doctrine\DBAL\Types\Type::INTEGER);
$saleTable->addColumn('payment_type', \Doctrine\DBAL\Types\Type::INTEGER);
$saleTable->addColumn('invoice', \Doctrine\DBAL\Types\Type::INTEGER);
$saleTable->setPrimaryKey(['id']);
$saleTable->addForeignKeyConstraint(
$currencyTable,
@ -250,6 +271,21 @@ $servicesNodeTable->addColumn(
\Doctrine\DBAL\Types\Type::DECIMAL,
['scale' => 2]
);
$servicesNodeTable->addColumn(
'price_without_tax',
\Doctrine\DBAL\Types\Type::DECIMAL,
['scale' => 2, 'notnull' => false]
);
$servicesNodeTable->addColumn(
'tax_perc',
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true, 'notnull' => false]
);
$servicesNodeTable->addColumn(
'tax_amount',
\Doctrine\DBAL\Types\Type::DECIMAL,
['scale' => 2, 'notnull' => false]
);
$servicesNodeTable->addColumn('node_type', \Doctrine\DBAL\Types\Type::INTEGER);
$servicesNodeTable->addColumn('node_id', \Doctrine\DBAL\Types\Type::INTEGER);
$servicesNodeTable->addColumn('buyer_id', \Doctrine\DBAL\Types\Type::INTEGER);
@ -265,6 +301,7 @@ $servicesNodeTable->addColumn(
);
$servicesNodeTable->addColumn('status', \Doctrine\DBAL\Types\Type::INTEGER);
$servicesNodeTable->addColumn('payment_type', \Doctrine\DBAL\Types\Type::INTEGER);
$servicesNodeTable->addColumn('invoice', \Doctrine\DBAL\Types\Type::INTEGER);
$servicesNodeTable->setPrimaryKey(['id']);
$servicesNodeTable->addForeignKeyConstraint(
$servicesTable,
@ -291,8 +328,40 @@ $globalTable->addColumn(
['autoincrement' => true, 'unsigned' => true]
);
$globalTable->addColumn('terms_and_conditions', \Doctrine\DBAL\Types\Type::TEXT);
$globalTable->addColumn('global_tax_perc', \Doctrine\DBAL\Types\Type::INTEGER);
$globalTable->addColumn('tax_applies_to', \Doctrine\DBAL\Types\Type::INTEGER);
$globalTable->addColumn('tax_name', \Doctrine\DBAL\Types\Type::STRING);
$globalTable->addColumn('seller_name', \Doctrine\DBAL\Types\Type::STRING);
$globalTable->addColumn('seller_id', \Doctrine\DBAL\Types\Type::STRING);
$globalTable->addColumn('seller_address', \Doctrine\DBAL\Types\Type::STRING);
$globalTable->addColumn('seller_email', \Doctrine\DBAL\Types\Type::STRING);
$globalTable->addColumn('next_number_invoice', \Doctrine\DBAL\Types\Type::INTEGER);
$globalTable->addColumn('invoice_series', \Doctrine\DBAL\Types\Type::STRING);
$globalTable->addColumn('sale_email', \Doctrine\DBAL\Types\Type::STRING);
$globalTable->setPrimaryKey(['id']);
$invoiceTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_INVOICE);
$invoiceTable->addColumn(
'id',
\Doctrine\DBAL\Types\Type::INTEGER,
['autoincrement' => true, 'unsigned' => true]
);
$invoiceTable->addColumn('sale_id', \Doctrine\DBAL\Types\Type::INTEGER);
$invoiceTable->addColumn('is_service', \Doctrine\DBAL\Types\Type::INTEGER);
$invoiceTable->addColumn(
'num_invoice',
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true, 'notnull' => false]
);
$invoiceTable->addColumn(
'year',
\Doctrine\DBAL\Types\Type::INTEGER,
['unsigned' => true, 'notnull' => false]
);
$invoiceTable->addColumn('serie', \Doctrine\DBAL\Types\Type::STRING);
$invoiceTable->addColumn('date_invoice', \Doctrine\DBAL\Types\Type::DATETIME);
$invoiceTable->setPrimaryKey(['id']);
$queries = $pluginSchema->toSql($platform);
foreach ($queries as $query) {
@ -631,3 +700,21 @@ foreach ($currencies as $currency) {
]
);
}
$fieldlabel = 'buycourses_company';
$fieldtype = '1';
$fieldtitle = BuyCoursesPlugin::get_lang('Company');
$fielddefault = '';
$field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
$fieldlabel = 'buycourses_vat';
$fieldtype = '1';
$fieldtitle = BuyCoursesPlugin::get_lang('VAT');
$fielddefault = '';
$field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
$fieldlabel = 'buycourses_address';
$fieldtype = '1';
$fieldtitle = BuyCoursesPlugin::get_lang('Address');
$fielddefault = '';
$field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);

@ -47,7 +47,7 @@ $strings['CancelOrder'] = "Anular ordem";
$strings['BankAccountInformation'] = "Detalhes da conta bancária";
$strings['BankAccount'] = "Contas bancárias";
$strings['OnceItIsConfirmedYouWillReceiveAnEmailWithTheBankInformationAndAnOrderReference'] = "Uma vez confirmada, você receberá um e-mail com os dados bancários e uma referência de ordem.";
$strings['SubscriptionToCourseXSuccessful'] = "Sua inscrição para \"%s\ foi concluída com sucesso.";
$strings['SubscriptionToCourseXSuccessful'] = "Sua inscrição para <a href=\"%s\"><strong>\"%s\"</strong></a> foi concluída com sucesso.";
$strings['OrderCanceled'] = "Ordem cancelada";
$strings['OrderStatus'] = "Status do pedido";
$strings['SearchByStatus'] = "Pesquisar por estado";

@ -82,7 +82,7 @@ $strings['CancelOrder'] = "Annuleer order";
$strings['BankAccountInformation'] = "Bankgegevens";
$strings['BankAccount'] = "Bankrekening";
$strings['OnceItIsConfirmedYouWillReceiveAnEmailWithTheBankInformationAndAnOrderReference'] = "Eenmaal bevestigd, ontvangt u een e-mail met de bankgegevens en een orderreferentie.";
$strings['SubscriptionToCourseXSuccessful'] = "Uw aankoop op \"%s \" werd met succes afgerond.";
$strings['SubscriptionToCourseXSuccessful'] = "Uw aankoop op <a href=\"%s\"><strong>\"%s\"</strong></a> werd met succes afgerond.";
$strings['OrderCanceled'] = "Order geannuleerd";
$strings['OrderStatus'] = "Bestelstatus";
$strings['PayoutStatus'] = "Betalingsstatus";

@ -9,6 +9,8 @@ $strings['paypal_enable'] = "Enable PayPal";
$strings['commissions_enable'] = "Enable Commissions";
$strings['transfer_enable'] = "Enable bank transfer";
$strings['unregistered_users_enable'] = "Allow anonymous users";
$strings['invoicing_enable'] = "Enable Invoicing";
$strings['tax_enable'] = "Enable Taxation";
$strings['Free'] = "FREE";
$strings['PaypalPayoutCommissions'] = "Paypal Payout Commissions";
$strings['MyPayouts'] = "My payments";
@ -47,6 +49,7 @@ $strings['PayoutStatusCompleted'] = "Payment completed";
$strings['PayoutsTotalPending'] = "Pending payments:";
$strings['PayoutsTotalCanceled'] = "Cancelled payments:";
$strings['PayoutsTotalCompleted'] = "Completed payments:";
$strings['Total'] = "Total";
$strings['TotalAmount'] = "Total amount:";
$strings['CourseListOnSale'] = "List of courses on sale";
$strings['AvailableCourses'] = "Available Courses";
@ -82,7 +85,7 @@ $strings['CancelOrder'] = "Cancel order";
$strings['BankAccountInformation'] = "Bank account details";
$strings['BankAccount'] = "Bank account";
$strings['OnceItIsConfirmedYouWillReceiveAnEmailWithTheBankInformationAndAnOrderReference'] = "Once confirmed, you will receive an e-mail with the bank details and an order reference.";
$strings['SubscriptionToCourseXSuccessful'] = "Your subscription to \"%s\" was completed successfully.";
$strings['SubscriptionToCourseXSuccessful'] = "Your subscription to <a href=\"%s\"><strong>\"%s\"</strong></a> was completed successfully.";
$strings['OrderCanceled'] = "Order canceled";
$strings['OrderStatus'] = "Order status";
$strings['PayoutStatus'] = "Payment status";
@ -160,3 +163,24 @@ $strings['BoughtBy'] = "BoughtBy";
$strings['PurchaserUser'] = "Purchaser user";
$strings['Pending'] = "Pending";
$strings['Names'] = "Names";
$strings['SellerName'] = "Seller name";
$strings['SellerId'] = "Seller id";
$strings['SellerAddress'] = "Seller address";
$strings['SellerEmail'] = "Seller e-mail";
$strings['NextNumberInvoice'] = "Next invoice number";
$strings['NextNumberInvoiceDescription'] = "Number of the following invoice";
$strings['InvoiceSeries'] = "Invoice series";
$strings['InvoiceSeriesDescription'] = "Optional parameter: Example invoice Id &lt;series&gt;&lt;year&gt;/&lt;number&gt;";
$strings['InvoiceView'] = "View invoice";
$strings['NoInvoiceEnable'] = "No invoicing block enable";
$strings['Company'] = "Company";
$strings['VAT'] = "VAT";
$strings['Address'] = "Address";
$strings['InvoiceNumber'] = "Invoice number";
$strings['InvoiceDate'] = "Invoice date";
$strings['Invoice'] = "Invoice";
$strings['SaleEmail'] = "Sales e-mail";
$strings['PurchaseDetailsIntro'] = "Purchase details";
$strings['PurchaseDetailsEnd'] = "Regards";
$strings['ProductName'] = "Product name";
$strings['BankAccountIntro'] = "Bank Account Info";

@ -82,7 +82,7 @@ $strings['CancelOrder'] = "Annuler la commande";
$strings['BankAccountInformation'] = "Détails du compte bancaire";
$strings['BankAccount'] = "Compte bancaire";
$strings['OnceItIsConfirmedYouWillReceiveAnEmailWithTheBankInformationAndAnOrderReference'] = "Une fois confirmée, vous recevrez un e-mail avec les données bancaires et la référence de la commande";
$strings['SubscriptionToCourseXSuccessful'] = "Votre inscription au \"%s\" est terminée.";
$strings['SubscriptionToCourseXSuccessful'] = "Votre inscription au <a href=\"%s\"><strong>\"%s\"</strong></a> est terminée.";
$strings['OrderCanceled'] = "Commande annulée";
$strings['OrderStatus'] = "Statut de commande";
$strings['PayoutStatus'] = "État du paiement";

@ -9,8 +9,9 @@ $strings['paypal_enable'] = "Habilitar PayPal";
$strings['commissions_enable'] = "Habilitar Comisiones";
$strings['transfer_enable'] = "Habilitar transferencia";
$strings['unregistered_users_enable'] = "Permitir usuarios sin registro en la plataforma";
$strings['invoicing_enable'] = "Habilitar Facturación";
$strings['tax_enable'] = "Habilitar Impuestos";
$strings['Free'] = "GRATIS";
$strings['PaypalPayoutCommissions'] = "Pagar comisiones por Paypal";
$strings['MyPayouts'] = "Mis Pagos";
$strings['Commission'] = "Comisión";
@ -19,7 +20,7 @@ $strings['SetCommissions'] = "Aplicar comisiones";
$strings['CommissionsConfig'] = "Configurar Comisiones";
$strings['PayoutReport'] = "Reporte de Pagos";
$strings['Stats'] = "Estadísticas";
$strings['InfoCommissions'] = "Ingrese aquí la comisión de ventas, en porcentaje (%), para la organización que controla la plataforma. Este porcentaje se deducirá del monto percibido por los docentes por cada curso o sessión vendido en la plataforma.";
$strings['InfoCommissions'] = "Ingrese aquí la comisión de ventas, en porcentaje (%), para la organización que controla la plataforma. Este porcentaje se deducirá del monto percibido por los docentes por cada curso o sesión vendido en la plataforma.";
$strings['NeedToSelectPaymentType'] = "Necesita seleccionar el tipo de pago";
$strings['IndividualPayout'] = "Pago individual";
$strings['CancelPayout'] = "Cancelar Payout";
@ -40,7 +41,7 @@ $strings['Buyer'] = "Comprador";
$strings['BankTransfer'] = "Transferencia Bancaria";
$strings['SaleInfo'] = "Información de la venta";
$strings['SaleStatusPending'] = "Venta pendiente";
$strings['SaleStatusCancelled'] = "Venta cancelada";
$strings['SaleStatusCanceled'] = "Venta cancelada";
$strings['SaleStatusCompleted'] = "Venta completada";
$strings['PayoutStatusPending'] = "Pago pendiente";
$strings['PayoutStatusCanceled'] = "Pago cancelado";
@ -48,6 +49,7 @@ $strings['PayoutStatusCompleted'] = "Pago completado";
$strings['PayoutsTotalPending'] = "Pagos pendientes:";
$strings['PayoutsTotalCanceled'] = "Pagos cancelados:";
$strings['PayoutsTotalCompleted'] = "Pagos completados:";
$strings['Total'] = "Total";
$strings['TotalAmount'] = "Monto total:";
$strings['CourseListOnSale'] = "Lista de cursos a la venta";
$strings['AvailableCourses'] = "Cursos disponibles";
@ -83,7 +85,7 @@ $strings['CancelOrder'] = "Cancelar Orden";
$strings['BankAccountInformation'] = "Información de la Cuenta Bancaria";
$strings['BankAccount'] = "Cuenta Bancaria";
$strings['OnceItIsConfirmedYouWillReceiveAnEmailWithTheBankInformationAndAnOrderReference'] = "Una vez confirmado, recibira un e-mail con los datos bancarios y una referencia del pedido.";
$strings['SubscriptionToCourseXSuccessful'] = "Tu subscripción a \"%s\" se realizó correctamente.";
$strings['SubscriptionToCourseXSuccessful'] = "<p class=\"lead\">Tu subscripción a <a href=\"%s\"><strong>\"%s\"</strong></a> se realizó correctamente.</p>";
$strings['OrderCanceled'] = "Pedido cancelado";
$strings['OrderStatus'] = "Estado del pedido";
$strings['PayoutStatus'] = "Estado del pago";
@ -173,3 +175,37 @@ $strings['DeleteThisService'] = 'Eliminar este servicio';
$strings['YourCoursesNeedAtLeastOneLearningPath'] = 'Los cursos en los que estás registrado necesitan tener al menos una lección que contenga un item de cerficado final';
$strings['NoPaymentOptionAvailable'] = 'No existen opciones de pago. Por favor reporte este problema al administrador.';
$strings['XIsOnlyPaymentMethodAvailable'] = '%s es el único método de pago disponible para esta compra.';
$strings['GlobalTaxPerc'] = "Porcentaje del impuesto global";
$strings['GlobalTaxPercDescription'] = "Porcentaje por defecto que se usará, excepto si existe un impuesto específico en el curso, sesión o servicio.";
$strings['TaxPerc'] = "Porcentaje del impuesto";
$strings['TaxPercDescription'] = "Si se deja vacío se usará valor global por defecto.";
$strings['ByDefault'] = "por defecto (valor global)";
$strings['OnlyCourses'] = "Solo Cursos";
$strings['OnlySessions'] = "Solo Sesiones";
$strings['OnlyServices'] = "Solo Servicios";
$strings['TaxAppliesTo'] = "Impuestos aplicados a";
$strings['AllCoursesSessionsAndServices'] = "Todos (Cursos, sesiones y servicios)";
$strings['TaxNameCustom'] = "Nombre del impuesto";
$strings['TaxNameExamples'] = "VAT, IVA, IGV, TVA, IV ...";
$strings['ErrorUpdateFieldDB'] = "Error al actualizar los campos de la base de datos";
$strings['SellerName'] = "Nombre vendedor";
$strings['SellerId'] = "Identificador vendedor";
$strings['SellerAddress'] = "Dirección vendedor";
$strings['SellerEmail'] = "E-mail vendedor";
$strings['NextNumberInvoice'] = "Número siguiente factura";
$strings['NextNumberInvoiceDescription'] = "Número de la siguiente factura asignado de forma manual";
$strings['InvoiceSeries'] = "Serie factura";
$strings['InvoiceSeriesDescription'] = "Parámetro opcional: Ejemplo de numeración factura &lt;serie&gt;&lt;año&gt;/&lt;número&gt;";
$strings['InvoiceView'] = "Ver factura";
$strings['NoInvoiceEnable'] = "No está habilitado el bloque de facturación";
$strings['Company'] = "Empresa";
$strings['VAT'] = "CIF";
$strings['Address'] = "Dirección";
$strings['InvoiceNumber'] = "Num. factura";
$strings['InvoiceDate'] = "Fecha de emisión";
$strings['Invoice'] = "Factura";
$strings['SaleEmail'] = "E-mail de ventas";
$strings['PurchaseDetailsIntro'] = "Detalles de la comprar";
$strings['PurchaseDetailsEnd'] = "Atentamente";
$strings['ProductName'] = "Nombre producto";
$strings['BankAccountIntro'] = "Información cuentas bancarias";

@ -41,6 +41,15 @@
letter-spacing: -0.020em;
}
.buy-info .price-details-tax, .service-buy .price-details-tax {
font-size: 18px;
line-height: 24px;
font-weight: bold;
padding-bottom: 0px;
padding-top: 10px;
letter-spacing: -0.020em;
}
.buy-info .buy-item .title {
margin-top: 5px;
font-weight: bold;

File diff suppressed because it is too large Load Diff

@ -235,6 +235,9 @@ switch ($action) {
$payout['id'],
BuyCoursesPlugin::PAYOUT_STATUS_COMPLETED
);
if ($plugin->get('invoicing_enable') === 'true') {
$plugin->setInvoice($payout['id']);
}
}
echo Display::return_message(
@ -328,10 +331,7 @@ switch ($action) {
if ($saleIsCompleted) {
Display::addFlash(
Display::return_message(
sprintf($plugin->get_lang('SubscriptionToCourseXSuccessful'), $sale['product_name']),
'success'
)
$plugin->getSubscriptionSuccessMessage($sale)
);
}
}

@ -12,6 +12,7 @@ require_once __DIR__.'/../../../main/inc/global.inc.php';
$plugin = BuyCoursesPlugin::create();
$includeSession = $plugin->get('include_sessions') === 'true';
$includeServices = $plugin->get('include_services') === 'true';
$taxEnable = $plugin->get('tax_enable') === 'true';
api_protect_admin_script(true);
@ -39,6 +40,7 @@ $tpl->assign('product_type_session', BuyCoursesPlugin::PRODUCT_TYPE_SESSION);
$tpl->assign('courses', $courses);
$tpl->assign('sessions_are_included', $includeSession);
$tpl->assign('services_are_included', $includeServices);
$tpl->assign('tax_enable', $taxEnable);
if ($includeSession) {
$sessions = $plugin->getSessionsForConfiguration();
@ -50,6 +52,13 @@ if ($includeServices) {
$tpl->assign('services', $services);
}
if ($taxEnable) {
$globalParameters = $plugin->getGlobalParameters();
$tpl->assign('global_tax_perc', $globalParameters['global_tax_perc']);
$tpl->assign('tax_applies_to', $globalParameters['tax_applies_to']);
$tpl->assign('tax_name', $globalParameters['tax_name']);
}
$content = $tpl->fetch('buycourses/view/configuration.tpl');
$tpl->assign('header', $templateName);

@ -88,6 +88,7 @@ if ($editingCourse) {
'name' => $courseItem['course_title'],
'visible' => $courseItem['visible'],
'price' => $courseItem['price'],
'tax_perc' => $courseItem['tax_perc'],
'beneficiaries' => $defaultBeneficiaries,
($commissionsEnable == "true") ? 'commissions' : '' => ($commissionsEnable == "true") ? $commissions : '',
];
@ -154,6 +155,7 @@ if ($editingCourse) {
'name' => $sessionItem['session_name'],
'visible' => $sessionItem['visible'],
'price' => $sessionItem['price'],
'tax_perc' => $sessionItem['tax_perc'],
'beneficiaries' => $defaultBeneficiaries,
($commissionsEnable == "true") ? 'commissions' : '' => ($commissionsEnable == "true") ? $commissions : '',
];
@ -190,6 +192,8 @@ if ($commissionsEnable === 'true') {
";
}
$globalSettingsParams = $plugin->getGlobalParameters();
$form = new FormValidator('beneficiaries');
$form->addText('product_type', $plugin->get_lang('ProductType'), false);
$form->addText('name', get_lang('Name'), false);
@ -204,6 +208,12 @@ $form->addElement(
[$plugin->get_lang('Price'), null, $currencyIso],
['step' => 0.01]
);
$form->addElement(
'number',
'tax_perc',
[$plugin->get_lang('TaxPerc'), $plugin->get_lang('TaxPercDescription'), '%'],
['step' => 1, 'placeholder' => $globalSettingsParams['global_tax_perc'].'% '.$plugin->get_lang('ByDefault')]
);
$beneficiariesSelect = $form->addSelect(
'beneficiaries',
$plugin->get_lang('Beneficiaries'),
@ -252,9 +262,13 @@ if ($form->validate()) {
$productItem = $plugin->getItemByProduct($formValues['i'], $formValues['t']);
if (isset($formValues['visible'])) {
$taxPerc = $formValues['tax_perc'] != '' ? (int) $formValues['tax_perc'] : null;
if (!empty($productItem)) {
$plugin->updateItem(
['price' => floatval($formValues['price'])],
[
'price' => floatval($formValues['price']),
'tax_perc' => $taxPerc,
],
$formValues['i'],
$formValues['t']
);
@ -264,6 +278,7 @@ if ($form->validate()) {
'product_type' => $formValues['t'],
'product_id' => intval($formValues['i']),
'price' => floatval($_POST['price']),
'tax_perc' => $taxPerc,
]);
$productItem['id'] = $itemId;
}

@ -9,15 +9,11 @@
$plugin = BuyCoursesPlugin::create();
$guess_enable = $plugin->get('unregistered_users_enable');
if ($guess_enable == "true" || isset($_SESSION['_user'])) {
// If the user is NOT an administrator, redirect it to course/session buy list
if (!api_is_platform_admin()) {
header('Location: src/course_panel.php');
exit;
if ($guess_enable == 'true' || isset($_SESSION['_user'])) {
if (api_is_platform_admin()) {
$tpl = new Template();
$content = $tpl->fetch('buycourses/view/index.tpl');
$tpl->assign('content', $content);
$tpl->display_one_col_template();
}
$tpl = new Template();
$content = $tpl->fetch('buycourses/view/index.tpl');
$tpl->assign('content', $content);
$tpl->display_one_col_template();
}

@ -0,0 +1,141 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
/**
* Print invoice of the Buy Courses plugin.
*
* @package chamilo.plugin.buycourses
*/
$cidReset = true;
require_once '../config.php';
api_protect_admin_script();
$plugin = BuyCoursesPlugin::create();
$invoicingEnable = $plugin->get('invoicing_enable') === 'true';
if (!$invoicingEnable) {
api_not_allowed(true, $plugin->get_lang('NoInvoiceEnable'));
}
$saleId = isset($_GET['invoice']) ? (int) $_GET['invoice'] : 0;
$isService = isset($_GET['is_service']) ? (int) $_GET['is_service'] : 0;
$globalParameters = $plugin->getGlobalParameters();
$infoSale = $plugin->getDataSaleInvoice($saleId, $isService);
$buyer = api_get_user_info($infoSale['user_id']);
$extraUserInfoData = UserManager::get_extra_user_data($infoSale['user_id']);
$infoInvoice = $plugin->getDataInvoice($saleId, $isService);
$taxAppliesTo = $globalParameters['tax_applies_to'];
$taxEnable = $plugin->get('tax_enable') === 'true' &&
($taxAppliesTo == BuyCoursesPlugin::TAX_APPLIES_TO_ALL ||
($taxAppliesTo == BuyCoursesPlugin::TAX_APPLIES_TO_ONLY_COURSE && !$isService) ||
($taxAppliesTo == BuyCoursesPlugin::TAX_APPLIES_TO_ONLY_SESSION && $isService));
$htmlText = '<html>';
$htmlText .= '<link rel="stylesheet" type="text/css" href="plugin.css">';
$htmlText .= '<link rel="stylesheet" type="text/css" href="'.api_get_path(WEB_CSS_PATH).'base.css">';
$htmlText .= '<body>';
$organization = ChamiloApi::getPlatformLogo('', [], true);
// Use custom logo image.
$pdfLogo = api_get_setting('pdf_logo_header');
if ($pdfLogo === 'true') {
$visualTheme = api_get_visual_theme();
$img = api_get_path(SYS_CSS_PATH).'themes/'.$visualTheme.'/images/pdf_logo_header.png';
if (file_exists($img)) {
$organization = "<img src='$img'>";
}
}
$htmlText .= $organization;
// Seller and customer info
$htmlText .= '<table width="100%">';
$htmlText .= '<tr>';
$htmlText .= '<td>';
$htmlText .= '<b>'.$globalParameters['seller_name'].'</b><br/>';
$htmlText .= $globalParameters['seller_id'].'<br/>';
$htmlText .= $globalParameters['seller_address'].'<br/>';
$htmlText .= $globalParameters['seller_email'].'<br/>';
$htmlText .= '</td>';
$htmlText .= '<td style="text-align:right;">';
$htmlText .= '<b>'.$buyer['complete_name'].'</b><br/>';
$htmlText .= ($extraUserInfoData['buycourses_company'] ? $extraUserInfoData['buycourses_company'].'<br>' : '');
$htmlText .= ($extraUserInfoData['buycourses_vat'] ? $extraUserInfoData['buycourses_vat'].'<br>' : '');
$htmlText .= ($extraUserInfoData['buycourses_address'] ? $extraUserInfoData['buycourses_address'].'<br/>' : '');
$htmlText .= ($buyer['phone'] ? $buyer['phone'].'<br/>' : '');
$htmlText .= ($buyer['email'] ? $buyer['email'].'<br>' : '');
$htmlText .= '</td>';
$htmlText .= '</tr>';
$htmlText .= '</table>';
$htmlText .= '<br><br>';
$htmlText .= '<p>';
$htmlText .= $plugin->get_lang('InvoiceDate').': <span style="font-weight:bold;">'
.api_convert_and_format_date($infoInvoice['date_invoice'], DATE_TIME_FORMAT_LONG_24H).'</span><br>';
$htmlText .= $plugin->get_lang('InvoiceNumber').': <span style="font-weight:bold;">'
.$infoInvoice['serie'].$infoInvoice['year'].'/'.$infoInvoice['num_invoice'].'</span><br>';
$htmlText .= '</p><br><br>';
$header = [
$plugin->get_lang('OrderReference'),
$plugin->get_lang('ProductType'),
$plugin->get_lang('Price'),
];
if ($taxEnable) {
$header[] = $globalParameters['tax_name'];
$header[] = $plugin->get_lang('Total');
}
$data = [];
$row = [
$infoSale['reference'],
$infoSale['product_name'],
];
if ($taxEnable) {
$row[] = $plugin->getCurrency($infoSale['currency_id'])['iso_code'].' '.$infoSale['price_without_tax'];
$row[] = $plugin->getCurrency($infoSale['currency_id'])['iso_code'].
' '.$infoSale['tax_amount'].
' ('.(int) $infoSale['tax_perc'].'%)';
}
$row[] = $plugin->getCurrency($infoSale['currency_id'])['iso_code'].' '.$infoSale['price'];
$data[] = $row;
if ($taxEnable) {
$row = [
'',
'',
'',
$plugin->get_lang('TotalPayout'),
$plugin->getCurrency($infoSale['currency_id'])['iso_code'].' '.$infoSale['price'],
];
} else {
$row = [
'',
$plugin->get_lang('TotalPayout'),
$plugin->getCurrency($infoSale['currency_id'])['iso_code'].' '.$infoSale['price'],
];
}
$data[] = $row;
$attr = [];
$attr['class'] = "table data_table";
$attr['width'] = "100%";
$htmlText .= Display::table($header, $data, $attr);
$htmlText .= '</body></html>';
$fileName = $infoInvoice['serie'].$infoInvoice['year'].'-'.$infoInvoice['num_invoice'];
$fileName = api_replace_dangerous_char($fileName);
$params = [
'filename' => $fileName,
'pdf_title' => $plugin->get_lang('Invoice'),
'pdf_description' => '',
'format' => 'A4',
'orientation' => 'P',
];
$pdf = new PDF($params['format'], $params['orientation'], $params);
$pdf->content_to_pdf($htmlText, '', $fileName, null, 'D', false, null, false, false, false);
exit;

@ -32,14 +32,14 @@ if (isset($_GET['action'], $_GET['id'])) {
}
}
$currencyForm = new FormValidator('currency');
$globalSettingForm = new FormValidator('currency');
if ($currencyForm->validate()) {
$currencyFormValues = $currencyForm->getSubmitValues();
if ($globalSettingForm->validate()) {
$globalSettingFormValues = $globalSettingForm->getSubmitValues();
$plugin->selectCurrency($currencyFormValues['currency']);
unset($currencyFormValues['currency']);
$plugin->saveGlobalParameters($currencyFormValues);
$plugin->selectCurrency($globalSettingFormValues['currency']);
unset($globalSettingFormValues['currency']);
$plugin->saveGlobalParameters($globalSettingFormValues);
Display::addFlash(
Display::return_message(get_lang('Saved'), 'success')
@ -51,7 +51,7 @@ if ($currencyForm->validate()) {
$currencies = $plugin->getCurrencies();
$currencySelect = $currencyForm->addSelect(
$currencySelect = $globalSettingForm->addSelect(
'currency',
[
$plugin->get_lang('CurrencyType'),
@ -77,14 +77,98 @@ foreach ($currencies as $currency) {
}
}
$currencyForm->addTextarea(
$globalSettingForm->addTextarea(
'terms_and_conditions',
[get_lang('TermsAndConditions'),
$plugin->get_lang('WriteHereTheTermsAndConditionsOfYourECommerce'), ],
$plugin->get_lang('WriteHereTheTermsAndConditionsOfYourECommerce'), ],
[]
);
$currencyForm->addButtonSave(get_lang('Save'));
$currencyForm->setDefaults($plugin->getGlobalParameters());
$globalSettingForm->addElement(
'text',
'sale_email',
$plugin->get_lang('SaleEmail')
);
$taxEnable = $plugin->get('tax_enable') === 'true';
$invoicingEnable = $plugin->get('invoicing_enable') === 'true';
if ($taxEnable) {
$globalSettingForm->addHtml('<hr/>');
$globalSettingForm->addElement(
'number',
'global_tax_perc',
[$plugin->get_lang('GlobalTaxPerc'), $plugin->get_lang('GlobalTaxPercDescription'), '%'],
['step' => 1]
);
$taxAppliesTo = $plugin->getTaxAppliesTo();
$taxTypeSelect = $globalSettingForm->addSelect(
'tax_applies_to',
$plugin->get_lang('TaxAppliesTo'),
[get_lang('Select')]
);
foreach ($taxAppliesTo as $key => $value) {
$optionText = $value;
$optionyValue = $key;
$taxTypeSelect->addOption($optionText, $optionyValue);
}
$globalSettingForm->addElement(
'text',
'tax_name',
$plugin->get_lang('TaxNameCustom'),
['placeholder' => $plugin->get_lang('TaxNameExamples')]
);
}
if ($invoicingEnable) {
$globalSettingForm->addHtml('<hr/>');
$globalSettingForm->addElement(
'text',
'seller_name',
$plugin->get_lang('SellerName')
);
$globalSettingForm->addElement(
'text',
'seller_id',
$plugin->get_lang('SellerId')
);
$globalSettingForm->addElement(
'text',
'seller_address',
$plugin->get_lang('SellerAddress')
);
$globalSettingForm->addElement(
'text',
'seller_email',
$plugin->get_lang('SellerEmail')
);
$globalSettingForm->addElement(
'number',
'next_number_invoice',
[$plugin->get_lang('NextNumberInvoice'), $plugin->get_lang('NextNumberInvoiceDescription')],
['step' => 1]
);
$globalSettingForm->addElement(
'text',
'invoice_series',
[$plugin->get_lang('InvoiceSeries'), $plugin->get_lang('InvoiceSeriesDescription')]
);
}
$globalSettingForm->addButtonSave(get_lang('Save'));
$globalSettingForm->setDefaults($plugin->getGlobalParameters());
$termsAndConditionsForm = new FormValidator('termsconditions');
@ -231,7 +315,7 @@ $interbreadcrumb[] = [
$templateName = $plugin->get_lang('PaymentsConfiguration');
$tpl = new Template($templateName);
$tpl->assign('header', $templateName);
$tpl->assign('global_config_form', $currencyForm->returnForm());
$tpl->assign('global_config_form', $globalSettingForm->returnForm());
$tpl->assign('paypal_form', $paypalForm->returnForm());
$tpl->assign('commission_form', $commissionForm->returnForm());
$tpl->assign('transfer_form', $transferForm->returnForm());

@ -11,11 +11,7 @@ use ChamiloSession as Session;
require_once '../config.php';
$currentUserId = api_get_user_id();
if (empty($currentUserId)) {
Session::write('buy_course_redirect', Security::remove_XSS($_SERVER['REQUEST_URI']));
header('Location: '.api_get_path(WEB_CODE_PATH).'auth/inscription.php');
exit;
}
$htmlHeadXtra[] = '<link rel="stylesheet" type="text/css" href="'.api_get_path(
WEB_PLUGIN_PATH
).'buycourses/resources/css/style.css"/>';
@ -37,6 +33,12 @@ $buyingCourse = intval($_REQUEST['t']) === BuyCoursesPlugin::PRODUCT_TYPE_COURSE
$buyingSession = intval($_REQUEST['t']) === BuyCoursesPlugin::PRODUCT_TYPE_SESSION;
$queryString = 'i='.intval($_REQUEST['i']).'&t='.intval($_REQUEST['t']);
if (empty($currentUserId)) {
Session::write('buy_course_redirect', api_get_self().'?'.$queryString);
header('Location: '.api_get_path(WEB_CODE_PATH).'auth/inscription.php');
exit;
}
if ($buyingCourse) {
$courseInfo = $plugin->getCourseInfo($_REQUEST['i']);
$item = $plugin->getItemByProduct($_REQUEST['i'], BuyCoursesPlugin::PRODUCT_TYPE_COURSE);

@ -25,7 +25,7 @@ if (empty($sale)) {
}
$currency = $plugin->getCurrency($sale['currency_id']);
$terms = $plugin->getGlobalParameters();
$globalParameters = $plugin->getGlobalParameters();
switch ($sale['payment_type']) {
case BuyCoursesPlugin::PAYMENT_TYPE_PAYPAL:
@ -64,6 +64,28 @@ switch ($sale['payment_type']) {
exit;
}
if (!empty($globalParameters['sale_email'])) {
$messageConfirmTemplate = new Template();
$messageConfirmTemplate->assign('user', $userInfo);
$messageConfirmTemplate->assign(
'sale',
[
'date' => $sale['date'],
'product' => $sale['product_name'],
'currency' => $currency['iso_code'],
'price' => $sale['price'],
'reference' => $sale['reference'],
]
);
api_mail_html(
'',
$globalParameters['sale_email'],
$plugin->get_lang('bc_subject'),
$messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl')
);
}
RedirectToPayPal($expressCheckout["TOKEN"]);
break;
case BuyCoursesPlugin::PAYMENT_TYPE_TRANSFER:
@ -109,7 +131,7 @@ switch ($sale['payment_type']) {
$messageTemplate->assign(
'sale',
[
'date' => api_format_date($sale['date'], DATE_FORMAT_LONG_NO_DAY),
'date' => $sale['date'],
'product' => $sale['product_name'],
'currency' => $currency['iso_code'],
'price' => $sale['price'],
@ -125,6 +147,28 @@ switch ($sale['payment_type']) {
$messageTemplate->fetch('buycourses/view/message_transfer.tpl')
);
if (!empty($globalParameters['sale_email'])) {
$messageConfirmTemplate = new Template();
$messageConfirmTemplate->assign('user', $userInfo);
$messageConfirmTemplate->assign(
'sale',
[
'date' => $sale['date'],
'product' => $sale['product_name'],
'currency' => $currency['iso_code'],
'price' => $sale['price'],
'reference' => $sale['reference'],
]
);
api_mail_html(
'',
$globalParameters['sale_email'],
$plugin->get_lang('bc_subject'),
$messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl')
);
}
Display::addFlash(
Display::return_message(
sprintf(
@ -162,7 +206,7 @@ switch ($sale['payment_type']) {
$template->assign('buying_course', $buyingCourse);
$template->assign('buying_session', $buyingSession);
$template->assign('terms', $terms['terms_and_conditions']);
$template->assign('terms', $globalParameters['terms_and_conditions']);
$template->assign('title', $sale['product_name']);
$template->assign('price', $sale['price']);
$template->assign('currency', $sale['currency_id']);
@ -253,7 +297,7 @@ switch ($sale['payment_type']) {
$template->assign('buying_course', $buyingCourse);
$template->assign('buying_session', $buyingSession);
$template->assign('terms', $terms['terms_and_conditions']);
$template->assign('terms', $globalParameters['terms_and_conditions']);
$template->assign('title', $sale['product_name']);
$template->assign('price', floatval($sale['price']));
$template->assign('currency', $plugin->getSelectedCurrency());

@ -18,6 +18,7 @@ $plugin = BuyCoursesPlugin::create();
$paypalEnable = $plugin->get('paypal_enable');
$commissionsEnable = $plugin->get('commissions_enable');
$includeServices = $plugin->get('include_services');
$invoicingEnable = $plugin->get('invoicing_enable') === 'true';
if (isset($_GET['order'])) {
$sale = $plugin->getSale($_GET['order']);
@ -33,10 +34,7 @@ if (isset($_GET['order'])) {
$plugin->completeSale($sale['id']);
$plugin->storePayouts($sale['id']);
Display::addFlash(
Display::return_message(
sprintf($plugin->get_lang('SubscriptionToCourseXSuccessful'), $sale['product_name']),
'success'
)
$plugin->getSubscriptionSuccessMessage($sale)
);
$urlToRedirect .= http_build_query([
@ -123,13 +121,15 @@ foreach ($sales as $sale) {
'id' => $sale['id'],
'reference' => $sale['reference'],
'status' => $sale['status'],
'date' => api_format_date($sale['date'], DATE_TIME_FORMAT_LONG_24H),
'date' => api_convert_and_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']),
'payment_type' => $paymentTypes[$sale['payment_type']],
'invoice' => $sale['invoice'],
'num_invoice' => $plugin->getNumInvoice($sale['id'], 0),
];
}
@ -179,6 +179,7 @@ $template->assign('sale_list', $saleList);
$template->assign('sale_status_canceled', BuyCoursesPlugin::SALE_STATUS_CANCELED);
$template->assign('sale_status_pending', BuyCoursesPlugin::SALE_STATUS_PENDING);
$template->assign('sale_status_completed', BuyCoursesPlugin::SALE_STATUS_COMPLETED);
$template->assign('invoicing_enable', $invoicingEnable);
$content = $template->fetch('buycourses/view/sales_report.tpl');

@ -25,7 +25,7 @@ if (empty($serviceSale)) {
}
$currency = $plugin->getCurrency($serviceSale['currency_id']);
$terms = $plugin->getGlobalParameters();
$globalParameters = $plugin->getGlobalParameters();
switch ($serviceSale['payment_type']) {
case BuyCoursesPlugin::PAYMENT_TYPE_PAYPAL:
@ -78,6 +78,28 @@ switch ($serviceSale['payment_type']) {
exit;
}
if (!empty($globalParameters['sale_email'])) {
$messageConfirmTemplate = new Template();
$messageConfirmTemplate->assign('user', $userInfo);
$messageConfirmTemplate->assign(
'sale',
[
'date' => $serviceSale['buy_date'],
'product' => $serviceSale['service']['name'],
'currency' => $currency['iso_code'],
'price' => $serviceSale['price'],
'reference' => $serviceSale['reference'],
]
);
api_mail_html(
'',
$globalParameters['sale_email'],
$plugin->get_lang('bc_subject'),
$messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl')
);
}
RedirectToPayPal($expressCheckout['TOKEN']);
break;
case BuyCoursesPlugin::PAYMENT_TYPE_TRANSFER:
@ -112,10 +134,10 @@ switch ($serviceSale['payment_type']) {
[
'name' => $serviceSale['service']['name'],
'buyer' => $serviceSale['buyer']['name'],
'buy_date' => api_format_date($serviceSale['buy_date'], DATE_TIME_FORMAT_LONG_24H),
'start_date' => api_format_date($serviceSale['start_date'], DATE_TIME_FORMAT_LONG_24H),
'end_date' => api_format_date($serviceSale['end_date'], DATE_TIME_FORMAT_LONG_24H),
'currency' => $currency['currency'],
'buy_date' => $serviceSale['buy_date'],
'start_date' => $serviceSale['start_date'],
'end_date' => $serviceSale['end_date'],
'currency' => $currency['iso_code'],
'price' => $serviceSale['price'],
'reference' => $serviceSale['reference'],
]
@ -126,9 +148,31 @@ switch ($serviceSale['payment_type']) {
$buyer['complete_name'],
$buyer['email'],
$plugin->get_lang('bc_subject'),
$messageTemplate->fetch('buycourses/view/message_transfer.tpl')
$messageTemplate->fetch('buycourses/view/service_message_transfer.tpl')
);
if (!empty($globalParameters['sale_email'])) {
$messageConfirmTemplate = new Template();
$messageConfirmTemplate->assign('user', $userInfo);
$messageConfirmTemplate->assign(
'sale',
[
'date' => $serviceSale['buy_date'],
'product' => $serviceSale['service']['name'],
'currency' => $currency['iso_code'],
'price' => $serviceSale['price'],
'reference' => $serviceSale['reference'],
]
);
api_mail_html(
'',
$globalParameters['sale_email'],
$plugin->get_lang('bc_subject'),
$messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl')
);
}
Display::addFlash(
Display::return_message(
sprintf(
@ -166,7 +210,7 @@ switch ($serviceSale['payment_type']) {
$template = new Template();
$template->assign('terms', $terms['terms_and_conditions']);
$template->assign('terms', $globalParameters['terms_and_conditions']);
$template->assign('title', $serviceSale['service']['name']);
$template->assign('price', $serviceSale['price']);
$template->assign('currency', $serviceSale['currency_id']);
@ -235,7 +279,7 @@ switch ($serviceSale['payment_type']) {
);
$template = new Template();
$template->assign('terms', $terms['terms_and_conditions']);
$template->assign('terms', $globalParameters['terms_and_conditions']);
$template->assign('title', $serviceSale['service']['name']);
$template->assign('price', floatval($serviceSale['price']));
$template->assign('currency', $plugin->getSelectedCurrency());

@ -17,17 +17,30 @@ $plugin = BuyCoursesPlugin::create();
$paypalEnable = $plugin->get('paypal_enable');
$commissionsEnable = $plugin->get('commissions_enable');
$includeServices = $plugin->get('include_services');
$invoicingEnable = $plugin->get('invoicing_enable') === 'true';
$saleStatuses = $plugin->getServiceSaleStatuses();
$paymentTypes = $plugin->getPaymentTypes();
$selectedStatus = isset($_GET['status']) ? $_GET['status'] : BuyCoursesPlugin::SALE_STATUS_PENDING;
$searchTerm = '';
$form = new FormValidator('search', 'get');
if ($form->validate()) {
$selectedStatus = $form->getSubmitValue('status');
$searchTerm = $form->getSubmitValue('user');
if ($selectedStatus === false) {
$selectedStatus = BuyCoursesPlugin::SALE_STATUS_PENDING;
}
}
$form->addSelect('status', $plugin->get_lang('OrderStatus'), $saleStatuses, ['cols-size' => [0, 0, 0]]);
$form->addText('user', get_lang('User'), false, ['cols-size' => [0, 0, 0]]);
$form->addButtonSearch(get_lang('Search'), 'search');
$servicesSales = $plugin->getServiceSale();
$servicesSales = $plugin->getServiceSale(null, null, $selectedStatus);
$serviceSaleList = [];
foreach ($servicesSales as $sale) {
@ -35,12 +48,14 @@ foreach ($servicesSales as $sale) {
'id' => $sale['id'],
'reference' => $sale['reference'],
'status' => $sale['status'],
'date' => api_format_date($sale['buy_date'], DATE_TIME_FORMAT_LONG_24H),
'date' => api_convert_and_format_date($sale['buy_date'], DATE_TIME_FORMAT_LONG_24H),
'currency' => $sale['currency'],
'price' => $sale['price'],
'service_type' => $sale['service']['applies_to'],
'service_name' => $sale['service']['name'],
'complete_user_name' => $sale['buyer']['name'],
'invoice' => $sale['invoice'],
'num_invoice' => $plugin->getNumInvoice($sale['id'], 1),
];
}
@ -87,6 +102,7 @@ $template->assign('sale_list', $serviceSaleList);
$template->assign('sale_status_cancelled', BuyCoursesPlugin::SERVICE_STATUS_CANCELLED);
$template->assign('sale_status_pending', BuyCoursesPlugin::SERVICE_STATUS_PENDING);
$template->assign('sale_status_completed', BuyCoursesPlugin::SERVICE_STATUS_COMPLETED);
$template->assign('invoicing_enable', $invoicingEnable);
$content = $template->fetch('buycourses/view/service_sales_report.tpl');
$template->assign('content', $content);
$template->display_one_col_template();

@ -32,8 +32,11 @@ $interbreadcrumb[] = [
'name' => $plugin->get_lang('Configuration'),
];
$globalSettingsParams = $plugin->getGlobalParameters();
$formDefaultValues = [
'price' => 0,
'tax_perc' => $globalSettingsParams['global_tax_perc'],
'duration_days' => 0,
'applies_to' => 0,
'visibility' => true,
@ -48,6 +51,12 @@ $form->addElement(
[$plugin->get_lang('Price'), null, $currency['iso_code']],
['step' => 0.01]
);
$form->addElement(
'number',
'tax_perc',
[$plugin->get_lang('TaxPerc'), $plugin->get_lang('TaxPercDescription'), '%'],
['step' => 1, 'placeholder' => $globalSettingsParams['global_tax_perc'].'% '.$plugin->get_lang('ByDefault')]
);
$form->addElement(
'number',
'duration_days',

@ -37,12 +37,14 @@ $interbreadcrumb[] = [
'name' => $plugin->get_lang('Configuration'),
];
$globalSettingsParams = $plugin->getGlobalParameters();
$service = $plugin->getServices($serviceId);
$formDefaultValues = [
'name' => $service['name'],
'description' => $service['description'],
'price' => $service['price'],
'tax_perc' => $service['tax_perc'],
'duration_days' => $service['duration_days'],
'owner_id' => intval($service['owner_id']),
'applies_to' => intval($service['applies_to']),
@ -63,6 +65,12 @@ $form->addElement(
[$plugin->get_lang('Price'), null, $currency['iso_code']],
['step' => 0.01]
);
$form->addElement(
'number',
'tax_perc',
[$plugin->get_lang('TaxPerc'), $plugin->get_lang('TaxPercDescription'), '%'],
['step' => 1, 'placeholder' => $globalSettingsParams['global_tax_perc'].'% '.$plugin->get_lang('ByDefault')]
);
$form->addElement(
'number',
'duration_days',

@ -83,23 +83,9 @@ if ($form->validate()) {
switch ($confirmPayments['PAYMENTINFO_0_PAYMENTSTATUS']) {
case 'Completed':
$saleIsCompleted = $plugin->completeSale($sale['id']);
if ($saleIsCompleted && $buyingSession) {
if ($saleIsCompleted) {
Display::addFlash(
Display::return_message(
sprintf($plugin->get_lang('SubscriptionToCourseXSuccessful'), $session['name']),
'success'
)
);
$plugin->storePayouts($sale['id']);
break;
}
if ($saleIsCompleted && $buyingCourse) {
Display::addFlash(
Display::return_message(
sprintf($plugin->get_lang('SubscriptionToCourseXSuccessful'), $course['title']),
'success'
)
$plugin->getSubscriptionSuccessMessage($sale)
);
$plugin->storePayouts($sale['id']);
break;

@ -1,13 +1,15 @@
<link rel="stylesheet" type="text/css" href="../resources/css/style.css"/>
{% if sessions_are_included %}
{% if sessions_are_included or services_are_included %}
<ul class="nav nav-tabs buy-courses-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#courses" aria-controls="courses" role="tab" data-toggle="tab">{{ 'Courses'|get_lang }}</a>
</li>
{% if sessions_are_included %}
<li role="presentation">
<a href="#sessions" aria-controls="sessions" role="tab" data-toggle="tab">{{ 'Sessions'|get_lang }}</a>
</li>
{% endif %}
{% if services_are_included %}
<li role="presentation">
<a href="#services" aria-controls="services" role="tab"
@ -27,6 +29,9 @@
<th class="text-center">{{ 'OfficialCode'|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>
{% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 2) %}
<th class="text-center" width="100">{{ tax_name }}</th>
{% endif %}
<th class="text-right">{{ 'Options'|get_lang }}</th>
</tr>
</thead>
@ -70,6 +75,15 @@
<td width="200" class="text-right">
{{ "#{item.price} #{tem.currency ?: item.currency}" }}
</td>
{% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 2) %}
<td class="text-center">
{% if item.tax_perc is null %}
{{ global_tax_perc }} %
{% else %}
{{ item.tax_perc }} %
{% endif %}
</td>
{% endif %}
<td class="text-right">
<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">
@ -94,6 +108,9 @@
<th class="text-center">{{ 'EndDate'|get_lang }}</th>
<th class="text-center">{{ 'VisibleInCatalog'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-right">{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}</th>
{% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 3) %}
<th class="text-center" width="100">{{ tax_name }}</th>
{% endif %}
<th class="text-right">{{ 'Options'|get_lang }}</th>
</tr>
</thead>
@ -101,25 +118,6 @@
{% for item in sessions %}
<tr data-item="{{ item.session_id }}" data-type="session">
<td>
{% if item.session_visibility == 0 %}
<img src="{{ 'bullet_red.png'|icon() }}"
alt="{{ 'CourseVisibilityClosed'|get_lang }}"
title="{{ 'CourseVisibilityClosed'|get_lang }}">
{% elseif item.session_visibility == 1 %}
<img src="{{ 'bullet_orange.png'|icon() }}" alt="{{ 'Private'|get_lang }}"
title="{{ 'Private'|get_lang }}">
{% elseif item.session_visibility == 2 %}
<img src="{{ 'bullet_green.png'|icon() }}" alt="{{ 'OpenToThePlatform'|get_lang }}"
title="{{ 'OpenToThePlatform'|get_lang }}">
{% elseif item.session_visibility == 3 %}
<img src="{{ 'bullet_blue.png'|icon() }}" alt="{{ 'OpenToTheWorld'|get_lang }}"
title="{{ 'OpenToTheWorld'|get_lang }}">
{% elseif item.session_visibility == 4 %}
<img src="{{ 'bullet_gray.png'|icon() }}"
alt="{{ 'CourseVisibilityHidden'|get_lang }}"
title="{{ 'CourseVisibilityHidden'|get_lang }}">
{% endif %}
<a href="{{ _p.web_main ~ 'session/index.php?' ~ {'session_id': item.session_id}|url_encode() }}">{{ item.session_name }}</a>
</td>
<td class="text-center">
@ -138,6 +136,15 @@
<td class="text-right" width="200">
{{ "#{item.price} #{tem.currency ?: item.currency}" }}
</td>
{% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 3) %}
<td class="text-center">
{% if item.tax_perc is null %}
{{ global_tax_perc }} %
{% else %}
{{ item.tax_perc }} %
{% endif %}
</td>
{% endif %}
<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">
@ -168,6 +175,9 @@
<th class="text-center">{{ 'VisibleInCatalog'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-center">{{ 'Owner'|get_lang }}</th>
<th class="text-right">{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}</th>
{% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 4) %}
<th class="text-center" width="100">{{ tax_name }}</th>
{% endif %}
<th class="text-right">{{ 'Options'|get_lang }}</th>
</tr>
</thead>
@ -200,6 +210,15 @@
<td class="text-right" width="200">
{{ "#{item.price} #{tem.currency ?: item.currency}" }}
</td>
{% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 4) %}
<td class="text-center">
{% if item.tax_perc is null %}
{{ global_tax_perc }} %
{% else %}
{{ item.tax_perc }} %
{% endif %}
</td>
{% endif %}
<td class="text-right">
<a href="{{ _p.web_plugin ~ 'buycourses/src/services_edit.php?' ~ {'id': item.id}|url_encode() }}"
class="btn btn-info btn-sm">

@ -0,0 +1,14 @@
<div>
<dl>
<dt>{{ 'OrderDate'|get_plugin_lang('BuyCoursesPlugin') }}</dt>
<dd>{{ sale.date|api_convert_and_format_date(constant('DATE_TIME_FORMAT_LONG_24H')) }}</dd>
<dt>{{ 'OrderReference'|get_plugin_lang('BuyCoursesPlugin') }}</dt>
<dd>{{ sale.reference }}</dd>
<dt>{{ 'UserName'|get_lang }}</dt>
<dd>{{ user.complete_name }}</dd>
<dt>{{ 'Course'|get_lang }}</dt>
<dd>{{ sale.product }}</dd>
<dt>{{ 'SalePrice'|get_plugin_lang('BuyCoursesPlugin') }}</dt>
<dd>{{ sale.currency ~ ' ' ~ sale.price }}</dd>
</dl>
</div>

@ -3,14 +3,14 @@
<p>{{ 'PurchaseDetailsIntro'|get_plugin_lang('BuyCoursesPlugin') }}</p>
<dl>
<dt>{{ 'OrderDate'|get_plugin_lang('BuyCoursesPlugin') }}</dt>
<dd>{{ sale.date }}</dd>
<dd>{{ sale.date|api_convert_and_format_date(constant('DATE_TIME_FORMAT_LONG_24H')) }}</dd>
<dt>{{ 'OrderReference'|get_plugin_lang('BuyCoursesPlugin') }}</dt>
<dd>sale.reference</dd>
<dd>{{ sale.reference }}</dd>
<dt>{{ 'UserName'|get_lang }}</dt>
<dd>{{ user.complete_name }}</dd>
<dt>{{ 'Course'|get_lang }}</dt>
<dd>{{ sale.product }}</dd>
<dt>{{ 'ProductName'|get_plugin_lang('BuyCoursesPlugin') }}</dt>
<dd>{{ sale.product }}</dd>
<dt>{{ 'SalePrice'|get_plugin_lang('BuyCoursesPlugin') }}</dt>
<dd>{{ sale.currency ~ ' ' ~ sale.price }}</dd>
</dl>
<p>{{ 'BankAccountIntro'|get_plugin_lang('BuyCoursesPlugin')|format(sale.product) }}</p>

@ -20,6 +20,15 @@
<img alt="{{ course.title }}" class="img-rounded img-responsive"
src="{{ course.course_img ? course.course_img : 'session_default.png'|icon() }}">
</a>
{% if course.tax_enable %}
<div class="price-details-tax">
{{ 'Price'|get_plugin_lang('BuyCoursesPlugin')}} :
{{ course.currency == 'BRL' ? 'R$' : course.currency }} {{ course.price_without_tax }}
<br>
{{ course.tax_name }} ({{ course.tax_perc }}%):
{{ course.currency == 'BRL' ? 'R$' : course.currency }} {{ course.tax_amount }}
</div>
{% endif %}
<div class="price">
{{ 'Total'|get_plugin_lang('BuyCoursesPlugin')}} :
{{ course.currency == 'BRL' ? 'R$' : course.currency }} {{ course.price }}
@ -56,6 +65,15 @@
<div class="col-md-3">
<img alt="{{ session.name }}" class="img-rounded img-responsive""
src="{{ session.image ? session.image : 'session_default.png'|icon() }}">
{% if session.tax_enable %}
<div class="price-details-tax">
{{ 'Price'|get_plugin_lang('BuyCoursesPlugin')}} :
{{ session.currency == 'BRL' ? 'R$' : session.currency }} {{ session.price_without_tax }}
<br>
{{ session.tax_name }} ({{ session.tax_perc }}%):
{{ session.currency == 'BRL' ? 'R$' : session.currency }} {{ session.tax_amount }}
</div>
{% endif %}
<div class="price">
{{ 'Total'|get_plugin_lang('BuyCoursesPlugin')}} :
{{ session.currency == 'BRL' ? 'R$' : session.currency }} {{ session.price }}

@ -22,7 +22,7 @@
</h3>
<ul class="list-unstyled">
{% for teacher in course.teachers %}
<li><em class="fa fa-user"></em> {{ teacher }}</li>
<li><em class="fa fa-user"></em> {{ teacher.name }}</li>
{% endfor %}
</ul>
<p id="n-price" class="lead text-right" style="color: white;">

@ -27,6 +27,9 @@
<th class="text-center">{{ 'ProductType'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th>{{ 'Name'|get_lang }}</th>
<th>{{ 'UserName'|get_lang }}</th>
{% if invoicing_enable %}
<th class="text-center">{{ 'Invoice'|get_plugin_lang('BuyCoursesPlugin') }}</th>
{% endif %}
<th class="text-center">{{ 'Options'|get_lang }}</th>
</tr>
</thead>
@ -49,6 +52,16 @@
<td class="text-center">{{ sale.product_type }}</td>
<td>{{ sale.product_name }}</td>
<td>{{ sale.complete_user_name }}</td>
{% if invoicing_enable %}
<td class="text-center">
{% if sale.invoice == 1 %}
<a href="{{ _p.web_plugin ~ 'buycourses/src/invoice.php?' ~ {'invoice': sale.id, 'is_service': 0}|url_encode() }}" title="{{ 'InvoiceView'|get_plugin_lang('BuyCoursesPlugin') }}" >
<img src="{{ _p.web_img }}/icons/32/default.png" alt="{{ 'InvoiceView'|get_plugin_lang('BuyCoursesPlugin') }}" />
<br/>{{ sale.num_invoice }}
</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() }}"
@ -68,7 +81,7 @@
</div>
<script>
$(document).on('ready', function () {
$(function () {
$('[name="filter_type"]').on('change', function () {
var self = $(this);

@ -68,14 +68,22 @@
{% endif %}
</p>
<p><em class="fa fa-money"></em> <b>{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}</b>
{% if service.tax_enable %}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price_with_tax }}
{% else %}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price }}</p>
{% endif %}
</div>
<div class="service-buy">
<div class="row">
<div class="col-sm-6">
<div class="price">
{{ 'Total'|get_lang }}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price }}
{% if service.tax_enable %}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price_with_tax }}
{% else %}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price }}
{% endif %}
</div>
</div>
<div class="col-sm-6">

@ -56,7 +56,7 @@
</table>
</div>
<script>
$(document).on('ready', function () {
$(function () {
$("td a").click(function () {
var id = $(this).attr('tag');
var action = $(this).attr('id');

@ -19,10 +19,25 @@
<img alt="{{ service.name }}" class="img-rounded img-responsive"
src="{{ service.image ? service.image : 'session_default.png'|icon() }}">
</a>
{% if service.tax_enable %}
<div class="price-details-tax">
{{ 'Price'|get_plugin_lang('BuyCoursesPlugin')}} :
{{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price_without_tax }}
<br>
{{ service.tax_name }} ({{ service.tax_perc_show }}%):
{{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.tax_amount }}
</div>
<div class="price">
{{ 'Total'|get_plugin_lang('BuyCoursesPlugin')}} :
{{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price_with_tax }}
</div>
{% else %}
<div class="price">
{{ 'Total'|get_plugin_lang('BuyCoursesPlugin')}} :
{{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price }}
</div>
{% endif %}
</div>
<div class="col-md-9">
<div class="buy-item">
@ -54,7 +69,11 @@
<li>
<em class="fa-li fa fa-money" aria-hidden="true"></em>
{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price }}
{% if service.tax_enable %}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price_with_tax }}
{% else %}
: {{ service.currency == 'BRL' ? 'R$' : service.currency }} {{ service.price }}
{% endif %}
/ {{ service.duration_days == 0 ? 'NoLimit'|get_lang : service.duration_days ~ ' ' ~ 'Days'|get_lang }}
</li>
<li><em class="fa-li fa fa-user" aria-hidden="true"></em> {{ service.owner_name }}</li>

@ -28,6 +28,9 @@
<th class="text-center">{{ 'OrderStatus'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-center">{{ 'OrderDate'|get_plugin_lang('BuyCoursesPlugin') }}</th>
<th class="text-right">{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}</th>
{% if sale.invoice == 1 and invoicing_enable %}
<th class="text-right">{{ 'Invoice'|get_plugin_lang('BuyCoursesPlugin') }}</th>
{% endif %}
<th class="text-center">{{ 'ServiceSaleInfo'|get_plugin_lang('BuyCoursesPlugin') }}</th>
</tr>
</thead>
@ -47,6 +50,16 @@
</td>
<td class="text-center">{{ sale.date }}</td>
<td class="text-right">{{ sale.currency ~ ' ' ~ sale.price }}</td>
{% if invoicing_enable %}
<td class="text-center">
{% if sale.invoice == 1 %}
<a href="{{ _p.web_plugin ~ 'buycourses/src/invoice.php?' ~ {'invoice': sale.id, 'is_service': 1}|url_encode() }}" title="{{ 'InvoiceView'|get_plugin_lang('BuyCoursesPlugin') }}" >
<img src="{{ _p.web_img }}/icons/32/default.png" alt="{{ 'InvoiceView'|get_plugin_lang('BuyCoursesPlugin') }}" />
<br>{{ sale.num_invoice }}
</a>
{% endif %}
</td>
{% endif %}
<td class="text-center">
<a id="service_sale_info" tag="{{ sale.id }}" name="s_{{ sale.id }}"
class="btn btn-info btn-sm">{{ 'Info'|get_lang }}</a>
@ -60,7 +73,7 @@
</div>
<script>
$(document).on('ready', function () {
$(function () {
$("td a").click(function () {
var id = $(this).attr('tag');
var action = $(this).attr('id');

@ -30,7 +30,7 @@
<h3 class="page-header">{{ course.title }}</h3>
<ul class="items-teacher list-unstyled">
{% for teacher in course.teachers %}
<li><em class="fa fa-user"></em> {{ teacher }}</li>
<li><em class="fa fa-user" aria-hidden="true"></em> {{ teacher.name }}</li>
{% endfor %}
</ul>
<p>
@ -57,7 +57,7 @@
{% for course in session.courses %}
<dt>{{ course.title }}</dt>
{% for coach in course.coaches %}
<dd><em class="fa fa-user fa-fw"></em> {{ coach }}</dd>
<dd><em class="fa fa-user fa-fw" aria-hidden="true"></em> {{ coach.name }}</dd>
{% endfor %}
{% endfor %}
</dl>

@ -50,8 +50,6 @@ class CourseBlockPlugin extends Plugin
return $result ? $result : $result = new self();
}
///public function
public function install()
{
// Installing course settings

@ -1,5 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Config the plugin.
*

@ -31,6 +31,7 @@ $strings['ExpectionPlace'] = "Expection place";
$strings['DateExpediction'] = "Expediction date";
$strings['UseDateEndAccessSession'] = "Use end date of session access";
$strings['UseDateDownloadCertificate'] = "Use certificate download date";
$strings['UseDateGenerationCertificate'] = "Use certificate generation date";
$strings['UseCustomDate'] = "Use custom date";
$strings['LogosSeal'] = "Logos / Seals";
$strings['LogoLeft'] = "Logo left";

@ -31,6 +31,7 @@ $strings['ExpectionPlace'] = "Lugar expedición";
$strings['DateExpediction'] = "Fecha expedición";
$strings['UseDateEndAccessSession'] = "Usar fecha fin de acceso de la sesión";
$strings['UseDateDownloadCertificate'] = "Usar fecha de descarga del certificado";
$strings['UseDateGenerationCertificate'] = "Usar fecha de generación del certificado";
$strings['UseCustomDate'] = "Usar fechas personalizadas";
$strings['LogosSeal'] = "Logos / Sellos";
$strings['LogoLeft'] = "Logo izquierda";

@ -205,14 +205,17 @@ class CustomCertificatePlugin extends Plugin
/**
* Get certificate data.
*
* @param int $id The certificate
* @param int $id The certificate
* @param int $userId
*
* @return array
*/
public static function getCertificateData($id)
public static function getCertificateData($id, $userId)
{
$id = (int) $id;
if (empty($id)) {
$userId = (int) $userId;
if (empty($id) || empty($userId)) {
return [];
}
@ -221,8 +224,9 @@ class CustomCertificatePlugin extends Plugin
$sql = "SELECT cer.user_id AS user_id, cat.session_id AS session_id, cat.course_code AS course_code
FROM $certificateTable cer
INNER JOIN $categoryTable cat
ON (cer.cat_id = cat.id)
ON (cer.cat_id = cat.id AND cer.user_id = $userId)
WHERE cer.id = $id";
$rs = Database::query($sql);
if (Database::num_rows($rs) > 0) {
$row = Database::fetch_assoc($rs);
@ -246,12 +250,15 @@ class CustomCertificatePlugin extends Plugin
*
* @param certificate $certificate
* @param int $certId
* @param int $userId
*/
public static function redirectCheck($certificate, $certId)
public static function redirectCheck($certificate, $certId, $userId)
{
$certId = (int) $certId;
if (api_get_plugin_setting('customcertificate', 'enable_plugin_customcertificate') == 'true') {
$infoCertificate = CustomCertificatePlugin::getCertificateData($certId);
$userId = !empty($userId) ? $userId : api_get_user_id();
if (api_get_plugin_setting('customcertificate', 'enable_plugin_customcertificate') === 'true') {
$infoCertificate = self::getCertificateData($certId, $userId);
if (!empty($infoCertificate)) {
if ($certificate->user_id == api_get_user_id() && !empty($certificate->certificate_data)) {
$certificateId = $certificate->certificate_data['id'];

@ -1,7 +1,9 @@
<?php
/* For licensing terms, see /license.txt */
if (intval($_GET['default']) == 1) {
$isDefault = isset($_GET['default']) ? (int) $_GET['default'] : null;
if ($isDefault === 1) {
$cidReset = true;
}
@ -17,7 +19,7 @@ $enable = $plugin->get('enable_plugin_customcertificate') == 'true';
$accessUrlId = api_get_current_access_url_id();
$course_info = api_get_course_info();
if (intval($_GET['default']) == 1) {
if ($isDefault === 1) {
$courseId = 0;
$courseCode = '';
$sessionId = 0;
@ -72,15 +74,6 @@ $infoCertificate = Database::select(
],
'first'
);
if (!is_array($infoCertificate)) {
$infoCertificate = [
'type_date_expediction' => '',
'year' => '',
'month' => '',
'day' => '',
'date_change' => '',
];
}
$form = new FormValidator(
'formEdit',
@ -106,13 +99,13 @@ if ($form->validate()) {
'c_id' => $formValues['c_id'],
'session_id' => $formValues['session_id'],
'content_course' => $formValues['content_course'],
'contents_type' => intval($formValues['contents_type']),
'contents_type' => (int) $formValues['contents_type'],
'contents' => $contents,
'date_change' => intval($formValues['date_change']),
'date_start' => date("Y-m-d", strtotime($date_start)),
'date_end' => date("Y-m-d", strtotime($date_end)),
'place' => $formValues['place'],
'type_date_expediction' => intval($formValues['type_date_expediction']),
'type_date_expediction' => (int) $formValues['type_date_expediction'],
'day' => $formValues['day'],
'month' => $formValues['month'],
'year' => $formValues['year'],
@ -120,8 +113,8 @@ if ($form->validate()) {
'signature_text2' => $formValues['signature_text2'],
'signature_text3' => $formValues['signature_text3'],
'signature_text4' => $formValues['signature_text4'],
'margin_left' => intval($formValues['margin_left']),
'margin_right' => intval($formValues['margin_right']),
'margin_left' => (int) $formValues['margin_left'],
'margin_right' => (int) $formValues['margin_right'],
'certificate_default' => 0,
];
@ -182,10 +175,9 @@ if ($form->validate()) {
$infoCertificateDefault = Database::select(
'*',
$table,
['where' => ['certificate_default = ? ' => 1]],
['where' => ['access_url_id = ? AND certificate_default = ? ' => [$accessUrlId, 1]]],
'first'
);
if (!empty($infoCertificateDefault)) {
foreach ($fieldList as $field) {
if (!empty($infoCertificateDefault[$field]) && !$checkLogo[$field]) {
@ -215,7 +207,13 @@ if (empty($infoCertificate)) {
);
if (!is_array($infoCertificate)) {
$infoCertificate = [];
$infoCertificate = [
'type_date_expediction' => '',
'year' => '',
'month' => '',
'day' => '',
'date_change' => '',
];
}
if (!empty($infoCertificate)) {
$useDefault = true;
@ -245,7 +243,7 @@ $dir = '/';
$courseInfo = api_get_course_info();
$isAllowedToEdit = api_is_allowed_to_edit(null, true);
$editorConfig = [
'ToolbarSet' => ($isAllowedToEdit ? 'Documents' : 'DocumentsStudent'),
'ToolbarSet' => $isAllowedToEdit ? 'Documents' : 'DocumentsStudent',
'Width' => '100%',
'Height' => '300',
'cols-size' => [0, 12, 0],
@ -455,7 +453,7 @@ $form->addText(
);
$group = [];
$option1 = &$form->createElement(
$option = &$form->createElement(
'radio',
'type_date_expediction',
'',
@ -467,9 +465,9 @@ $option1 = &$form->createElement(
(($sessionId == 0) ? 'disabled' : ''),
]
);
$group[] = $option1;
$group[] = $option;
$option2 = &$form->createElement(
$option = &$form->createElement(
'radio',
'type_date_expediction',
'',
@ -480,9 +478,22 @@ $option2 = &$form->createElement(
'onclick' => 'javascript: typeDateExpedictionSwitchRadioButton();',
]
);
$group[] = $option2;
$group[] = $option;
$option4 = &$form->createElement(
$option = &$form->createElement(
'radio',
'type_date_expediction',
'',
get_lang('UseDateGenerationCertificate'),
4,
[
'id' => 'type_date_expediction_4',
'onclick' => 'javascript: typeDateExpedictionSwitchRadioButton();',
]
);
$group[] = $option;
$option = &$form->createElement(
'radio',
'type_date_expediction',
'',
@ -493,9 +504,9 @@ $option4 = &$form->createElement(
'onclick' => 'javascript: typeDateExpedictionSwitchRadioButton();',
]
);
$group[] = $option4;
$group[] = $option;
$option3 = &$form->createElement(
$option = &$form->createElement(
'radio',
'type_date_expediction',
'',
@ -506,7 +517,7 @@ $option3 = &$form->createElement(
'onclick' => 'javascript: typeDateExpedictionSwitchRadioButton();',
]
);
$group[] = $option3;
$group[] = $option;
$form->addGroup(
$group,
@ -939,6 +950,7 @@ function checkInstanceImage($certificateId, $imagePath, $field, $type = 'certifi
$table = Database::get_main_table(CustomCertificatePlugin::TABLE_CUSTOMCERTIFICATE);
$imagePath = Database::escape_string($imagePath);
$field = Database::escape_string($field);
$certificateId = (int) $certificateId;
$sql = "SELECT * FROM $table WHERE $field = '$imagePath'";
$res = Database::query($sql);

@ -3,7 +3,9 @@
use Chamilo\CourseBundle\Entity\CLpCategory;
if (intval($_GET['default']) == 1) {
$default = isset($_GET['default']) ? (int) $_GET['default'] : null;
if ($default === 1) {
$cidReset = true;
}
@ -19,7 +21,7 @@ if (!$enable) {
api_not_allowed(true, $plugin->get_lang('ToolDisabled'));
}
if (intval($_GET['default']) == 1) {
if ($default == 1) {
$courseId = 0;
$courseCode = '';
$sessionId = 0;
@ -32,6 +34,21 @@ if (intval($_GET['default']) == 1) {
$enableCourse = api_get_course_setting('customcertificate_course_enable', $courseCode) == 1 ? true : false;
$useDefault = api_get_course_setting('use_certificate_default', $courseCode) == 1 ? true : false;
}
if (empty($courseCode)) {
$courseCode = isset($_REQUEST['course_code']) ? Database::escape_string($_REQUEST['course_code']) : '';
$courseInfo = api_get_course_info($courseCode);
if (!empty($courseInfo)) {
$courseId = $courseInfo['real_id'];
}
} else {
$courseInfo = api_get_course_info($courseCode);
}
if (empty($sessionId)) {
$sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : '';
}
$accessUrlId = api_get_current_access_url_id();
$userList = [];
@ -101,17 +118,21 @@ if (empty($infoCertificate)) {
$workSpace = intval(297 - $infoCertificate['margin_left'] - $infoCertificate['margin_right']);
$widthCell = intval($workSpace / 6);
$htmlText = '<html>';
$htmlText .= '
$htmlList = [];
$currentLocalTime = api_get_local_time();
foreach ($userList as $userInfo) {
$htmlText = '<html>';
$htmlText .= '
<link rel="stylesheet"
type="text/css"
href="'.api_get_path(WEB_PLUGIN_PATH).'customcertificate/resources/css/certificate.css">';
$htmlText .= '
$htmlText .= '
<link rel="stylesheet"
type="text/css"
href="'.api_get_path(WEB_CSS_PATH).'document.css">';
$htmlText .= '<body>';
foreach ($userList as $userInfo) {
$htmlText .= '<body>';
$studentId = $userInfo['user_id'];
if (empty($infoCertificate['background'])) {
@ -162,19 +183,19 @@ foreach ($userList as $userInfo) {
$htmlText .= '</tr>';
$htmlText .= '</table>';
$all_user_info = DocumentManager::get_all_info_to_certificate(
$allUserInfo = DocumentManager::get_all_info_to_certificate(
$studentId,
$courseCode,
true
false
);
$myContentHtml = $infoCertificate['content_course'];
$myContentHtml = str_replace(chr(13).chr(10).chr(13).chr(10), chr(13).chr(10), $myContentHtml);
$info_to_be_replaced_in_content_html = $all_user_info[0];
$info_to_replace_in_content_html = $all_user_info[1];
$infoToBeReplacedInContentHtml = $allUserInfo[0];
$infoToReplaceInContentHtml = $allUserInfo[1];
$myContentHtml = str_replace(
$info_to_be_replaced_in_content_html,
$info_to_replace_in_content_html,
$infoToBeReplacedInContentHtml,
$infoToReplaceInContentHtml,
$myContentHtml
);
@ -232,9 +253,13 @@ foreach ($userList as $userInfo) {
'............'
);
}
} elseif ($infoCertificate['type_date_expediction'] == 4) {
$dateExpediction .= $plugin->get_lang('to').$infoToReplaceInContentHtml[9]; //date_certificate_no_time
} else {
$dateInfo = api_get_local_time($sessionInfo['access_end_date']);
$dateExpediction .= $plugin->get_lang('to').api_format_date($dateInfo, DATE_FORMAT_LONG);
if (!empty($sessionInfo)) {
$dateInfo = api_get_local_time($sessionInfo['access_end_date']);
$dateExpediction .= $plugin->get_lang('to').api_format_date($dateInfo, DATE_FORMAT_LONG);
}
}
}
@ -450,24 +475,50 @@ foreach ($userList as $userInfo) {
}
$htmlText .= '</div>';
}
$htmlText .= '</body></html>';
$fileName = 'certificate_'.$courseInfo['code'].'_'.$userInfo['complete_name'].'_'.$currentLocalTime;
$htmlList[$fileName] = $htmlText;
}
$fileList = [];
$archivePath = api_get_path(SYS_ARCHIVE_PATH).'certificates/';
if (!is_dir($archivePath)) {
mkdir($archivePath, api_get_permissions_for_new_directories());
}
foreach ($htmlList as $fileName => $content) {
$fileName = api_replace_dangerous_char($fileName);
$params = [
'filename' => $fileName,
'pdf_title' => 'Certificate',
'pdf_description' => '',
'format' => 'A4-L',
'orientation' => 'L',
'left' => 15,
'top' => 15,
'bottom' => 0,
];
$pdf = new PDF($params['format'], $params['orientation'], $params);
if (count($htmlList) == 1) {
$pdf->content_to_pdf($content, '', $fileName, null, 'D', false, null, false, false, false);
exit;
} else {
$filePath = $archivePath.$fileName.'.pdf';
$pdf->content_to_pdf($content, '', $fileName, null, 'F', true, $filePath, false, false, false);
$fileList[] = $filePath;
}
}
if (!empty($fileList)) {
$zipFile = $archivePath.'certificates_'.api_get_unique_id().'.zip';
$zipFolder = new PclZip($zipFile);
foreach ($fileList as $file) {
$zipFolder->add($file, PCLZIP_OPT_REMOVE_ALL_PATH);
}
$name = 'certificates_'.$courseInfo['code'].'_'.$currentLocalTime.'.zip';
DocumentManager::file_send_for_download($zipFile, true, $name);
exit;
}
$htmlText .= '</body></html>';
$fileName = 'certificate_'.date("Ymd_His");
$params = [
'filename' => $fileName,
'pdf_title' => "Certificate",
'pdf_description' => '',
'format' => 'A4-L',
'orientation' => 'L',
'left' => 15,
'top' => 15,
'bottom' => 0,
];
$pdf = new PDF($params['format'], $params['orientation'], $params);
$pdf->content_to_pdf($htmlText, '', $fileName, null, 'D', false, null, false, false, false);
exit;
function getIndexFiltered($index)
{
@ -476,12 +527,16 @@ function getIndexFiltered($index)
$lines = explode(chr(13).chr(10), $txt);
$text1 = '';
for ($x = 0; $x < 47; $x++) {
$text1 .= $lines[$x].chr(13).chr(10);
if (isset($lines[$x])) {
$text1 .= $lines[$x].chr(13).chr(10);
}
}
$text2 = '';
for ($x = 47; $x < 94; $x++) {
$text2 .= $lines[$x].chr(13).chr(10);
if (isset($lines[$x])) {
$text2 .= $lines[$x].chr(13).chr(10);
}
}
$showLeft = str_replace(chr(13).chr(10), "<br/>", $text1);

@ -75,9 +75,6 @@ switch ($action) {
$tpl = new Template($plugin->get_lang('plugin_title'));
$tpl->assign('terms', $terms);
$tpl->assign('form', $form->returnForm());
//$url = api_get_path(WEB_PLUGIN_PATH).'studentfollowup/posts.php?';
//$tpl->assign('post_url', $url);
$content = $tpl->fetch('/'.$plugin->get_name().'/view/terms.html.twig');
// Assign into content
$tpl->assign('content', $content);

@ -23,7 +23,7 @@
</div>
</div>
<script>
$(document).on('ready', function () {
$(function () {
$('form[name="frm_grading_electronic"]').on('submit', function (e) {
e.preventDefault();

@ -3,6 +3,9 @@
namespace Chamilo\PluginBundle\Entity\ImsLti;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\GradebookEvaluation;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
@ -42,13 +45,13 @@ class ImsLtiTool
/**
* @var string
*
* @ORM\Column(name="consumer_key", type="string")
* @ORM\Column(name="consumer_key", type="string", nullable=true)
*/
private $consumerKey = '';
/**
* @var string
*
* @ORM\Column(name="shared_secret", type="string")
* @ORM\Column(name="shared_secret", type="string", nullable=true)
*/
private $sharedSecret = '';
/**
@ -60,9 +63,63 @@ class ImsLtiTool
/**
* @var bool
*
* @ORM\Column(name="is_global", type="boolean")
* @ORM\Column(name="active_deep_linking", type="boolean", nullable=false, options={"default": false})
*/
private $isGlobal = false;
private $activeDeepLinking = false;
/**
* @var null|string
*
* @ORM\Column(name="privacy", type="text", nullable=true, options={"default": null})
*/
private $privacy = null;
/**
* @var Course|null
*
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course")
* @ORM\JoinColumn(name="c_id", referencedColumnName="id")
*/
private $course = null;
/**
* @var GradebookEvaluation|null
*
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\GradebookEvaluation")
* @ORM\JoinColumn(name="gradebook_eval_id", referencedColumnName="id", onDelete="SET NULL")
*/
private $gradebookEval = null;
/**
* @var ImsLtiTool|null
*
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool", mappedBy="parent")
*/
private $children;
/**
* ImsLtiTool constructor.
*/
public function __construct()
{
$this->description = null;
$this->customParams = null;
$this->activeDeepLinking = false;
$this->course = null;
$this->gradebookEval =null;
$this->privacy = null;
$this->children = new ArrayCollection();
$this->consumerKey = null;
$this->sharedSecret = null;
}
/**
* @return int
@ -191,18 +248,27 @@ class ImsLtiTool
*/
public function isGlobal()
{
return $this->isGlobal;
return $this->course === null;
}
/**
* @param bool $isGlobal
* @return ImsLtiTool
* @param array $params
*
* @return null|string
*/
public function setIsGlobal($isGlobal)
public function encodeCustomParams(array $params)
{
$this->isGlobal = $isGlobal;
if (empty($params)) {
return null;
}
return $this;
$pairs = [];
foreach ($params as $key => $value) {
$pairs[] = "$key=$value";
}
return implode("\n", $pairs);
}
/**
@ -210,12 +276,219 @@ class ImsLtiTool
*/
public function parseCustomParams()
{
$strings = explode($this->customParams, "\n");
$pairs = explode('=', $strings);
if (empty($this->customParams)) {
return [];
}
$params = [];
$strings = explode("\n", $this->customParams);
foreach ($strings as $string) {
if (empty($string)) {
continue;
}
$pairs = explode('=', $string, 2);
$key = self::parseCustomKey($pairs[0]);
$value = $pairs[1];
$params['custom_'.$key] = $value;
}
return $params;
}
/**
* Map the key from custom param.
*
* @param string $key
*
* @return string
*/
private static function parseCustomKey($key)
{
$newKey = '';
$key = strtolower($key);
$split = str_split($key);
foreach ($split as $char) {
if (
($char >= 'a' && $char <= 'z') || ($char >= '0' && $char <= '9')
) {
$newKey .= $char;
continue;
}
$newKey .= '_';
}
return $newKey;
}
/**
* Set activeDeepLinking.
*
* @param bool $activeDeepLinking
*
* @return ImsLtiTool
*/
public function setActiveDeepLinking($activeDeepLinking)
{
$this->activeDeepLinking = $activeDeepLinking;
return $this;
}
/**
* Get activeDeepLinking.
*
* @return bool
*/
public function isActiveDeepLinking()
{
return $this->activeDeepLinking;
}
/**
* Get course.
*
* @return Course|null
*/
public function getCourse()
{
return $this->course;
}
/**
* Set course.
*
* @param Course|null $course
*
* @return ImsLtiTool
*/
public function setCourse(Course $course = null)
{
$this->course = $course;
return $this;
}
/**
* Get gradebookEval.
*
* @return GradebookEvaluation|null
*/
public function getGradebookEval()
{
return $this->gradebookEval;
}
/**
* Set gradebookEval.
*
* @param GradebookEvaluation|null $gradebookEval
*
* @return ImsLtiTool
*/
public function setGradebookEval($gradebookEval)
{
$this->gradebookEval = $gradebookEval;
return [
'key' => 'custom_'.$pairs[0],
'value' => $pairs[1]
];
return $this;
}
/**
* Get privacy.
*
* @return null|string
*/
public function getPrivacy()
{
return $this->privacy;
}
/**
* Set privacy.
*
* @param bool $shareName
* @param bool $shareEmail
* @param bool $sharePicture
*
* @return ImsLtiTool
*/
public function setPrivacy($shareName = false, $shareEmail = false, $sharePicture = false)
{
$this->privacy = serialize(
[
'share_name' => $shareName,
'share_email' => $shareEmail,
'share_picture' => $sharePicture,
]
);
return $this;
}
/**
* @return bool
*/
public function isSharingName()
{
$unserialize = $this->unserializePrivacy();
return (bool) $unserialize['share_name'];
}
/**
* @return bool
*/
public function isSharingEmail()
{
$unserialize = $this->unserializePrivacy();
return (bool) $unserialize['share_email'];
}
/**
* @return bool
*/
public function isSharingPicture()
{
$unserialize = $this->unserializePrivacy();
return (bool) $unserialize['share_picture'];
}
/**
* @return mixed
*/
public function unserializePrivacy()
{
return \UnserializeApi::unserialize('not_allowed_classes', $this->privacy);
}
/**
* @return ImsLtiTool|null
*/
public function getParent()
{
return $this->parent;
}
/**
* @param ImsLtiTool $parent
*
* @return ImsLtiTool
*/
public function setParent(ImsLtiTool $parent)
{
$this->parent = $parent;
$this->sharedSecret = $parent->getSharedSecret();
$this->consumerKey = $parent->getConsumerKey();
$this->privacy = $parent->getPrivacy();
return $this;
}
}

@ -1,24 +1,99 @@
IMS/LTI plugin
===
Version 1.0 (beta)
Version 1.5.1 (beta)
Installation
------------
1. Install the plugin from Plugin page
2. Enable the plugin from Plugin Settings page
3. Assign to the Administrator region
This plugin is meant to be later integrated into Chamilo (in a major version
release).
As platform admin you can register external tools available for all courses.
IMS/LTI defines the possibility to integrate tools or content into Chamilo.
This plugin allows the integration of a new tool into courses, obtaining
data back from those tools and recording them as gradebook "external" activities.
As a platform admin, you can register external tools available for all courses.
You need set the tools settings in the IMS/LTI administration page.
Then the registered tools should be add in each course individually.
Then the registered tools should be added in each course individually.
As teacher you can register external tools available only for the current course.
You need follow the link in the IMS/LTI block located in the Course Settings tool.
Then select a previously tool registered or register a new external tool.
As a teacher, you can register external tools available only for the current
course. You need follow the link in the IMS/LTI block located in the Course
Settings tool. Then select a previously tool registered or register a new
external tool.
This plugin is meant to be later integrated into Chamilo (in a major version release).
# Changelog
IMS/LTI defines the possibility to integrate tools or content into Chamilo.
This plugin allows the integration of a new tool into courses, without (for now) obtaining any data back from those tools.
It will gradually be developed to support IMS/LTI content items.
## v1.1
* Support for Deep-Linking added.
* Support for outcomes services. And register score on course gradebook.
## v1.2
* Register course in which the tool was added.
* Register parent tool from which the new tool comes from.
## v1.3
* Privacy settings added. Allow to indicate id the launcher's data
should be sent in request.
## v1.4
* Allow create external tools when there is no key/secret available for launch
## v1.5
* Plugin has passed the tests from the LTI Certification suite.
* Add support for substitution of variable.
See `ImsLti::getSubstitutableParams()`.
* Outcome services has a unique URL and sourced ID.
# Installation
1. Install the plugin from the Plugins page
2. Enable the plugin from the IMS/LTI Plugin Settings page
3. Assign to the Administrator region (in the regions management page)
# Upgrading
Run this changes on database:
## To v1.1
```sql
ALTER TABLE plugin_ims_lti_tool
ADD active_deep_linking TINYINT(1) DEFAULT '0' NOT NULL,
CHANGE id id INT AUTO_INCREMENT NOT NULL,
CHANGE launch_url launch_url VARCHAR(255) NOT NULL;
ALTER TABLE plugin_ims_lti_tool ADD gradebook_eval_id INT DEFAULT NULL;
ALTER TABLE plugin_ims_lti_tool ADD CONSTRAINT FK_C5E47F7C82F80D8B
FOREIGN KEY (gradebook_eval_id) REFERENCES gradebook_evaluation (id)
ON DELETE SET NULL;
CREATE INDEX IDX_C5E47F7C82F80D8B ON plugin_ims_lti_tool (gradebook_eval_id);
```
## To v1.2
```sql
ALTER TABLE plugin_ims_lti_tool ADD c_id INT DEFAULT NULL;
ALTER TABLE plugin_ims_lti_tool ADD CONSTRAINT FK_C5E47F7C91D79BD3
FOREIGN KEY (c_id) REFERENCES course (id);
CREATE INDEX IDX_C5E47F7C91D79BD3 ON plugin_ims_lti_tool (c_id);
ALTER TABLE plugin_ims_lti_tool ADD parent_id INT DEFAULT NULL, DROP is_global;
ALTER TABLE plugin_ims_lti_tool ADD CONSTRAINT FK_C5E47F7C727ACA70
FOREIGN KEY (parent_id) REFERENCES plugin_ims_lti_tool (id);
CREATE INDEX IDX_C5E47F7C727ACA70 ON plugin_ims_lti_tool (parent_id);
```
## To v1.3
```sql
ALTER TABLE plugin_ims_lti_tool ADD privacy LONGTEXT DEFAULT NULL;
```
## To v1.4
```sql
ALTER TABLE plugin_ims_lti_tool
CHANGE consumer_key consumer_key VARCHAR(255) DEFAULT NULL,
CHANGE shared_secret shared_secret VARCHAR(255) DEFAULT NULL;
```
## To v1.5.1
```sql
ALTER TABLE plugin_ims_lti_tool
DROP FOREIGN KEY FK_C5E47F7C727ACA70,
ADD FOREIGN KEY (parent_id) REFERENCES plugin_ims_lti_tool (id) ON DELETE CASCADE ON UPDATE RESTRICT;
```

@ -11,6 +11,8 @@ $plugin = ImsLtiPlugin::create();
$em = Database::getManager();
$tools = $em->getRepository('ChamiloPluginBundle:ImsLti\ImsLtiTool')->findAll();
$interbreadcrumb[] = ['url' => api_get_path(WEB_CODE_PATH).'admin/index.php', 'name' => get_lang('PlatformAdmin')];
$template = new Template($plugin->get_title());
$template->assign('tools', $tools);

@ -12,14 +12,8 @@ $plugin = ImsLtiPlugin::create();
$em = Database::getManager();
$form = new FormValidator('ism_lti_create_tool');
$form->addText('name', get_lang('Name'));
$form->addText('base_url', $plugin->get_lang('LaunchUrl'));
$form->addText('consumer_key', $plugin->get_lang('ConsumerKey'));
$form->addText('shared_secret', $plugin->get_lang('SharedSecret'));
$form->addTextarea('description', get_lang('Description'), ['rows' => 10]);
$form->addTextarea('custom_params', $plugin->get_lang('CustomParams'));
$form->addButtonCreate($plugin->get_lang('AddExternalTool'));
$form = new FrmAdd('ism_lti_create_tool');
$form->build();
if ($form->validate()) {
$formValues = $form->exportValues();
@ -27,12 +21,45 @@ if ($form->validate()) {
$externalTool = new ImsLtiTool();
$externalTool
->setName($formValues['name'])
->setDescription($formValues['description'])
->setLaunchUrl($formValues['base_url'])
->setConsumerKey($formValues['consumer_key'])
->setSharedSecret($formValues['shared_secret'])
->setCustomParams($formValues['custom_params'])
->setIsGlobal(true);
->setDescription(
empty($formValues['description']) ? null : $formValues['description']
)
->setCustomParams(
empty($formValues['custom_params']) ? null : $formValues['custom_params']
)
->setCourse(null)
->setActiveDeepLinking(
isset($formValues['deep_linking'])
)
->setPrivacy(
isset($formValues['share_name']),
isset($formValues['share_email']),
isset($formValues['share_picture'])
);
if (empty($formValues['consumer_key']) && empty($formValues['shared_secret'])) {
try {
$launchUrl = $plugin->getLaunchUrlFromCartridge($formValues['launch_url']);
} catch (Exception $e) {
Display::addFlash(
Display::return_message($e->getMessage(), 'error')
);
header('Location: '.api_get_path(WEB_PLUGIN_PATH).'ims_lti/admin.php');
exit;
}
$externalTool->setLaunchUrl($launchUrl);
} else {
$externalTool
->setLaunchUrl($formValues['launch_url'])
->setConsumerKey(
empty($formValues['consumer_key']) ? null : $formValues['consumer_key']
)
->setSharedSecret(
empty($formValues['shared_secret']) ? null : $formValues['shared_secret']
);
}
$em->persist($externalTool);
$em->flush();
@ -45,11 +72,18 @@ if ($form->validate()) {
exit;
}
$template = new Template($plugin->get_lang('AddExternalTool'));
$form->setDefaultValues();
$interbreadcrumb[] = ['url' => api_get_path(WEB_CODE_PATH).'admin/index.php', 'name' => get_lang('PlatformAdmin')];
$interbreadcrumb[] = ['url' => api_get_path(WEB_PLUGIN_PATH).'ims_lti/admin.php', 'name' => $plugin->get_title()];
$pageTitle = $plugin->get_lang('AddExternalTool');
$template = new Template($pageTitle);
$template->assign('form', $form->returnForm());
$content = $template->fetch('ims_lti/view/add.tpl');
$template->assign('header', $plugin->get_title());
$template->assign('header', $pageTitle);
$template->assign('content', $content);
$template->display_one_col_template();

@ -29,34 +29,42 @@ if (!$tool) {
exit;
}
$form = new FormValidator('ims_lti_edit_tool');
$form->addText('name', get_lang('Name'));
$form->addTextarea('description', get_lang('Description'), ['rows' => 10]);
$form->addText('url', $plugin->get_lang('LaunchUrl'));
$form->addText('consumer_key', $plugin->get_lang('ConsumerKey'));
$form->addText('shared_secret', $plugin->get_lang('SharedSecret'));
$form->addTextarea('custom_params', $plugin->get_lang('CustomParams'));
$form->addButtonSave(get_lang('Save'));
$form->addHidden('id', $tool->getId());
$form->setDefaults([
'name' => $tool->getName(),
'description' => $tool->getDescription(),
'url' => $tool->getLaunchUrl(),
'consumer_key' => $tool->getConsumerKey(),
'shared_secret' => $tool->getSharedSecret(),
'custom_params' => $tool->getCustomParams()
]);
$form = new FrmEdit('ims_lti_edit_tool', [], $tool);
$form->build();
if ($form->validate()) {
$formValues = $form->exportValues();
$tool
->setName($formValues['name'])
->setDescription($formValues['description'])
->setLaunchUrl($formValues['url'])
->setConsumerKey($formValues['consumer_key'])
->setSharedSecret($formValues['shared_secret'])
->setCustomParams($formValues['custom_params']);
->setDescription(
empty($formValues['description']) ? null : $formValues['description']
)
->setCustomParams(
empty($formValues['custom_params']) ? null : $formValues['custom_params']
)
->setPrivacy(
!empty($formValues['share_name']),
!empty($formValues['share_email']),
!empty($formValues['share_picture'])
);
if (null === $tool->getParent()) {
$tool
->setLaunchUrl($formValues['launch_url'])
->setConsumerKey(
empty($formValues['consumer_key']) ? null : $formValues['consumer_key']
)
->setSharedSecret(
empty($formValues['shared_secret']) ? null : $formValues['shared_secret']
);
}
if (null === $tool->getParent() ||
(null !== $tool->getParent() && !$tool->getParent()->isActiveDeepLinking())
) {
$tool->setActiveDeepLinking(!empty($formValues['deep_linking']));
}
$em->persist($tool);
$em->flush();
@ -69,6 +77,11 @@ if ($form->validate()) {
exit;
}
$form->setDefaultValues();
$interbreadcrumb[] = ['url' => api_get_path(WEB_CODE_PATH).'admin/index.php', 'name' => get_lang('PlatformAdmin')];
$interbreadcrumb[] = ['url' => api_get_path(WEB_PLUGIN_PATH).'ims_lti/admin.php', 'name' => $plugin->get_title()];
$template = new Template($plugin->get_lang('EditExternalTool'));
$template->assign('form', $form->returnForm());

@ -1,19 +1,22 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\UserBundle\Entity\User;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool;
use Chamilo\UserBundle\Entity\User;
require_once __DIR__.'/../../main/inc/global.inc.php';
require './OAuthSimple.php';
api_protect_course_script();
api_protect_course_script(false);
api_block_anonymous_users(false);
$em = Database::getManager();
/** @var ImsLtiTool $tool */
$tool = isset($_GET['id']) ? $em->find('ChamiloPluginBundle:ImsLti\ImsLtiTool', intval($_GET['id'])) : 0;
$tool = isset($_GET['id'])
? $em->find('ChamiloPluginBundle:ImsLti\ImsLtiTool', (int) $_GET['id'])
: null;
if (!$tool) {
api_not_allowed(true);
@ -21,61 +24,151 @@ if (!$tool) {
/** @var ImsLtiPlugin $imsLtiPlugin */
$imsLtiPlugin = ImsLtiPlugin::create();
/** @var Session $session */
$session = $em->find('ChamiloCoreBundle:Session', api_get_session_id());
/** @var Course $course */
$course = $em->find('ChamiloCoreBundle:Course', api_get_course_int_id());
/** @var User $user */
$user = $em->find('ChamiloUserBundle:User', api_get_user_id());
$siteName = api_get_setting('siteName');
$institution = api_get_setting('Institution');
$toolUserId = "$siteName - $institution - {$user->getId()}";
$toolUserId = api_replace_dangerous_char($toolUserId);
$params = [
'lti_message_type' => 'basic-lti-launch-request',
'lti_version' => 'LTI-1p0',
'resource_link_id' => $tool->getId(),
'resource_link_title' => $tool->getName(),
'resource_link_description' => $tool->getDescription(),
'user_id' => $toolUserId,
'roles' => api_is_teacher() ? 'Instructor' : 'Student',
'lis_person_name_given' => $user->getFirstname(),
'lis_person_name_family' => $user->getLastname(),
'lis_person_name_full' => $user->getCompleteName(),
'lis_person_contact_email_primary' => $user->getEmail(),
'context_id' => $course->getId(),
'context_label' => $course->getCode(),
'context_title' => $course->getTitle(),
'launch_presentation_locale' => api_get_language_isocode(),
'launch_presentation_document_target' => 'embed',
'tool_consumer_info_product_family_code' => 'Chamilo LMS',
'tool_consumer_info_version' => api_get_version(),
'tool_consumer_instance_guid' => api_get_setting('InstitutionUrl'),
'tool_consumer_instance_name' => $siteName,
'tool_consumer_instance_url' => api_get_path(WEB_PATH),
'tool_consumer_instance_contact_email' => api_get_setting('emailAdministrator'),
];
$oauth = new OAuthSimple(
$tool->getConsumerKey(),
$tool->getSharedSecret()
);
$oauth->setAction('post');
$oauth->setSignatureMethod('HMAC-SHA1');
$oauth->setParameters($params);
$result = $oauth->sign(array(
'path' => $tool->getLaunchUrl(),
'parameters' => array(
'oauth_callback' => 'about:blank'
)
));
$pluginPath = api_get_path(WEB_PLUGIN_PATH).'ims_lti/';
$toolUserId = ImsLtiPlugin::generateToolUserId($user->getId());
$platformDomain = str_replace(['https://', 'http://'], '', api_get_setting('InstitutionUrl'));
$params = [];
$params['lti_version'] = 'LTI-1p0';
if ($tool->isActiveDeepLinking()) {
$params['lti_message_type'] = 'ContentItemSelectionRequest';
$params['content_item_return_url'] = $pluginPath.'item_return.php';
$params['accept_media_types'] = '*/*';
$params['accept_presentation_document_targets'] = 'iframe';
//$params['accept_unsigned'];
//$params['accept_multiple'];
//$params['accept_copy_advice'];
//$params['auto_create']';
$params['title'] = $tool->getName();
$params['text'] = $tool->getDescription();
$params['data'] = 'tool:'.$tool->getId();
} else {
$params['lti_message_type'] = 'basic-lti-launch-request';
$params['resource_link_id'] = $tool->getId();
$params['resource_link_title'] = $tool->getName();
$params['resource_link_description'] = $tool->getDescription();
$toolEval = $tool->getGradebookEval();
if (!empty($toolEval)) {
$params['lis_result_sourcedid'] = json_encode(
['e' => $toolEval->getId(), 'u' => $user->getId(), 'l' => uniqid(), 'lt' => time()]
);
$params['lis_outcome_service_url'] = api_get_path(WEB_PATH).'lti/os';
$params['lis_person_sourcedid'] = "$platformDomain:$toolUserId";
$params['lis_course_section_sourcedid'] = "$platformDomain:".$course->getId();
if ($session) {
$params['lis_course_section_sourcedid'] .= ':'.$session->getId();
}
}
}
$params['user_id'] = $toolUserId;
if ($tool->isSharingPicture()) {
$params['user_image'] = UserManager::getUserPicture($user->getId());
}
$params['roles'] = ImsLtiPlugin::getUserRoles($user);
if ($tool->isSharingName()) {
$params['lis_person_name_given'] = $user->getFirstname();
$params['lis_person_name_family'] = $user->getLastname();
$params['lis_person_name_full'] = $user->getFirstname().' '.$user->getLastname();
}
if ($tool->isSharingEmail()) {
$params['lis_person_contact_email_primary'] = $user->getEmail();
}
if (DRH === $user->getStatus()) {
$scopeMentor = ImsLtiPlugin::getRoleScopeMentor($user);
if (!empty($scopeMentor)) {
$params['role_scope_mentor'] = $scopeMentor;
}
}
$params['context_id'] = $course->getId();
$params['context_type'] = 'CourseSection';
$params['context_label'] = $course->getCode();
$params['context_title'] = $course->getTitle();
$params['launch_presentation_locale'] = api_get_language_isocode();
$params['launch_presentation_document_target'] = 'iframe';
$params['tool_consumer_info_product_family_code'] = 'Chamilo LMS';
$params['tool_consumer_info_version'] = api_get_version();
$params['tool_consumer_instance_guid'] = $platformDomain;
$params['tool_consumer_instance_name'] = api_get_setting('siteName');
$params['tool_consumer_instance_url'] = api_get_path(WEB_PATH);
$params['tool_consumer_instance_contact_email'] = api_get_setting('emailAdministrator');
$params['oauth_callback'] = 'about:blank';
$customParams = $tool->parseCustomParams();
$imsLtiPlugin->trimParams($customParams);
$substitutables = ImsLti::getSubstitutableParams($user, $course, $session);
$variables = array_keys($substitutables);
foreach ($customParams as $customKey => $customValue) {
if (in_array($customValue, $variables)) {
$val = $substitutables[$customValue];
if (is_array($val)) {
$val = current($val);
if (array_key_exists($val, $params)) {
$customParams[$customKey] = $params[$val];
continue;
} else {
$val = false;
}
}
if (false === $val) {
$customParams[$customKey] = $customValue;
continue;
}
$customParams[$customKey] = $substitutables[$customValue];
}
}
$params += $customParams;
$imsLtiPlugin->trimParams($params);
if (!empty($tool->getConsumerKey()) && !empty($tool->getSharedSecret())) {
$consumer = new OAuthConsumer(
$tool->getConsumerKey(),
$tool->getSharedSecret(),
null
);
$hmacMethod = new OAuthSignatureMethod_HMAC_SHA1();
$request = OAuthRequest::from_consumer_and_token(
$consumer,
'',
'POST',
$tool->getLaunchUrl(),
$params
);
$request->sign_request($hmacMethod, $consumer, '');
$params = $request->get_parameters();
}
$imsLtiPlugin->removeUrlParamsFromLaunchParams($tool, $params);
?>
<!DOCTYPE html>
<html>
@ -85,16 +178,10 @@ $result = $oauth->sign(array(
<body>
<form action="<?php echo $tool->getLaunchUrl() ?>" name="ltiLaunchForm" method="post"
encType="application/x-www-form-urlencoded">
<?php
foreach ($result["parameters"] as $key => $values) { //Dump parameters
echo '<input type="hidden" name="'.$key.'" value="'.$values.'" />';
}
?>
<input type="submit" value="Press to continue to external tool"/>
<?php foreach ($params as $key => $value) { ?>
<input type="hidden" name="<?php echo $key ?>" value="<?php echo htmlspecialchars($value) ?>">
<?php } ?>
</form>
<script language="javascript">
document.ltiLaunchForm.submit();
</script>
<script>document.ltiLaunchForm.submit();</script>
</body>
</html>

@ -13,6 +13,7 @@ $strings['LaunchUrl'] = 'Launch URL';
$strings['ConsumerKey'] = 'Consumer key';
$strings['SharedSecret'] = 'Shared secret';
$strings['CustomParams'] = 'Custom params';
$strings['CustomParamsHelp'] = 'Custom params required by the Tool Provider. Format: <code>name=value</code>';
$strings['ToolName'] = 'Tool name';
$strings['ToolNotAdded'] = 'Tool not added';
$strings['AvailableTools'] = 'Available tools';
@ -22,3 +23,18 @@ $strings['IsGlobal'] = 'Is global';
$strings['EditExternalTool'] = 'Edit external tool';
$strings['ToolDeleted'] = 'Tool deleted';
$strings['ToolAdded'] = 'Tool added';
$strings['PressToContinue'] = 'Press to continue to external tool';
$strings['ConfigureExternalTool'] = 'Configure external tools';
$strings['SupportDeepLinking'] = 'Support Deep-Linking';
$strings['ScoreNotSet'] = 'Score not set';
$strings['ScoreForXUserIsYScore'] = 'Score for %s is %s';
$strings['ToolsAdded'] = 'Added tools';
$strings['ToolEdited'] = 'Tool edited';
$strings['ShareLauncherName'] = 'Share launcher\'s name';
$strings['ShareLauncherEmail'] = 'Share launcher\'s email';
$strings['ShareLauncherPicture'] = 'Share launcher\'s picture';
$strings['NoTool'] = 'Tool not exists';
$strings['ToolAddedOnCourseX'] = 'Tool addeed on course <strong>%s</strong>.';
$strings['SupportDeppLinkingHelp'] = 'Contact your Tool Provider to verify if Deep Linking support is mandatory';
$strings['NoAccessToUrl'] = 'No access to URL';
$strings['LaunchUrlNotFound'] = 'Launch URL not found';

@ -13,6 +13,7 @@ $strings['LaunchUrl'] = 'URL de démarrage (Launch URL)';
$strings['ConsumerKey'] = 'Clef consommateur (Consumer key)';
$strings['SharedSecret'] = 'Secret partagé (Shared secret)';
$strings['CustomParams'] = 'Paramètres personnalisés';
$strings['CustomParamsHelp'] = 'Paramètres personnalisés requis par le fournisseur d\'outils. Format: <code>nom=valeur</code>.';
$strings['ToolName'] = 'Nom de l\'outil';
$strings['ToolNotAdded'] = 'Outil non ajouté';
$strings['AvailableTools'] = 'Outils disponibles';
@ -22,3 +23,16 @@ $strings['IsGlobal'] = 'Est global';
$strings['EditExternalTool'] = 'Éditer outil externe';
$strings['ToolDeleted'] = 'Outil supprimé';
$strings['ToolAdded'] = 'Outil ajouté';
$strings['PressToContinue'] = 'Appuyez sur pour continuer à l\'outil externe';
$strings['ConfigureExternalTool'] = 'Configure external tools';
$strings['SupportDeepLinking'] = 'Support Deep-Linking';
$strings['ScoreNotSet'] = 'Score non défini';
$strings['ScoreForXUserIsYScore'] = 'Score pour %s est %s';
$strings['ToolsAdded'] = 'Outils ajoutés';
$strings['ToolEdited'] = 'Outil édité';
$strings['ShareLauncherName'] = 'Share launcher\'s name';
$strings['ShareLauncherEmail'] = 'Share launcher\'s email';
$strings['ShareLauncherPicture'] = 'Share launcher\'s picture';
$strings['NoTool'] = 'Tool not exists';
$strings['ToolAddedOnCourseX'] = 'Tool addeed on course <strong>%s</strong>.';
$strings['SupportDeppLinkingHelp'] = 'Contact your Tool Provider to verify if Deep Linking support is mandatory';

@ -13,6 +13,7 @@ $strings['LaunchUrl'] = 'URL de arranque (launch URL)';
$strings['ConsumerKey'] = 'Clave consumidor (consumer key)';
$strings['SharedSecret'] = 'Secreto compartido (shared secret)';
$strings['CustomParams'] = 'Parámetros personalizados';
$strings['CustomParamsHelp'] = 'Parámetros personalizados requeridos por el Proveedor de la Herramienta. Formato: <code>name=value</code>.';
$strings['ToolName'] = 'Nombre de la herramienta';
$strings['ToolNotAdded'] = 'Herramienta no añadida';
$strings['AvailableTools'] = 'Herramientas disponibles';
@ -22,3 +23,18 @@ $strings['IsGlobal'] = 'Es global';
$strings['EditExternalTool'] = 'Editar herramienta externa';
$strings['ToolDeleted'] = 'Herramienta eliminada';
$strings['ToolAdded'] = 'Herramienta agregada';
$strings['PressToContinue'] = 'Presione para continuar con la herramienta externa';
$strings['ConfigureExternalTool'] = 'Configure external tools';
$strings['SupportDeepLinking'] = 'Soportar Deep-Linking';
$strings['ScoreNotSet'] = 'Puntuación no establecida';
$strings['ScoreForXUserIsYScore'] = 'Puntuación para %s es %s';
$strings['ToolsAdded'] = 'Herramientas agregadas';
$strings['ToolEdited'] = 'Herramienta editada';
$strings['ShareLauncherName'] = 'Enviar el nombre del usuario';
$strings['ShareLauncherEmail'] = 'Enviar el correo electrónico del usuario';
$strings['ShareLauncherPicture'] = 'Enviar la foto del usuario';
$strings['NoTool'] = 'La herramienta no existe';
$strings['ToolAddedOnCourseX'] = 'Herramienta agregada en el curso <strong>%s</strong>.';
$strings['SupportDeppLinkingHelp'] = 'Contacte a su Proveedor de Herramienta para verificar si el soporte a Deep Linking es obligatorio';
$strings['NoAccessToUrl'] = 'Sin acceso a la URL';
$strings['LaunchUrlNotFound'] = 'URL de lanzamiento no encontrada';

@ -18,7 +18,9 @@ if (!$tool) {
$imsLtiPlugin = ImsLtiPlugin::create();
$template = new Template($tool->getName());
$pageTitle = Security::remove_XSS($tool->getName());
$template = new Template($pageTitle);
$template->assign('tool', $tool);
$template->assign(
'launch_url',
@ -27,6 +29,6 @@ $template->assign(
$content = $template->fetch('ims_lti/view/start.tpl');
$template->assign('header', $tool->getName());
$template->assign('header', $pageTitle);
$template->assign('content', $content);
$template->display_one_col_template();

@ -1,33 +1,61 @@
<div class="row">
{% if tools|length %}
{% if global_tools|length or added_tools|length %}
<div class="col-sm-3">
<h2 class="page-header">{{ 'AvailableTools'|get_plugin_lang('ImsLtiPlugin') }}</h2>
<ul class="nav nav-pills nav-stacked">
{% for tool in tools %}
<li class="{{ type == tool.id ? 'active' : '' }}">
<a href="{{ _p.web_self }}?type={{ tool.id }}&{{ _p.web_cid_query }}">{{ tool.name }}</a>
</li>
{% endfor %}
</ul>
{% if added_tools|length %}
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">{{ 'ToolsAdded'|get_plugin_lang('ImsLtiPlugin') }}</h2>
</div>
<ul class="list-group">
{% for tool in added_tools %}
<li class="list-group-item {{ type == tool.id ? 'active' : '' }}">
<div class="pull-right">
{% if tool.isActiveDeepLinking %}
<a href="{{ _p.web_plugin }}ims_lti/start.php?id={{ tool.id }}&{{ _p.web_cid_query }}">
{{ 'settings.png'|img(22, 'Configure'|get_lang) }}
</a>
{% endif %}
<a href="{{ _p.web_plugin }}ims_lti/configure.php?action=edit&id={{ tool.id }}&{{ _p.web_cid_query }}">
{{ 'edit.png'|img(22, 'Edit'|get_lang) }}
</a>
</div>
{{ tool.name|e }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if global_tools|length %}
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">{{ 'AvailableTools'|get_plugin_lang('ImsLtiPlugin') }}</h2>
</div>
<ul class="list-group">
{% for tool in global_tools %}
<li class="list-group-item {{ type == tool.id ? 'active' : '' }}">
<div class="pull-right">
{% if tool.isActiveDeepLinking %}
<a href="{{ _p.web_plugin }}ims_lti/start.php?id={{ tool.id }}&{{ _p.web_cid_query }}">
{{ 'settings.png'|img(22, 'Configure'|get_lang) }}
</a>
{% else %}
<a href="{{ _p.web_self }}?type={{ tool.id }}&{{ _p.web_cid_query }}">
{{ 'add.png'|img(22, 'Add'|get_lang) }}
</a>
{% endif %}
</div>
{{ tool.name|e }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
{% endif %}
<div class="col-sm-9 {{ tools|length ? '' : 'col-sm-offset-3' }}">
<h2 class="page-header">{{ 'ToolSettings'|get_plugin_lang('ImsLtiPlugin') }}</h2>
<div class="col-sm-9 {{ not global_tools|length and not added_tools|length ? 'col-md-offset-3' : '' }}">
{{ form }}
</div>
</div>
<script>
$(document).on('ready', function () {
$('select[name="type"]').on('change', function () {
var advancedOptionsEl = $('#show_advanced_options');
var type = parseInt($(this).val());
if (type > 0) {
advancedOptionsEl.hide();
} else {
advancedOptionsEl.show();
}
});
});
</script>

@ -1,43 +1,46 @@
{{ 'ImsLtiDescription'|get_plugin_lang('ImsLtiPlugin') }}
<div class="btn-toolbar">
<a href="{{ _p.web_plugin }}ims_lti/create.php" class="btn btn-primary">
<span class="fa fa-plus fa-fw" aria-hidden="true"></span> {{ 'AddExternalTool'|get_plugin_lang('ImsLtiPlugin') }}
</a>
</div>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>{{ 'Name'|get_lang }}</th>
<th>{{ 'LaunchUrl'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-center">{{ 'IsGlobal'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-right">{{ 'Actions'|get_lang }}</th>
</tr>
</thead>
<tbody>
{% for tool in tools %}
{% autoescape 'html' %}
<div class="btn-toolbar">
<a href="{{ _p.web_plugin }}ims_lti/create.php" class="btn btn-primary">
<span class="fa fa-plus fa-fw" aria-hidden="true"></span> {{ 'AddExternalTool'|get_plugin_lang('ImsLtiPlugin') }}
</a>
</div>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<td>{{ tool.name }}</td>
<td>{{ tool.launchUrl }}</td>
<td class="text-center">
{% if tool.isGlobal %}
<span class="fa fa-check-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'Yes'|get_lang }}</span>
{% else %}
<span class="fa fa-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'No'|get_lang }}</span>
{% endif %}
</td>
<td class="text-right">
<a href="{{ _p.web_plugin }}ims_lti/edit.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-success">
<span class="fa fa-edit fa-fw" aria-hidden="true"></span> {{ 'Edit'|get_lang }}
</a>
<a href="{{ _p.web_plugin }}ims_lti/delete.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-danger">
<span class="fa fa-times fa-fw" aria-hidden="true"></span> {{ 'Delete'|get_lang }}
</a>
</td>
<th>{{ 'Name'|get_lang }}</th>
<th>{{ 'LaunchUrl'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-center">{{ 'IsGlobal'|get_plugin_lang('ImsLtiPlugin') }}</th>
<th class="text-right">{{ 'Actions'|get_lang }}</th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</thead>
<tbody>
{% for tool in tools %}
<tr>
<td>{{ tool.name }}</td>
<td>{{ tool.launchUrl }}</td>
<td class="text-center">
{% if tool.isGlobal %}
<span class="fa fa-check-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'Yes'|get_lang }}</span>
{% else %}
<span class="fa fa-square-o" aria-hidden="true"></span>
<span class="sr-only">{{ 'No'|get_lang }}</span>
{% endif %}
</td>
<td class="text-right">
<a href="{{ _p.web_plugin }}ims_lti/edit.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-success">
<span class="fa fa-edit fa-fw" aria-hidden="true"></span> {{ 'Edit'|get_lang }}
</a>
<a href="{{ _p.web_plugin }}ims_lti/delete.php?{{ {'id': tool.id}|url_encode() }}" class="btn btn-danger">
<span class="fa fa-times fa-fw" aria-hidden="true"></span> {{ 'Delete'|get_lang }}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endautoescape %}

@ -1,6 +1,6 @@
{% if tool.description %}
<p class="lead">{{ tool.description }}</p>
<p class="lead">{{ tool.description|e|nl2br }}</p>
{% endif %}
<div class="embed-responsive embed-responsive-16by9">
<div class="embed-responsive embed-responsive-4by3">
<iframe src="{{ launch_url }}" class="plugin-ims-lti-iframe"></iframe>
</div>

@ -709,7 +709,7 @@ class LearningCalendarPlugin extends Plugin
ON (r.evaluation_id = e.id)
WHERE
e.type = 'evaluation' AND
r.score > 0 AND
r.score >= 2 AND
r.user_id = $userId
$courseSessionConditionToString
";

@ -8,9 +8,9 @@ $strings['LearningCalendar'] = 'Learning calendar';
$strings['NumberDaysAccumulatedInCalendar'] = 'Number of days accumulated in the calendar: ';
$strings['NumberDaysAccumulatedInLp'] = 'Number of days accumulated in the LP: ';
$strings['NumberDaysInRetard'] = 'Number of days in retard: ';
$strings['DifferenceOfDaysAndCalendar'] = 'Difference of days and calendar';
$strings['DifferenceOfDaysAndCalendar'] = 'Difference of days with the calendar plan';
$strings['EventTypeTaken'] = 'Taken';
$strings['EventTypeTaken'] = 'Busy';
$strings['EventTypeExam'] = 'Exam';
$strings['EventTypeFree'] = 'Free';
$strings['CourseHoursDuration'] = 'Course hours duration';

@ -4,11 +4,19 @@
$strings['plugin_title'] = 'Learning calendar';
$strings['plugin_comment'] = '';
$strings['enabled'] = 'Enabled';
$strings['LearningCalendar'] = 'Learning calendar';
$strings['LearningCalendar'] = 'Calendrier d\'apprentissage';
$strings['NumberDaysAccumulatedInCalendar'] = 'Nombre de jours cumulés dans le calendrier: ';
$strings['NumberDaysAccumulatedInLp'] = 'Nombre de jours cumulés dans les parcours réalisés: ';
$strings['NumberDaysInRetard'] = "Nombre de jour de retard ou d'avance à la date d'aujourd'hui: ";
$strings['DifferenceOfDaysAndCalendar'] = 'Différence de nombre de jours avec le plan issu du learning_calendar';
$strings['EventTypeTaken'] = 'Occupé';
$strings['EventTypeExam'] = 'Examen';
$strings['EventTypeFree'] = 'Libre';
$strings['CourseHoursDuration'] = 'Durée du cours (h)';
$strings['LearningCalendarOneDayMarker'] = 'Marqueur 1 jour calendrier';
$strings['ControlPointAdded'] = 'Point de contrôle ajouté';
$strings['NumberOfDays'] = 'Nombre de jours';
$strings['Date'] = 'Date';
$strings['AddMultipleUsersToCalendar'] = 'Ajouter plusieurs utilisateurs au calendrier';
$strings['UpdateCalendar'] = 'Mettre à jour calendrier';

@ -4,4 +4,19 @@
$strings['plugin_title'] = 'Learning calendar';
$strings['plugin_comment'] = '';
$strings['enabled'] = 'Activado';
$strings['LearningCalendar'] = 'Learning calendar';
$strings['LearningCalendar'] = 'Calendario de aprendizaje';
$strings['NumberDaysAccumulatedInCalendar'] = 'Número de días acumulados en el calendario: ';
$strings['NumberDaysAccumulatedInLp'] = 'Número de días acumulados en la lección: ';
$strings['NumberDaysInRetard'] = 'Número de días de retraso: ';
$strings['DifferenceOfDaysAndCalendar'] = 'Diferencia entre días y plan del calendario';
$strings['EventTypeTaken'] = 'Ocupado';
$strings['EventTypeExam'] = 'Examen';
$strings['EventTypeFree'] = 'Libre';
$strings['CourseHoursDuration'] = 'Duración del curso (h)';
$strings['LearningCalendarOneDayMarker'] = 'Marcador 1 día del calendario de aprendizaje';
$strings['ControlPointAdded'] = 'Puntos de control añadidos';
$strings['NumberOfDays'] = 'Número de días';
$strings['Date'] = 'Fecha';
$strings['AddMultipleUsersToCalendar'] = 'Añadir usuarios múltiples a un calendario';
$strings['UpdateCalendar'] = 'Actualizar calendario';

@ -6,11 +6,13 @@
url: "{{ ajax_url }}&a=get_events",
success: function(response) {
for (var i = 0; i < response.length; i++) {
var startDate = moment(response[i].start_date + " 13:00:00").toDate();
var endDate = moment(response[i].end_date + " 13:00:00").toDate();
myData.push({
id: response[i].id,
title: response[i].title,
startDate: new Date(response[i].start_date),
endDate: new Date(response[i].end_date),
startDate: startDate,
endDate: endDate,
color: response[i].color
});
}

@ -58,18 +58,23 @@ class NotebookTeacherPlugin extends Plugin
return false;
}
$srcfile1 = __DIR__.'/../resources/img/64/notebookteacher.png';
$srcfile2 = __DIR__.'/../resources/img/64/notebookteacher_na.png';
$srcfile3 = __DIR__.'/../resources/img/32/notebookteacher.png';
$srcfile4 = __DIR__.'/../resources/img/22/notebookteacher.png';
$dstfile1 = __DIR__.'/../../../main/img/icons/64/notebookteacher.png';
$dstfile2 = __DIR__.'/../../../main/img/icons/64/notebookteacher_na.png';
$dstfile3 = __DIR__.'/../../../main/img/icons/32/notebookteacher.png';
$dstfile4 = __DIR__.'/../../../main/img/notebookteacher.png';
copy($srcfile1, $dstfile1);
copy($srcfile2, $dstfile2);
copy($srcfile3, $dstfile3);
copy($srcfile4, $dstfile4);
$list = [
'/64/notebookteacher.png',
'/64/notebookteacher_na.png',
'/32/notebookteacher.png',
'/32/notebookteacher_na.png',
'/32/test2pdf_na.png',
'/22/notebookteacher.png',
];
foreach ($list as $file) {
$source = __DIR__.'/../resources/img/'.$file;
$destination = __DIR__.'/../../../main/img/icons/'.$file;
$res = @copy($source, $destination);
if (!$res) {
break;
}
}
require_once api_get_path(SYS_PLUGIN_PATH).'notebookteacher/database.php';
}

@ -4,7 +4,7 @@ Redirection plugin
Chamilo plugin for the redirection of specific users after they login and
redirect from the index.php to the selected URL.
Requires the addition of the following in configuration.php:
1. Requires the addition of the following in configuration.php:
```
$_configuration['plugin_redirection_enabled'] = true;
@ -13,4 +13,6 @@ $_configuration['plugin_redirection_enabled'] = true;
This setting is defined in configuration.php rather than in settings_current to reduce the
load, as it is used on every login.
2. Add the plugin in the "menu administration" region.
@TODO Check the load difference for *just* checking it in settings_current rather than building the plugin object

@ -87,6 +87,20 @@ class RedirectionPlugin extends Plugin
return Database::fetch_array($result, 'ASSOC');
}
/**
* Deletes redirection from user.
*
* @param int $userId
*/
public static function deleteUserRedirection($userId)
{
$table = Database::get_main_table('plugin_redirection');
Database::delete(
$table,
['user_id = ?' => [$userId]]
);
}
/**
* Deletes an existing redirection.
*

@ -16,17 +16,20 @@ if (empty($url)) {
return;
}
$channel = Reader::import($url);
if (!empty($channel)) {
/** @var FeedInterface $item */
foreach ($channel as $item) {
$title = $item->getTitle();
$link = $item->getLink();
if (!empty($link)) {
$title = Display::url($title, $link, ['target' => '_blank']);
try {
$channel = Reader::import($url);
if (!empty($channel)) {
/** @var FeedInterface $item */
foreach ($channel as $item) {
$title = $item->getTitle();
$link = $item->getLink();
if (!empty($link)) {
$title = Display::url($title, $link, ['target' => '_blank']);
}
echo Display::panel($item->getDescription(), $title);
}
echo Display::panel($item->getDescription(), $title);
}
} catch (Exception $e) {
echo Display::return_message($plugin->get_lang('no_valid_rss'), 'warning');
error_log($e->getMessage());
}

@ -13,3 +13,4 @@ $strings['block_title'] = "Block title";
$strings['title'] = "Title";
$strings['no_rss'] = "There is no RSS configured. Please add a RSS";
$strings['no_valid_rss'] = "Please check if the URL contains a valid RSS URL";

@ -109,7 +109,7 @@ class RegisterCourseWidget
$user_id = $_user['user_id'];
}
return (bool) CourseManager::add_user_to_course($user_id, $course_code);
return (bool) CourseManager::subscribeUser($user_id, $course_code);
}
/**

@ -154,11 +154,11 @@ if (api_is_platform_admin()) {
$tpl->assign('new_action', '1');
$tpl->assign('course_id', intval($_GET['cid']));
} else {
$courseId = getCourse(intval($_GET['action_id']));
$courseId = getCourse($_GET['action_id']);
$interbreadcrumb[] = ["url" => "/plugin/sepe/src/sepe-administration-menu.php", "name" => $plugin->get_lang('MenuSepe')];
$interbreadcrumb[] = ["url" => "formative-actions-list.php", "name" => $plugin->get_lang('FormativesActionsList')];
$interbreadcrumb[] = ["url" => "formative-action.php?cid=".$courseId, "name" => $plugin->get_lang('FormativeAction')];
$info = getActionInfo(intval($_GET['action_id']));
$info = getActionInfo($_GET['action_id']);
$templateName = $plugin->get_lang('formativeActionEdit');
$tpl = new Template($templateName);
$tpl->assign('info', $info);

@ -11,7 +11,7 @@ $plugin = SepePlugin::create();
$_cid = 0;
if (api_is_platform_admin()) {
$actionId = getActionId(intval($_GET['cid']));
$actionId = getActionId($_GET['cid']);
$info = getActionInfo($actionId);
if ($info === false) {
header("Location: formative-actions-list.php");

@ -10,7 +10,10 @@ $plugin = SepePlugin::create();
if (api_is_platform_admin()) {
$templateName = $plugin->get_lang('FormativesActionsList');
$interbreadcrumb[] = ["url" => "/plugin/sepe/src/sepe-administration-menu.php", "name" => $plugin->get_lang('MenuSepe')];
$interbreadcrumb[] = [
"url" => "/plugin/sepe/src/sepe-administration-menu.php",
"name" => $plugin->get_lang('MenuSepe'),
];
$tpl = new Template($templateName);
if (isset($_SESSION['sepe_message_info'])) {

@ -20,34 +20,34 @@ if (!empty($_POST)) {
$id = intval($_POST['id']);
if (checkIdentificationData()) {
$sql = "UPDATE $tableSepeCenter SET
center_origin = '".$centerOrigin."',
center_code = '".$centerCode."',
center_name = '".$centerName."',
url = '".$url."',
tracking_url = '".$trackingUrl."',
phone = '".$phone."',
mail = '".$mail."'
$sql = "UPDATE $tableSepeCenter SET
center_origin = '".$centerOrigin."',
center_code = '".$centerCode."',
center_name = '".$centerName."',
url = '".$url."',
tracking_url = '".$trackingUrl."',
phone = '".$phone."',
mail = '".$mail."'
WHERE id = $id";
} else {
$sql = "INSERT INTO $tableSepeCenter (
id,
center_origin,
center_code,
center_name,
url,
tracking_url,
phone,
mail
) VALUES (
1,
'".$centerOrigin."',
'".$centerCode."',
'".$centerName."',
'".$url."',
'".$trackingUrl."',
'".$phone."',
'".$mail."'
$sql = "INSERT INTO $tableSepeCenter (
id,
center_origin,
center_code,
center_name,
url,
tracking_url,
phone,
mail
) VALUES (
1,
'".$centerOrigin."',
'".$centerCode."',
'".$centerName."',
'".$url."',
'".$trackingUrl."',
'".$phone."',
'".$mail."'
);";
}
$res = Database::query($sql);
@ -67,7 +67,10 @@ if (!empty($_POST)) {
}
if (api_is_platform_admin()) {
$interbreadcrumb[] = ["url" => "/plugin/sepe/src/sepe-administration-menu.php", "name" => $plugin->get_lang('MenuSepe')];
$interbreadcrumb[] = [
"url" => "/plugin/sepe/src/sepe-administration-menu.php",
"name" => $plugin->get_lang('MenuSepe'),
];
$interbreadcrumb[] = ["url" => "identification-data.php", "name" => $plugin->get_lang('DataCenter')];
$templateName = $plugin->get_lang('DataCenterEdit');
$tpl = new Template($templateName);

@ -201,10 +201,10 @@ if (api_is_platform_admin()) {
$templateName = $plugin->get_lang('EditParticipantAction');
$tpl = new Template($templateName);
$tpl->assign('action_id', $actionId);
$info = getInfoParticipantAction(intval($_GET['participant_id']));
$info = getInfoParticipantAction($_GET['participant_id']);
$tpl->assign('info', $info);
$tpl->assign('new_participant', '0');
$tpl->assign('participant_id', intval($_GET['participant_id']));
$tpl->assign('participant_id', (int) $_GET['participant_id']);
if ($info['platform_user_id'] != 0) {
$infoUserPlatform = api_get_user_info($info['platform_user_id']);
@ -225,10 +225,8 @@ if (api_is_platform_admin()) {
}
}
$tpl->assign('listStudent', $listStudentInfo);
$listTutorCompany = [];
$listTutorCompany = listTutorType("company = '1'");
$tpl->assign('list_tutor_company', $listTutorCompany);
$listTutorTraining = [];
$listTutorTraining = listTutorType("training = '1'");
$tpl->assign('list_tutor_training', $listTutorTraining);
if (isset($_SESSION['sepe_message_info'])) {

@ -178,7 +178,7 @@ if (api_is_platform_admin()) {
$tpl->assign('action_id', $actionId);
$tpl->assign('specialty_id', intval($_GET['specialty_id']));
$tpl->assign('participant_id', intval($_GET['participant_id']));
$info = getInfoSpecialtyParticipant(intval($_GET['specialty_id']));
$info = getInfoSpecialtyParticipant($_GET['specialty_id']);
$tpl->assign('info', $info);
$tpl->assign('new_specialty', '0');
if ($info['registration_date'] != '0000-00-00' && $info['registration_date'] != null) {
@ -221,7 +221,7 @@ if (api_is_platform_admin()) {
} else {
$endYear = date("Y");
}
$listSpecialtyTutorials = getListSpecialtyTutorial(intval($_GET['specialty_id']));
$listSpecialtyTutorials = getListSpecialtyTutorial($_GET['specialty_id']);
$tpl->assign('listSpecialtyTutorials', $listSpecialtyTutorials);
}

@ -59,6 +59,7 @@ function checkIdentificationData()
function getActionId($courseId)
{
global $tableSepeCourseActions;
$courseId = (int) $courseId;
$sql = "SELECT action_id FROM $tableSepeCourseActions WHERE course_id = $courseId";
$rs = Database::query($sql);
$aux = Database::fetch_assoc($rs);
@ -69,6 +70,7 @@ function getActionId($courseId)
function getCourse($actionId)
{
global $tableSepeCourseActions;
$actionId = (int) $actionId;
$sql = "SELECT course_id FROM $tableSepeCourseActions WHERE action_id = $actionId";
$rs = Database::query($sql);
$aux = Database::fetch_assoc($rs);
@ -78,6 +80,7 @@ function getCourse($actionId)
function getCourseCode($actionId)
{
global $tableCourse;
$actionId = (int) $actionId;
$courseId = getCourse($actionId);
$sql = "SELECT code FROM $tableCourse WHERE id = $courseId";
$rs = Database::query($sql);
@ -89,6 +92,8 @@ function getCourseCode($actionId)
function getActionInfo($id)
{
global $tableSepeActions;
$id = (int) $id;
$sql = "SELECT * FROM $tableSepeActions WHERE id = $id";
$res = Database::query($sql);
$row = false;
@ -115,6 +120,7 @@ function getActionInfo($id)
function getSpecialtActionInfo($specialtyId)
{
global $tableSepeSpecialty;
$specialtyId = (int) $specialtyId;
$sql = "SELECT * FROM $tableSepeSpecialty WHERE id = $specialtyId";
$res = Database::query($sql);
$row = false;
@ -135,8 +141,10 @@ function getInfoSpecialtyClassroom($classroomId)
{
global $tableSepeSpecialtyClassroom;
global $tableCenters;
$sql = "SELECT a.*, center_origin, center_code
FROM $tableSepeSpecialtyClassroom a LEFT JOIN $tableCenters b ON a.center_id = b.id
$classroomId = (int) $classroomId;
$sql = "SELECT a.*, center_origin, center_code
FROM $tableSepeSpecialtyClassroom a
LEFT JOIN $tableCenters b ON a.center_id = b.id
WHERE a.id = $classroomId";
$res = Database::query($sql);
$row = false;
@ -152,6 +160,7 @@ function getInfoSpecialtyClassroom($classroomId)
function getInfoSpecialtyTutorial($tutorialId)
{
global $tableSepeParticipantsSpecialtyTutorials;
$tutorialId = (int) $tutorialId;
$sql = "SELECT * FROM $tableSepeParticipantsSpecialtyTutorials WHERE id = $tutorialId";
$res = Database::query($sql);
$aux = [];
@ -167,6 +176,7 @@ function getInfoSpecialtyTutorial($tutorialId)
function list_tutor($specialtyId)
{
global $tableSepeSpecialtyTutors;
$specialtyId = (int) $specialtyId;
$sql = "SELECT * FROM $tableSepeSpecialtyTutors WHERE specialty_id = $specialtyId";
$res = Database::query($sql);
if (Database::num_rows($res) > 0) {
@ -194,6 +204,7 @@ function getCentersList()
function listTutorType($condition)
{
global $tableTutorCompany;
$condition = Database::escape_string($condition);
$sql = "SELECT * FROM $tableTutorCompany WHERE ".$condition." ORDER BY alias ASC, document_number ASC;";
$res = Database::query($sql);
$aux = [];
@ -216,14 +227,17 @@ function getTutorsSpecialty($specialtyId)
global $tableSepeSpecialtyTutors;
global $tableSepeTutors;
global $tableUser;
$specialtyId = (int) $specialtyId;
$sql = "SELECT tutor_id FROM $tableSepeSpecialtyTutors WHERE specialty_id = $specialtyId";
$rs = Database::query($sql);
$tutorsList = [];
while ($tmp = Database::fetch_assoc($rs)) {
$tutorsList[] = $tmp['tutor_id'];
}
$sql = "SELECT a.*, b.firstname AS firstname, b.lastname AS lastname
FROM $tableSepeTutors AS a LEFT JOIN $tableUser AS b ON a.platform_user_id=b.user_id;";
$sql = "SELECT a.*, b.firstname AS firstname, b.lastname AS lastname
FROM $tableSepeTutors AS a
LEFT JOIN $tableUser AS b ON a.platform_user_id=b.user_id;";
$res = Database::query($sql);
$aux = [];
while ($row = Database::fetch_assoc($res)) {
@ -246,9 +260,10 @@ function getInfoSpecialtyTutor($tutorId)
{
global $tableSepeSpecialtyTutors;
global $tableSepeTutors;
$sql = "SELECT a.*,platform_user_id,document_type, document_number,document_letter
FROM $tableSepeSpecialtyTutors a
INNER JOIN $tableSepeTutors b ON a.tutor_id=b.id
$tutorId = (int) $tutorId;
$sql = "SELECT a.*,platform_user_id,document_type, document_number,document_letter
FROM $tableSepeSpecialtyTutors a
INNER JOIN $tableSepeTutors b ON a.tutor_id=b.id
WHERE a.id = $tutorId;";
$res = Database::query($sql);
$aux = [];
@ -268,6 +283,10 @@ function freeTeacherList($teacherList, $specialtyId, $platform_user_id)
{
global $tableSepeSpecialtyTutors;
global $tableSepeTutors;
$specialtyId = (int) $specialtyId;
$platform_user_id = (int) $platform_user_id;
$sql = "SELECT tutor_id FROM $tableSepeSpecialtyTutors WHERE specialty_id = $specialtyId";
$rs = Database::query($sql);
if (Database::num_rows($rs) > 0) {
@ -294,9 +313,9 @@ function freeTeacherList($teacherList, $specialtyId, $platform_user_id)
function getInfoParticipantAction($participantId)
{
global $tableSepeParticipants;
$participantId = (int) $participantId;
$sql = "SELECT * FROM $tableSepeParticipants WHERE id = $participantId";
$res = Database::query($sql);
$aux = [];
if (Database::num_rows($res) > 0) {
$row = Database::fetch_assoc($res);
$result = [];
@ -321,6 +340,7 @@ function getInfoParticipantAction($participantId)
function getParticipantId($id)
{
global $tableSepeParticipantsSpecialty;
$id = (int) $id;
$sql = "SELECT participant_id FROM $tableSepeParticipantsSpecialty WHERE id = $id";
$rs = Database::query($sql);
$aux = Database::fetch_assoc($rs);
@ -331,9 +351,9 @@ function getParticipantId($id)
function getInfoSpecialtyParticipant($specialtyId)
{
global $tableSepeParticipantsSpecialty;
$specialtyId = (int) $specialtyId;
$sql = "SELECT * FROM $tableSepeParticipantsSpecialty WHERE id = $specialtyId";
$res = Database::query($sql);
$aux = [];
if (Database::num_rows($res) > 0) {
$row = Database::fetch_assoc($res);
$row['specialty_origin'] = Security::remove_XSS(stripslashes($row['specialty_origin']));
@ -354,8 +374,9 @@ function getInfoSpecialtyParticipant($specialtyId)
function specialtyList($actionId)
{
global $tableSepeSpecialty;
$sql = "SELECT id, specialty_origin, professional_area, specialty_code
FROM $tableSepeSpecialty
$actionId = (int) $actionId;
$sql = "SELECT id, specialty_origin, professional_area, specialty_code
FROM $tableSepeSpecialty
WHERE action_id = $actionId";
$res = Database::query($sql);
$aux = [];
@ -370,8 +391,10 @@ function participantList($actionId)
{
global $tableSepeParticipants;
global $tableUser;
$sql = "SELECT $tableSepeParticipants.id AS id, document_type, document_number, document_letter, firstname, lastname
FROM $tableSepeParticipants LEFT JOIN $tableUser ON $tableSepeParticipants.platform_user_id=$tableUser.user_id
$actionId = (int) $actionId;
$sql = "SELECT $tableSepeParticipants.id AS id, document_type, document_number, document_letter, firstname, lastname
FROM $tableSepeParticipants
LEFT JOIN $tableUser ON $tableSepeParticipants.platform_user_id=$tableUser.user_id
WHERE action_id = $actionId";
$res = Database::query($sql);
$aux = [];
@ -385,6 +408,8 @@ function participantList($actionId)
function listParticipantSpecialty($participantId)
{
global $tableSepeParticipantsSpecialty;
$participantId = (int) $participantId;
$sql = "SELECT * FROM $tableSepeParticipantsSpecialty WHERE participant_id = $participantId";
$res = Database::query($sql);
$aux = [];
@ -407,8 +432,10 @@ function classroomList($specialtyId)
{
global $tableSepeSpecialtyClassroom;
global $tableCenters;
$sql = "SELECT a.*, center_origin, center_code
FROM $tableSepeSpecialtyClassroom a LEFT JOIN $tableCenters b ON a.center_id=b.id
$specialtyId = (int) $specialtyId;
$sql = "SELECT a.*, center_origin, center_code
FROM $tableSepeSpecialtyClassroom a
LEFT JOIN $tableCenters b ON a.center_id=b.id
WHERE specialty_id = $specialtyId";
$res = Database::query($sql);
$aux = [];
@ -424,10 +451,12 @@ function tutorsList($specialtyId)
global $tableSepeSpecialtyTutors;
global $tableSepeTutors;
global $tableUser;
$specialtyId = (int) $specialtyId;
$aux = [];
$sql = "SELECT a.*,document_type,document_number,document_letter, firstname, lastname FROM $tableSepeSpecialtyTutors a
INNER JOIN $tableSepeTutors b ON a.tutor_id=b.id
LEFT JOIN $tableUser c ON b.platform_user_id=c.user_id
$sql = "SELECT a.*,document_type,document_number,document_letter, firstname, lastname
FROM $tableSepeSpecialtyTutors a
INNER JOIN $tableSepeTutors b ON a.tutor_id=b.id
LEFT JOIN $tableUser c ON b.platform_user_id=c.user_id
WHERE a.specialty_id = $specialtyId";
$res = Database::query($sql);
while ($row = Database::fetch_assoc($res)) {
@ -440,7 +469,9 @@ function tutorsList($specialtyId)
function getListSpecialtyTutorial($specialtyId)
{
global $tableSepeParticipantsSpecialtyTutorials;
$sql = "SELECT * FROM $tableSepeParticipantsSpecialtyTutorials WHERE participant_specialty_id = $specialtyId";
$specialtyId = (int) $specialtyId;
$sql = "SELECT * FROM $tableSepeParticipantsSpecialtyTutorials
WHERE participant_specialty_id = $specialtyId";
$res = Database::query($sql);
$aux = [];
while ($row = Database::fetch_assoc($res)) {
@ -457,9 +488,10 @@ function listCourseAction()
{
global $tableSepeActions;
global $tableSepeCourseActions;
$sql = "SELECT $tableSepeCourseActions.*, course.title AS title, $tableSepeActions.action_origin AS action_origin, $tableSepeActions.action_code AS action_code
FROM $tableSepeCourseActions, course, $tableSepeActions
WHERE $tableSepeCourseActions.course_id=course.id
$sql = "SELECT $tableSepeCourseActions.*, course.title AS title, $tableSepeActions.action_origin AS action_origin, $tableSepeActions.action_code AS action_code
FROM $tableSepeCourseActions, course, $tableSepeActions
WHERE $tableSepeCourseActions.course_id=course.id
AND $tableSepeActions.id=$tableSepeCourseActions.action_id";
$res = Database::query($sql);
$aux = [];
@ -474,9 +506,10 @@ function listCourseFree()
{
global $tableCourse;
global $tableSepeCourseActions;
$sql = "SELECT id, title FROM $tableCourse
WHERE NOT EXISTS (
SELECT * FROM $tableSepeCourseActions WHERE $tableCourse.id = $tableSepeCourseActions.course_id)
$sql = "SELECT id, title FROM $tableCourse
WHERE NOT EXISTS (
SELECT * FROM $tableSepeCourseActions
WHERE $tableCourse.id = $tableSepeCourseActions.course_id)
;";
$res = Database::query($sql);
while ($row = Database::fetch_assoc($res)) {
@ -490,9 +523,9 @@ function listActionFree()
{
global $tableSepeActions;
global $tableSepeCourseActions;
$sql = "SELECT id, action_origin, action_code FROM $tableSepeActions
WHERE NOT EXISTS (
SELECT * FROM $tableSepeCourseActions WHERE $tableSepeActions.id = $tableSepeCourseActions.action_id)
$sql = "SELECT id, action_origin, action_code FROM $tableSepeActions
WHERE NOT EXISTS (
SELECT * FROM $tableSepeCourseActions WHERE $tableSepeActions.id = $tableSepeCourseActions.action_id)
;";
$res = Database::query($sql);
$aux = [];
@ -508,8 +541,11 @@ function listActionFree()
function getSpecialtyTutorId($specialtyId, $tutorId)
{
global $tableSepeSpecialtyTutors;
$sql = "SELECT id
FROM $tableSepeSpecialtyTutors
$specialtyId = (int) $specialtyId;
$tutorId = (int) $tutorId;
$sql = "SELECT id
FROM $tableSepeSpecialtyTutors
WHERE specialty_id = $specialtyId AND tutor_id = $tutorId";
$res = Database::query($sql);
$row = Database::fetch_assoc($res);
@ -520,6 +556,8 @@ function getSpecialtyTutorId($specialtyId, $tutorId)
function checkInsertNewLog($platformUserId, $actionId)
{
global $tableSepeLogParticipant;
$platformUserId = (int) $platformUserId;
$actionId = (int) $actionId;
$sql = "SELECT * FROM $tableSepeLogParticipant WHERE platform_user_id = $platformUserId AND action_id = $actionId";
$res = Database::query($sql);
if (Database::num_rows($res) > 0) {
@ -532,6 +570,8 @@ function checkInsertNewLog($platformUserId, $actionId)
function getUserPlatformFromParticipant($participantId)
{
global $tableSepeParticipants;
$participantId = (int) $participantId;
$sql = "SELECT * FROM $tableSepeParticipants WHERE id = $participantId";
$res = Database::query($sql);
$row = Database::fetch_assoc($res);

@ -80,7 +80,7 @@ class SepePlugin extends Plugin
$sm = $cn->getSchemaManager();
$tables = $sm->tablesExist($tablesToBeCompared);
if ($tables) {
if (empty($tables)) {
return false;
}

@ -85,7 +85,7 @@ if (!empty($_POST)) {
}
if (api_is_platform_admin()) {
$courseId = getCourse(intval($_GET['action_id']));
$courseId = getCourse($_GET['action_id']);
$interbreadcrumb[] = ["url" => "/plugin/sepe/src/sepe-administration-menu.php", "name" => $plugin->get_lang('MenuSepe')];
$interbreadcrumb[] = ["url" => "formative-actions-list.php", "name" => $plugin->get_lang('FormativesActionsList')];
$interbreadcrumb[] = ["url" => "formative-action.php?cid=".$courseId, "name" => $plugin->get_lang('FormativeAction')];
@ -104,7 +104,7 @@ if (api_is_platform_admin()) {
$tpl->assign('action_id', intval($_GET['action_id']));
$tpl->assign('specialty_id', intval($_GET['specialty_id']));
$tpl->assign('classroom_id', intval($_GET['classroom_id']));
$info = getInfoSpecialtyClassroom(intval($_GET['classroom_id']));
$info = getInfoSpecialtyClassroom($_GET['classroom_id']);
$tpl->assign('info', $info);
$tpl->assign('new_classroom', '0');
}

@ -189,16 +189,16 @@ if (api_is_platform_admin()) {
$tpl->assign('action_id', intval($_GET['action_id']));
$tpl->assign('specialty_id', intval($_GET['specialty_id']));
$tpl->assign('tutor_id', intval($_GET['tutor_id']));
$info = getInfoSpecialtyTutor(intval($_GET['tutor_id']));
$info = getInfoSpecialtyTutor($_GET['tutor_id']);
$tpl->assign('info', $info);
$tpl->assign('new_tutor', '0');
$platformUserId = $info['platform_user_id'];
}
$tutorsList = getTutorsSpecialty(intval($_GET['specialty_id']));
$tutorsList = getTutorsSpecialty($_GET['specialty_id']);
$tpl->assign('ExistingTutorsList', $tutorsList);
$listTeachers = CourseManager::getTeachersFromCourse($courseId);
$listTeachers = freeTeacherList($listTeachers, intval($_GET['specialty_id']), $platformUserId);
$listTeachers = freeTeacherList($listTeachers, $_GET['specialty_id'], $platformUserId);
$tpl->assign('listTeachers', $listTeachers);
if (isset($_SESSION['sepe_message_info'])) {
$tpl->assign('message_info', $_SESSION['sepe_message_info']);

@ -133,7 +133,7 @@ class StudentFollowUpPlugin extends Plugin
}
// Check if course session coach
$sessions = SessionManager::get_sessions_by_user($studentId);
$sessions = SessionManager::get_sessions_by_user($studentId, false, true);
if (!empty($sessions)) {
foreach ($sessions as $session) {
$sessionId = $session['session_id'];
@ -146,7 +146,6 @@ class StudentFollowUpPlugin extends Plugin
break;
}
foreach ($session['courses'] as $course) {
//$isCourseCoach = api_is_coach($sessionId, $course['real_id']);
$coachList = SessionManager::getCoachesByCourseSession(
$sessionId,
$course['real_id']
@ -174,18 +173,27 @@ class StudentFollowUpPlugin extends Plugin
/**
* @param string $status
* @param int $currentUserId
* @param int $sessionId
* @param int $start
* @param int $limit
*
* @return array
*/
public static function getUsers($status, $currentUserId, $start, $limit)
public static function getUsers($status, $currentUserId, $sessionId, $start, $limit)
{
$sessions = [];
$courses = [];
$sessionsFull = [];
switch ($status) {
case COURSEMANAGER:
$sessions = SessionManager::get_sessions_by_user($currentUserId);
$sessions = array_column($sessions, 'session_id');
/*$sessions = SessionManager::get_sessions_by_user($currentUserId);
$sessions = array_column($sessions, 'session_id');*/
$sessionsFull = SessionManager::getSessionsCoachedByUser($currentUserId);
$sessions = array_column($sessionsFull, 'id');
if (!empty($sessionId)) {
$sessions = [$sessionId];
}
// Get session courses where I'm coach
$courseList = SessionManager::getCoursesListByCourseCoach($currentUserId);
$courses = [];
@ -195,8 +203,12 @@ class StudentFollowUpPlugin extends Plugin
}
break;
case DRH:
$sessions = SessionManager::get_sessions_followed_by_drh($currentUserId);
$sessions = array_column($sessions, 'id');
$sessionsFull = SessionManager::get_sessions_followed_by_drh($currentUserId);
$sessions = array_column($sessionsFull, 'id');
if (!empty($sessionId)) {
$sessions = [$sessionId];
}
$courses = [];
foreach ($sessions as $sessionId) {
$sessionDrhInfo = SessionManager::getSessionFollowedByDrh(
@ -230,7 +242,10 @@ class StudentFollowUpPlugin extends Plugin
$userList = array_unique($userList);
}*/
return $userList;
return [
'users' => $userList,
'sessions' => $sessionsFull,
];
}
/**
@ -240,4 +255,15 @@ class StudentFollowUpPlugin extends Plugin
{
return 20;
}
/**
* @param int $userId
*/
public function doWhenDeletingUser($userId)
{
$userId = (int) $userId;
Database::query("DELETE FROM sfu_post WHERE user_id = $userId");
Database::query("DELETE FROM sfu_post WHERE insert_user_id = $userId");
}
}

@ -5,3 +5,6 @@ $strings['plugin_comment'] = "Care system (Zorgdossier) [CS]
Career follow system (Structuurschema) [CFS]
Competence based evaluation system (Competentie evaluatie systeem) [CBES]";
$strings['tool_enable'] = 'Enable plugin';
$strings['CareDetailView'] = 'Mijn begeleidingen';
$strings['Private'] = 'Niet gedeeld met lesgevers';
$strings['Public'] = 'Gedeeld met lesgevers';

@ -11,37 +11,60 @@ api_block_anonymous_users();
$plugin = StudentFollowUpPlugin::create();
$currentUserId = api_get_user_id();
$currentPage = isset($_GET['page']) ? (int) $_GET['page'] : 1;
$keyword = isset($_GET['keyword']) ? $_GET['keyword'] : '';
$currentPage = isset($_REQUEST['page']) ? (int) $_REQUEST['page'] : 1;
$keyword = isset($_REQUEST['keyword']) ? Security::remove_XSS($_REQUEST['keyword']) : '';
$sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : 0;
$selectedTag = isset($_REQUEST['tag']) ? Security::remove_XSS($_REQUEST['tag']) : '';
$totalItems = 0;
$items = [];
$tags = [];
$showPrivate = false;
$pageSize = StudentFollowUpPlugin::getPageSize();
$firstResults = $pageSize * ($currentPage - 1);
$pagesCount = 0;
$isAdmin = api_is_platform_admin();
$userList = [];
if (!api_is_platform_admin()) {
if (!$isAdmin) {
$status = COURSEMANAGER;
if (api_is_drh()) {
$status = DRH;
}
$userList = StudentFollowUpPlugin::getUsers(
$data = StudentFollowUpPlugin::getUsers(
$status,
$currentUserId,
$sessionId,
$firstResults,
$pageSize
);
$userList = $data['users'];
$fullSessionList = $data['sessions'];
} else {
$fullSessionList = SessionManager::getSessionsCoachedByUser($currentUserId);
}
if (!empty($sessionId)) {
$userList = SessionManager::get_users_by_session($sessionId);
$userList = array_column($userList, 'user_id');
}
$tagList = [];
if (!empty($userList) || api_is_platform_admin()) {
if (!empty($userList) || $isAdmin) {
$em = Database::getManager();
$qb = $em->createQueryBuilder();
$criteria = Criteria::create();
if (!api_is_platform_admin()) {
if (!$isAdmin) {
$criteria->where(Criteria::expr()->in('user', $userList));
}
if (!empty($sessionId)) {
$criteria->where(Criteria::expr()->in('user', $userList));
}
if ($showPrivate == false) {
if ($showPrivate === false) {
$criteria->andWhere(Criteria::expr()->eq('private', false));
}
@ -58,9 +81,9 @@ if (!empty($userList) || api_is_platform_admin()) {
;
if (!empty($keyword)) {
$keyword = explode(' ', $keyword);
if (is_array($keyword)) {
foreach ($keyword as $key) {
$keywordToArray = explode(' ', $keyword);
if (is_array($keywordToArray)) {
foreach ($keywordToArray as $key) {
$key = trim($key);
if (empty($key)) {
continue;
@ -78,15 +101,45 @@ if (!empty($userList) || api_is_platform_admin()) {
}
}
$queryBuilderOriginal = clone $qb;
if (!empty($selectedTag)) {
$qb->andWhere('p.tags LIKE :tags ');
$qb->setParameter('tags', "%$selectedTag%");
}
$query = $qb->getQuery();
$items = new Paginator($query);
$queryBuilderOriginal->select('p.tags')
->distinct(false)
->setFirstResult(null)
->setMaxResults(null)
->groupBy('p.id')
;
$tags = $queryBuilderOriginal->getQuery()->getResult();
//var_dump($queryBuilderOriginal->getQuery()->getSQL());
$tagList = [];
foreach ($tags as $tag) {
$itemTags = $tag['tags'];
foreach ($itemTags as $itemTag) {
if (in_array($itemTag, array_keys($tagList))) {
$tagList[$itemTag]++;
} else {
$tagList[$itemTag] = 1;
}
}
}
$totalItems = $items->count();
$pagesCount = ceil($totalItems / $pageSize);
}
$pagination = '';
$url = api_get_self().'?';
if ($totalItems > 1) {
$url = api_get_self().'?session_id='.$sessionId.'&tag='.$selectedTag.'&keyword='.$keyword.'&';
if ($totalItems > 1 && $pagesCount > 1) {
$pagination .= '<ul class="pagination">';
for ($i = 0; $i < $pagesCount; $i++) {
$newPage = $i + 1;
@ -100,17 +153,42 @@ if ($totalItems > 1) {
}
// Create a search-box
$form = new FormValidator('search_simple', 'get', null, null, null, 'inline');
$form = new FormValidator('search_simple', 'get', null, null, null, FormValidator::LAYOUT_HORIZONTAL);
$form->addText(
'keyword',
get_lang('Search'),
false,
[
'aria-label' => get_lang("SearchUsers"),
'aria-label' => get_lang('SearchUsers'),
]
);
if (!empty($fullSessionList)) {
$options = array_column($fullSessionList, 'name', 'id');
$options[0] = get_lang('SelectAnOption');
ksort($options);
$form->addSelect('session_id', get_lang('Session'), $options);
}
if (!empty($tagList)) {
$tagOptions = [];
arsort($tagList);
foreach ($tagList as $tag => $counter) {
$tagOptions[$tag] = $tag.' ('.$counter.')';
}
$form->addSelect('tag', get_lang('Tags'), $tagOptions, ['placeholder' => get_lang('SelectAnOption')]);
}
$form->addButtonSearch(get_lang('Search'));
$defaults = [
'session_id' => $sessionId,
'keyword' => $keyword,
'tag' => $selectedTag,
];
$form->setDefaults($defaults);
$tpl = new Template($plugin->get_lang('plugin_title'));
$tpl->assign('users', $items);
$tpl->assign('form', $form->returnForm());
@ -121,7 +199,5 @@ $tpl->assign('my_students_url', $url);
$tpl->assign('pagination', $pagination);
$tpl->assign('care_title', $plugin->get_lang('CareDetailView'));
$content = $tpl->fetch('/'.$plugin->get_name().'/view/my_students.html.twig');
// Assign into content
$tpl->assign('content', $content);
// Display
$tpl->display_one_col_template();

@ -3,8 +3,8 @@
{% if users %}
<table class="data_table">
<tr>
<th>Student</th>
<th>Action</th>
<th>{{'Student' | get_lang }}</th>
<th>{{'Action' | get_lang }}</th>
</tr>
{% for user in users %}
<tr>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save