diff --git a/.hgignore b/.hgignore index 1fe06ca119..3542bea55f 100644 --- a/.hgignore +++ b/.hgignore @@ -116,4 +116,6 @@ syntax: regexp ^main/upload/users$ syntax: regexp -^\.settings$ \ No newline at end of file +^\.settings$ + +nbproject/* \ No newline at end of file diff --git a/custompages/index-unlogged.php b/custompages/index-unlogged.php index 371ea315f6..ad0bdf9984 100644 --- a/custompages/index-unlogged.php +++ b/custompages/index-unlogged.php @@ -29,13 +29,14 @@ if (isset($_GET['loginFailed'])){ Custompage - login - + - + + + + + + + + + + + +
+
+ + +
+ + += '5.3' && extension_loaded('fileinfo')) { + $finfo = new finfo(FILEINFO_MIME); + $current_mime=$finfo->buffer($contents); + finfo_close($finfo); + if(strpos($current_mime, 'image')===false) { + echo "Invalid mime type file"; + exit; + } +} //path, file and title $paintFileName = $filename.'.'.$extension; @@ -127,7 +168,8 @@ if($currentTool=='document/createpaint'){ //delete temporal file -unlink($_SESSION['temp_realpath_image']); +$temp_file_2delete=$_SESSION['temp_realpath_image']; +unlink($temp_file_2delete); //Clean sessions and return to Chamilo file list unset($_SESSION['paint_dir']); diff --git a/main/inc/lib/nanogong/receiver.php b/main/inc/lib/nanogong/receiver.php index f5a284fefa..b2f8a16810 100644 --- a/main/inc/lib/nanogong/receiver.php +++ b/main/inc/lib/nanogong/receiver.php @@ -6,7 +6,7 @@ * * @package chamilo.document * - * @author Juan Carlos Ra�a Trabado + * @author Juan Carlos Raña Trabado * @since 5/mar/2011 */ /** @@ -15,18 +15,23 @@ require_once '../../../inc/global.inc.php'; require_once api_get_path(LIBRARY_PATH).'fileUpload.lib.php'; -//security. Nanogong need less security because under Firefox, Chrome..., not save user_id... +//security. Nanogong need less security because under Firefox, Chrome..., not stay SESSION if (api_get_setting('enable_nanogong') == 'false'){ api_protect_course_script(); api_block_anonymous_users(); } -if (!isset($_GET['filename']) || !isset($_GET['filepath']) || !isset($_GET['dir']) || !isset($_GET['course_code'])){ - api_not_allowed(true); +if (!isset($_GET['filename']) || !isset($_GET['filepath']) || !isset($_GET['dir']) || !isset($_GET['course_code'])|| !isset($_GET['nano_group_id']) || !isset($_GET['nano_session_id']) || !isset($_GET['nano_user_id'])){ + echo 'Error. Not allowed'; + exit; } if (!is_uploaded_file($_FILES['voicefile']['tmp_name'])) exit; //clean +$nano_user_id=Security::remove_XSS($_GET['nano_user_id']); +$nano_group_id=Security::remove_XSS($_GET['nano_group_id']); +$nano_session_id=Security::remove_XSS($_GET['nano_session_id']); + $filename=Security::remove_XSS($_GET['filename']); $filename=urldecode($filename); $filepath=Security::remove_XSS(urldecode($_GET['filepath'])); @@ -41,21 +46,33 @@ $filename = Database::escape_string($filename); $filename = replace_dangerous_char($filename, $strict = 'loose');// or strict $filename = disable_dangerous_file($filename); -$title= str_replace('_',' ',$filename); +$title= trim(str_replace('_chnano_.','.',$filename));//hide nanogong wav tag at title +$title= str_replace('_',' ',$title); + // $documentPath = $filepath.$filename; +/* +//comment because here api_get_user_id() return alway 0 +if ($nano_user_id!= api_get_user_id() || api_get_user_id()==0 || $nano_user_id==0) { + echo 'Not allowed'; + exit; +} +*/ + +//Do not use here check Fileinfo method because return: text/plain + if (!file_exists($documentPath)){ //add document to disk move_uploaded_file($_FILES['voicefile']['tmp_name'], $documentPath); //add document to database - $current_session_id = api_get_session_id(); - $groupId=$_SESSION['_gid']; + $current_session_id = $nano_session_id; // $nano_session_id instead api_get_session_id() because here $_SESSION is lost + $groupId=$nano_group_id; // $nano_group_id instead $_SESSION['_gid'], because here $_SESSION is lost. $file_size = filesize($documentPath); $relativeUrlPath=$dir; $doc_id = add_document($_course, $relativeUrlPath.$filename, 'file', filesize($documentPath), $title); - api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', $_user['user_id'], $groupId, null, null, null, $current_session_id); + api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', $nano_user_id, $groupId, null, null, null, $current_session_id);// $nano_user_id instead $_user['user_id'], because here $_user['user_id'] is lost. } else { return get_lang('FileExistRename'); } \ No newline at end of file diff --git a/main/inc/lib/plugin.class.php b/main/inc/lib/plugin.class.php new file mode 100644 index 0000000000..a90241e2ed --- /dev/null +++ b/main/inc/lib/plugin.class.php @@ -0,0 +1,176 @@ + + */ +class Plugin +{ + + protected $version = ''; + protected $author = ''; + protected $fields = array(); + + protected function __construct($version, $author, $settings = array()) + { + $this->version = $version; + $this->author = $author; + $this->fields = $settings; + + global $language_files; + $language_files[] = 'plugin_' . $this->get_name(); + } + + function get_info() + { + $result = array(); + + $result['title'] = $this->get_title(); + $result['comment'] = $this->get_comment(); + $result['version'] = $this->get_version(); + $result['author'] = $this->get_author(); + if ($form = $this->get_settings_form()) + { + $result['settings_form'] = $form; + foreach ($this->fields as $name => $type) + { + $value = $this->get($name); + $result[$name] = $value; + } + } + return $result; + } + + function get_name() + { + $result = get_class($this); + $result = str_replace('Plugin', '', $result); + $result = strtolower($result); + return $result; + } + + function get_title() + { + return $this->get_lang('plugin_title'); + } + + function get_comment() + { + return $this->get_lang('plugin_comment'); + } + + function get_version() + { + return $this->version; + } + + function get_author() + { + return $this->author; + } + + function get_css() + { + $name = $this->get_name(); + $root = api_get_path(SYS_PLUGIN_PATH); + $path = "$root/$name/resources/$name.css"; + if (!is_readable($path)) + { + return ''; + } + $css = array(); + $css[] = file_get_contents($path); + $result = implode($css); + return $result; + } + + /** + * + * @return FormValidator + */ + function get_settings_form() + { + $result = new FormValidator($this->get_name()); + + $defaults = array(); + foreach ($this->fields as $name => $type) + { + $value = $this->get($name); + $defaults[$name] = $value; + $type = $type ? $type : 'text'; + if ($type == 'wysiwyg') + { + $result->add_html_editor($name, $this->get_lang($name)); + } + else + { + $result->addElement($type, $name, $this->get_lang($name)); + } + } + $result->setDefaults($defaults); + + $result->addElement('style_submit_button', 'submit_button', $this->get_lang('Save')); + return $result; + } + + function get($name) + { + $content = ''; + $title = 'Static'; + $settings = $this->get_settings(); + foreach ($settings as $setting) + { + if ($setting['variable'] == ($this->get_name() . '_' . $name)) + { + return $setting['selected_value']; + } + } + + return false; + } + + private $settings = null; + + public function get_settings() + { + if (is_null($this->settings)) + { + $settings = api_get_settings_params(array("subkey = ? AND category = ? AND type = ? " => array($this->get_name(), 'Plugins', 'setting'))); + $this->settings = $settings; + } + return $this->settings; + } + + private $strings = null; + + public function get_lang($name) + { + if (is_null($this->strings)) + { + global $language_interface; + + $root = api_get_path(SYS_PLUGIN_PATH); + $plugin_name = $this->get_name(); + $language = $language_interface; + $path = "$root/$plugin_name/lang/$language.php"; + if (is_readable($path)) + { + include $path; + $this->strings = $strings; + } + else + { + $this->strings = array(); + } + } + if (isset($this->strings[$name])) + { + return $this->strings[$name]; + } + return get_lang($name); + } + +} \ No newline at end of file diff --git a/main/inc/lib/svg-edit/extensions/filesave.php b/main/inc/lib/svg-edit/extensions/filesave.php index 1763a08a62..57d04d8b7f 100644 --- a/main/inc/lib/svg-edit/extensions/filesave.php +++ b/main/inc/lib/svg-edit/extensions/filesave.php @@ -83,7 +83,7 @@ if ($suffix!= 'svg' && $suffix!= 'png'){ //a bit mime security //comment because finfo seems stopping the save process files in some php vers. /* -if (phpversion() >= '5.3') { +if (phpversion() >= '5.3' && extension_loaded('fileinfo')) { $finfo = new finfo(FILEINFO_MIME); $current_mime=$finfo->buffer($contents); finfo_close($finfo); diff --git a/main/inc/lib/userportal.lib.php b/main/inc/lib/userportal.lib.php index 3498f5b22a..4e1bd2b792 100644 --- a/main/inc/lib/userportal.lib.php +++ b/main/inc/lib/userportal.lib.php @@ -423,6 +423,7 @@ class IndexManager { * @author Patrick Cool , Ghent University - refactoring and code cleaning */ function display_anonymous_course_list() { + $result = ''; $ctok = $_SESSION['sec_token']; $stok = Security::get_token(); @@ -553,12 +554,12 @@ class IndexManager { } $htmlListCat .= ""; } - echo $htmlTitre; + $result .= $htmlTitre; if ($thereIsSubCat) { - echo $htmlListCat; + $result .= $htmlListCat; } while ($categoryName = Database::fetch_array($resCats)) { - echo '

', $categoryName['name'], "

\n"; + $result .= '

' . $categoryName['name'] . "

\n"; } $numrows = Database::num_rows($sql_result_courses); $courses_list_string = ''; @@ -657,16 +658,17 @@ class IndexManager { } $courses_list_string .= ""; } else { - //echo '
', get_lang('_No_course_publicly_available'), "
\n"; + //$result .= '
', get_lang('_No_course_publicly_available'), "
\n"; } if ($courses_shown > 0) { // Only display the list of courses and categories if there was more than // 0 courses visible to the world (we're in the anonymous list here). - echo $courses_list_string; + $result .= $courses_list_string; } if ($category != '') { - echo '

', Display :: return_icon('back.png', get_lang('BackToHomePage')), get_lang('BackToHomePage'), '

'; + $result .= '

' . Display :: return_icon('back.png', get_lang('BackToHomePage')) . get_lang('BackToHomePage') . '

'; } + return '
' . $result . '
'; } /** diff --git a/main/inc/lib/wami-recorder/Wami.swf b/main/inc/lib/wami-recorder/Wami.swf new file mode 100644 index 0000000000..047bbc39ae Binary files /dev/null and b/main/inc/lib/wami-recorder/Wami.swf differ diff --git a/main/inc/lib/wami-recorder/buttons.png b/main/inc/lib/wami-recorder/buttons.png new file mode 100644 index 0000000000..3520230b03 Binary files /dev/null and b/main/inc/lib/wami-recorder/buttons.png differ diff --git a/main/inc/lib/wami-recorder/gui.js b/main/inc/lib/wami-recorder/gui.js new file mode 100644 index 0000000000..5cff480c92 --- /dev/null +++ b/main/inc/lib/wami-recorder/gui.js @@ -0,0 +1,349 @@ +var Wami = window.Wami || {}; + +// Upon a creation of a new Wami.GUI(options), we assume that a WAMI recorder +// has been initialized. +Wami.GUI = function(options) { + var RECORD_BUTTON = 1; + var PLAY_BUTTON = 2; + + setOptions(options); + setupDOM(); + + var recordButton, playButton; + var recordInterval, playInterval; + + function createDiv(id, style) { + var div = document.createElement("div"); + if (id) { + div.setAttribute('id', id); + } + if (style) { + div.style.cssText = style; + } + return div; + } + + function setOptions(options) { + if (!options.buttonUrl) { + options.buttonUrl = "buttons.png"; + } + + if (typeof options.listen == 'undefined' || options.listen) { + listen(); + } + } + + function setupDOM() { + var guidiv = createDiv(null, + "position: absolute; width: 214px; height: 137px;"); + document.getElementById(options.id).appendChild(guidiv); + + var rid = Wami.createID(); + var recordDiv = createDiv(rid, + "position: absolute; left: 40px; top: 25px"); + guidiv.appendChild(recordDiv); + + recordButton = new Button(rid, RECORD_BUTTON, options.buttonUrl); + recordButton.onstart = startRecording; + recordButton.onstop = stopRecording; + + recordButton.setEnabled(true); + + if (!options.singleButton) { + var pid = Wami.createID(); + var playDiv = createDiv(pid, + "position: absolute; right: 40px; top: 25px"); + guidiv.appendChild(playDiv); + + playButton = new Button(pid, PLAY_BUTTON, options.buttonUrl); + playButton.onstart = startPlaying; + playButton.onstop = stopPlaying; + } + } + + /** + * These methods are called on clicks from the GUI. + */ + function startRecording() { + if (!options.recordUrl) { + alert("No record Url specified!"); + } + recordButton.setActivity(0); + playButton.setEnabled(false); + Wami.startRecording(options.recordUrl, + Wami.nameCallback(onRecordStart), Wami + .nameCallback(onRecordFinish), Wami + .nameCallback(onError)); + } + + function stopRecording() { + Wami.stopRecording(); + clearInterval(recordInterval); + recordButton.setEnabled(true); + } + + function startPlaying() { + if (!options.playUrl) { + alert('No play URL specified!'); + } + + playButton.setActivity(0); + recordButton.setEnabled(false); + + Wami.startPlaying(options.playUrl, Wami.nameCallback(onPlayStart), Wami + .nameCallback(onPlayFinish), Wami.nameCallback(onError)); + } + + function stopPlaying() { + Wami.stopPlaying(); + } + + this.setPlayUrl = function(url) { + options.playUrl = url; + } + + this.setRecordUrl = function(url) { + options.recordUrl = url; + } + + this.setPlayEnabled = function(val) { + playButton.setEnabled(val); + } + + this.setRecordEnabled = function(val) { + recordButton.setEnabled(val); + } + + /** + * Callbacks from the flash indicating certain events + */ + + function onError(e) { + alert(e); + } + + function onRecordStart() { + recordInterval = setInterval(function() { + if (recordButton.isActive()) { + var level = Wami.getRecordingLevel(); + recordButton.setActivity(level); + } + }, 200); + if (options.onRecordStart) { + options.onRecordStart(); + } + } + + function onRecordFinish() { + playButton.setEnabled(true); + if (options.onRecordFinish) { + options.onRecordFinish(); + } + } + + function onPlayStart() { + playInterval = setInterval(function() { + if (playButton.isActive()) { + var level = Wami.getPlayingLevel(); + playButton.setActivity(level); + } + }, 200); + if (options.onPlayStart) { + options.onPlayStart(); + } + } + + function onPlayFinish() { + clearInterval(playInterval); + recordButton.setEnabled(true); + playButton.setEnabled(true); + if (options.onPlayFinish) { + options.onPlayFinish(); + } + } + + function listen() { + Wami.startListening(); + // Continually listening when the window is in focus allows us to + // buffer a little audio before the users clicks, since sometimes + // people talk too soon. Without "listening", the audio would record + // exactly when startRecording() is called. + window.onfocus = function() { + Wami.startListening(); + }; + + // Note that the use of onfocus and onblur should probably be replaced + // with a more robust solution (e.g. jQuery's $(window).focus(...) + window.onblur = function() { + Wami.stopListening(); + }; + } + + function Button(buttonid, type, url) { + var self = this; + self.active = false; + self.type = type; + + init(); + + // Get the background button image position + // Index: 1) normal 2) pressed 3) mouse-over + function background(index) { + if (index == 1) + return "-56px 0px"; + if (index == 2) + return "0px 0px"; + if (index == 3) + return "-112px 0"; + alert("Background not found: " + index); + } + + // Get the type of meter and its state + // Index: 1) enabled 2) meter 3) disabled + function meter(index, offset) { + var top = 5; + if (offset) + top += offset; + if (self.type == RECORD_BUTTON) { + if (index == 1) + return "-169px " + top + "px"; + if (index == 2) + return "-189px " + top + "px"; + if (index == 3) + return "-249px " + top + "px"; + } else { + if (index == 1) + return "-269px " + top + "px"; + if (index == 2) + return "-298px " + top + "px"; + if (index == 3) + return "-327px " + top + "px"; + } + alert("Meter not found: " + self.type + " " + index); + } + + function silhouetteWidth() { + if (self.type == RECORD_BUTTON) { + return "20px"; + } else { + return "29px"; + } + } + + function mouseHandler(e) { + var rightclick; + if (!e) + var e = window.event; + if (e.which) + rightclick = (e.which == 3); + else if (e.button) + rightclick = (e.button == 2); + + if (!rightclick) { + if (self.active && self.onstop) { + self.active = false; + self.onstop(); + } else if (!self.active && self.onstart) { + self.active = true; + self.onstart(); + } + } + } + + function init() { + var div = document.createElement("div"); + var elem = document.getElementById(buttonid); + if (elem) { + elem.appendChild(div); + } else { + alert('Could not find element on page named ' + buttonid); + } + + self.guidiv = document.createElement("div"); + self.guidiv.style.width = '56px'; + self.guidiv.style.height = '63px'; + self.guidiv.style.cursor = 'pointer'; + self.guidiv.style.background = "url(" + url + ") no-repeat"; + self.guidiv.style.backgroundPosition = background(1); + div.appendChild(self.guidiv); + + // margin auto doesn't work in IE quirks mode + // http://stackoverflow.com/questions/816343/why-will-this-div-img-not-center-in-ie8 + // text-align is a hack to force it to work even if you forget the + // doctype. + self.guidiv.style.textAlign = 'center'; + + self.meterDiv = document.createElement("div"); + self.meterDiv.style.width = silhouetteWidth(); + self.meterDiv.style.height = '63px'; + self.meterDiv.style.margin = 'auto'; + self.meterDiv.style.cursor = 'pointer'; + self.meterDiv.style.position = 'relative'; + self.meterDiv.style.background = "url(" + url + ") no-repeat"; + self.meterDiv.style.backgroundPosition = meter(2); + self.guidiv.appendChild(self.meterDiv); + + self.coverDiv = document.createElement("div"); + self.coverDiv.style.width = silhouetteWidth(); + self.coverDiv.style.height = '63px'; + self.coverDiv.style.margin = 'auto'; + self.coverDiv.style.cursor = 'pointer'; + self.coverDiv.style.position = 'relative'; + self.coverDiv.style.background = "url(" + url + ") no-repeat"; + self.coverDiv.style.backgroundPosition = meter(1); + self.meterDiv.appendChild(self.coverDiv); + + self.active = false; + self.guidiv.onmousedown = mouseHandler; + } + + self.isActive = function() { + return self.active; + } + + self.setActivity = function(level) { + self.guidiv.onmouseout = function() { + }; + self.guidiv.onmouseover = function() { + }; + self.guidiv.style.backgroundPosition = background(2); + self.coverDiv.style.backgroundPosition = meter(1, 5); + self.meterDiv.style.backgroundPosition = meter(2, 5); + + var totalHeight = 31; + var maxHeight = 9; + + // When volume goes up, the black image loses height, + // creating the perception of the colored one increasing. + var height = (maxHeight + totalHeight - Math.floor(level / 100 + * totalHeight)); + self.coverDiv.style.height = height + "px"; + } + + self.setEnabled = function(enable) { + var guidiv = self.guidiv; + self.active = false; + if (enable) { + self.coverDiv.style.backgroundPosition = meter(1); + self.meterDiv.style.backgroundPosition = meter(1); + guidiv.style.backgroundPosition = background(1); + guidiv.onmousedown = mouseHandler; + guidiv.onmouseover = function() { + guidiv.style.backgroundPosition = background(3); + }; + guidiv.onmouseout = function() { + guidiv.style.backgroundPosition = background(1); + }; + } else { + self.coverDiv.style.backgroundPosition = meter(3); + self.meterDiv.style.backgroundPosition = meter(3); + guidiv.style.backgroundPosition = background(1); + guidiv.onmousedown = null; + guidiv.onmouseout = function() { + }; + guidiv.onmouseover = function() { + }; + } + } + } +} diff --git a/main/inc/lib/wami-recorder/index.html b/main/inc/lib/wami-recorder/index.html new file mode 100644 index 0000000000..aa7b9c934b --- /dev/null +++ b/main/inc/lib/wami-recorder/index.html @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/main/inc/lib/wami-recorder/record_document.php b/main/inc/lib/wami-recorder/record_document.php new file mode 100644 index 0000000000..6c89cf4614 --- /dev/null +++ b/main/inc/lib/wami-recorder/record_document.php @@ -0,0 +1,64 @@ + \ No newline at end of file diff --git a/main/inc/lib/wami-recorder/recorder.js b/main/inc/lib/wami-recorder/recorder.js new file mode 100644 index 0000000000..299e084b46 --- /dev/null +++ b/main/inc/lib/wami-recorder/recorder.js @@ -0,0 +1,273 @@ +var Wami = window.Wami || {}; + +// Returns a (very likely) unique string with of random letters and numbers +Wami.createID = function() { + return "wid" + ("" + 1e10).replace(/[018]/g, function(a) { + return (a ^ Math.random() * 16 >> a / 4).toString(16) + }); +} + +// Creates a named callback in WAMI and returns the name as a string. +Wami.nameCallback = function(cb, cleanup) { + Wami._callbacks = Wami._callbacks || {}; + var id = Wami.createID(); + Wami._callbacks[id] = function() { + if (cleanup) { + Wami._callbacks[id] = null; + } + cb.apply(null, arguments); + }; + var named = "Wami._callbacks['" + id + "']"; + return named; +} + +// This method ensures that a WAMI recorder is operational, and that +// the following API is available in the Wami namespace. All functions +// must be named (i.e. cannot be anonymous). +// +// Wami.startPlaying(url, startfn = null, finishedfn = null, failedfn = null); +// Wami.stopPlaying() +// +// Wami.startRecording(url, startfn = null, finishedfn = null, failedfn = null); +// Wami.stopRecording() +// +// Wami.getRecordingLevel() // Returns a number between 0 and 100 +// Wami.getPlayingLevel() // Returns a number between 0 and 100 +// +// Wami.hide() +// Wami.show() +// +// Manipulate the WAMI recorder's settings. In Flash +// we need to check if the microphone permission has been granted. +// We might also set/return sample rate here, etc. +// +// Wami.getSettings(); +// Wami.setSettings(options); +// +// Optional way to set up browser so that it's constantly listening +// This is to prepend audio in case the user starts talking before +// they click-to-talk. +// +// Wami.startListening() +// +Wami.setup = function(options) { + if (Wami.startRecording) { + // Wami's already defined. + if (options.onReady) { + options.onReady(); + } + return; + } + + // Assumes that swfobject.js is included if Wami.swfobject isn't + // already defined. + Wami.swfobject = Wami.swfobject || swfobject; + + if (!Wami.swfobject) { + alert("Unable to find swfobject to help embed the SWF."); + } + + var _options; + setOptions(options); + embedWamiSWF(_options.id, Wami.nameCallback(delegateWamiAPI)); + + function supportsTransparency() { + // Detecting the OS is a big no-no in Javascript programming, but + // I can't think of a better way to know if wmode is supported or + // not... since NOT supporting it (like Flash on Ubuntu) is a bug. + return (navigator.platform.indexOf("Linux") == -1); + } + + function setOptions(options) { + // Start with default options + _options = { + swfUrl : "Wami.swf", + onReady : function() { + Wami.hide(); + }, + onSecurity : checkSecurity, + onError : function(error) { + alert(error); + } + }; + + if (typeof options == 'undefined') { + alert('Need at least an element ID to place the Flash object.'); + } + + if (typeof options == 'string') { + _options.id = options; + } else { + _options.id = options.id; + } + + if (options.swfUrl) { + _options.swfUrl = options.swfUrl; + } + + if (options.onReady) { + _options.onReady = options.onReady; + } + + if (options.onLoaded) { + _options.onLoaded = options.onLoaded; + } + + if (options.onSecurity) { + _options.onSecurity = options.onSecurity; + } + + if (options.onError) { + _options.onError = options.onError; + } + + // Create a DIV for the SWF under _options.id + + var container = document.createElement('div'); + container.style.position = 'absolute'; + _options.cid = Wami.createID(); + container.setAttribute('id', _options.cid); + + var swfdiv = document.createElement('div'); + var id = Wami.createID(); + swfdiv.setAttribute('id', id); + + container.appendChild(swfdiv); + document.getElementById(_options.id).appendChild(container); + + _options.id = id; + } + + function checkSecurity() { + var settings = Wami.getSettings(); + if (settings.microphone.granted) { + _options.onReady(); + } else { + // Show any Flash settings panel you want: + // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/SecurityPanel.html + Wami.showSecurity("privacy", "Wami.show", Wami + .nameCallback(_options.onSecurity), Wami + .nameCallback(_options.onError)); + } + } + + // Embed the WAMI SWF and call the named callback function when loaded. + function embedWamiSWF(id, initfn) { + var flashVars = { + visible : false, + loadedCallback : initfn + } + + var params = { + allowScriptAccess : "always" + } + + if (supportsTransparency()) { + params.wmode = "transparent"; + } + + if (typeof console !== 'undefined') { + flashVars.console = true; + } + + var version = '10.0.0'; + document.getElementById(id).innerHTML = "WAMI requires Flash " + + version + + " or greater
https://get.adobe.com/flashplayer/"; + + // This is the minimum size due to the microphone security panel + Wami.swfobject.embedSWF(_options.swfUrl, id, 214, 137, version, null, + flashVars, params); + + // Without this line, Firefox has a dotted outline of the flash + Wami.swfobject.createCSS("#" + id, "outline:none"); + } + + // To check if the microphone settings were 'remembered', we + // must actually embed an entirely new Wami client and check + // whether its microphone is granted. If it is, it was remembered. + function checkRemembered(finishedfn) { + var id = Wami.createID(); + var div = document.createElement('div'); + div.style.top = '-999px'; + div.style.left = '-999px'; + div.setAttribute('id', id); + var body = document.getElementsByTagName('body').item(0); + body.appendChild(div); + + var fn = Wami.nameCallback(function() { + var swf = document.getElementById(id); + Wami._remembered = swf.getSettings().microphone.granted; + Wami.swfobject.removeSWF(id); + eval(finishedfn + "()"); + }); + + embedWamiSWF(id, fn); + } + + // Attach all the audio methods to the Wami namespace in the callback. + function delegateWamiAPI() { + var recorder = document.getElementById(_options.id); + + function delegate(name) { + Wami[name] = function() { + return recorder[name].apply(recorder, arguments); + } + } + delegate('startPlaying'); + delegate('stopPlaying'); + delegate('startRecording'); + delegate('stopRecording'); + delegate('startListening'); + delegate('stopListening'); + delegate('getRecordingLevel'); + delegate('getPlayingLevel'); + delegate('setSettings'); + + // Append extra information about whether mic settings are sticky + Wami.getSettings = function() { + var settings = recorder.getSettings(); + settings.microphone.remembered = Wami._remembered; + return settings; + } + + Wami.showSecurity = function(panel, startfn, finishedfn, failfn) { + // Flash must be on top for this. + var container = document.getElementById(_options.cid); + + var augmentedfn = Wami.nameCallback(function() { + checkRemembered(finishedfn); + container.style.cssText = "position: absolute;"; + }); + + container.style.cssText = "position: absolute; z-index: 99999"; + + recorder.showSecurity(panel, startfn, augmentedfn, failfn); + } + + Wami.show = function() { + if (!supportsTransparency()) { + recorder.style.visibility = "visible"; + } + } + + Wami.hide = function() { + // Hiding flash in all the browsers is tricky. Please read: + // https://code.google.com/p/wami-recorder/wiki/HidingFlash + if (!supportsTransparency()) { + recorder.style.visibility = "hidden"; + } + } + + // If we already have permissions, they were previously 'remembered' + Wami._remembered = recorder.getSettings().microphone.granted; + + if (_options.onLoaded) { + _options.onLoaded(); + } + + if (!_options.noSecurityCheck) { + checkSecurity(); + } + } +} diff --git a/main/install/db_main.sql b/main/install/db_main.sql index 8149b92792..962caa4346 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -864,7 +864,8 @@ VALUES ('login_is_email', NULL, 'radio', 'Platform', 'false', 'LoginIsEmailTitle', 'LoginIsEmailComment', NULL, NULL, 0), ('courses_default_creation_visibility', NULL, 'radio', 'Course', '2', 'CoursesDefaultCreationVisibilityTitle', 'CoursesDefaultCreationVisibilityComment', NULL, NULL, 1), ('allow_browser_sniffer', NULL, 'radio', 'Tuning', 'false', 'AllowBrowserSnifferTitle', 'AllowBrowserSnifferComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17053','DokeosDatabaseVersion','', NULL, NULL, 0); +('enable_wami_record',NULL,'radio','Tools','false','EnableWamiRecordTitle','EnableWamiRecordComment',NULL,NULL, 0), +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17054','DokeosDatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -1201,7 +1202,9 @@ VALUES ('courses_default_creation_visibility', '1', 'Private'), ('courses_default_creation_visibility', '0', 'CourseVisibilityClosed'), ('allow_browser_sniffer', 'true', 'Yes'), -('allow_browser_sniffer', 'false', 'No'); +('allow_browser_sniffer', 'false', 'No'), +('enable_wami_record', 'true', 'Yes'), +('enable_wami_record', 'false', 'No'); UNLOCK TABLES; /* diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index 4184c9a552..802f21b3ae 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -148,6 +148,11 @@ INSERT INTO settings_current (variable, subkey, type, category, selected_value, INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_browser_sniffer', 'true', 'Yes'); INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_browser_sniffer', 'false', 'No'); +INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('enable_wami_record', NULL, 'radio', 'Tools', 'false', 'EnableWamiRecordTitle', 'EnableWamiRecordComment', NULL, NULL, 0); +INSERT INTO settings_options (variable, value, display_text) VALUES ('enable_wami_record', 'true', 'Yes'); +INSERT INTO settings_options (variable, value, display_text) VALUES ('enable_wami_record', 'false', 'No'); + + -- Course ranking CREATE TABLE track_course_ranking (id int unsigned not null PRIMARY KEY AUTO_INCREMENT,c_id int unsigned not null, session_id int unsigned not null default 0, url_id int unsigned not null default 0, accesses int unsigned not null default 0, total_score int unsigned not null default 0, users int unsigned not null default 0, creation_date datetime not null); diff --git a/main/lang/english/shibboleth.inc.php b/main/lang/english/shibboleth.inc.php new file mode 100644 index 0000000000..231e7f45a9 --- /dev/null +++ b/main/lang/english/shibboleth.inc.php @@ -0,0 +1,25 @@ + + */ + +$no_login = 'The system was unable to log you in. Please contact your administrator.'; +$page_title = 'Shibboleth Login'; +$email = 'email'; +$submit = 'submit'; +$status = 'status'; +$new_status = 'New status'; +$reason = 'reason'; +$request_status = 'Request new status'; +$status_request_message = 'You have been logged-in with default rights. If you can request more rights by submitting the following request.'; +$reason_is_mandatory = 'You reason field is mandatory. Please fill it in before submitting.'; +$request_submitted = 'Your request has been submitted.'; +$request_failed = 'We appologize but we are not ableto fulfill your request at this time. Please contact your administrator.'; +$internal_login = 'Internal login'; +$already_logged_in = 'You are already logged in'; +$Pass = 'Password'; \ No newline at end of file diff --git a/main/lang/french/shibboleth.inc.php b/main/lang/french/shibboleth.inc.php new file mode 100644 index 0000000000..bc92400d27 --- /dev/null +++ b/main/lang/french/shibboleth.inc.php @@ -0,0 +1,24 @@ + + */ + +$no_login = "Le systéme n'a pas réussi à vous idenditfier. Veuiller contacter votre adminstrateur."; +$page_title = 'Login Shibboleth'; +$email = 'Email'; +$submit = 'Envoyer'; +$new_status = 'Nouveau status'; +$reason = 'Raison'; +$request_status = 'Demande de nouveau status'; +$status_request_message = 'Vous avez été enregistré avec les droits par défaut. Si vous le souhaitez vous pouvez remplir le formulaire ci-dessous pour demander plus de droits à votre administrateur.'; +$reason_is_mandatory = 'Le champs "raison" est obligatoire. Veuillez remplir ce champs avant de soumettre votre formulaire.'; +$request_submitted = 'Votre requête à été soumise. Elle sera traitée prochainement.'; +$request_failed = "Nous ne sommes malheureusement pas en mesure de traiter votre demande pour le moment. Veuillez s'il vous plait prendre contacte avec votre administrateur ou réessayer à une date ultérieur."; +$internal_login = 'Login Interne'; +$already_logged_in = 'Vous êtes déjà connecté'; +$Pass = 'Mot de passe'; \ No newline at end of file diff --git a/main/template/default/layout/hot_courses.tpl b/main/template/default/layout/hot_courses.tpl index 9c110b41ac..e0f36a02de 100644 --- a/main/template/default/layout/hot_courses.tpl +++ b/main/template/default/layout/hot_courses.tpl @@ -1,4 +1,4 @@ -{% if hot_courses is not null %} +{% if hot_courses is not null and hot_courses is not empty %} + + + $title +
+ + +EOT; diff --git a/plugin/rss/lang/english.php b/plugin/rss/lang/english.php new file mode 100644 index 0000000000..e98e541feb --- /dev/null +++ b/plugin/rss/lang/english.php @@ -0,0 +1,16 @@ + + */ +$strings['plugin_title'] = "Rss"; +$strings['plugin_comment'] = "Display rss content."; + +$strings['rss'] = "Rss"; +$strings['block_title'] = "Block title"; + +$strings['title'] = "Title"; +$strings['no_rss'] = "There is no RSS configured. Please add a RSS"; \ No newline at end of file diff --git a/plugin/rss/lang/french.php b/plugin/rss/lang/french.php new file mode 100644 index 0000000000..92ec942b4b --- /dev/null +++ b/plugin/rss/lang/french.php @@ -0,0 +1,13 @@ + + */ + +$strings['plugin_title'] = "Rss"; +$strings['plugin_comment'] = "Affiche le contenu de flux rss."; + +$strings['title'] = "Titre"; +$strings['no_rss'] = "Veuillez configurer"; \ No newline at end of file diff --git a/plugin/rss/lib/rss_plugin.class.php b/plugin/rss/lib/rss_plugin.class.php new file mode 100644 index 0000000000..9a8de34ffb --- /dev/null +++ b/plugin/rss/lib/rss_plugin.class.php @@ -0,0 +1,38 @@ + + */ +class RssPlugin extends Plugin +{ + + /** + * + * @return RssPlugin + */ + static function create() + { + static $result = null; + return $result ? $result : $result = new self(); + } + + function get_block_title() + { + return $this->get('block_title'); + } + + function get_rss() + { + return $this->get('rss'); + } + + protected function __construct() + { + parent::__construct('1.1', 'Laurent Opprecht', array('block_title' => 'text', 'rss' => 'text')); + } + +} \ No newline at end of file diff --git a/plugin/rss/plugin.php b/plugin/rss/plugin.php new file mode 100644 index 0000000000..f998de58d8 --- /dev/null +++ b/plugin/rss/plugin.php @@ -0,0 +1,16 @@ +get_info(); diff --git a/plugin/rss/readme.txt b/plugin/rss/readme.txt new file mode 100644 index 0000000000..1ebcbe17b1 --- /dev/null +++ b/plugin/rss/readme.txt @@ -0,0 +1,4 @@ +Display RSS feeds using the Google Dynamic Feed control. +

+See http://www.google.com/uds/solutions/dynamicfeed/index.html for further information. +

\ No newline at end of file diff --git a/plugin/rss/resources/arrow-bullet.png b/plugin/rss/resources/arrow-bullet.png new file mode 100644 index 0000000000..bbb5d27e5a Binary files /dev/null and b/plugin/rss/resources/arrow-bullet.png differ diff --git a/plugin/rss/resources/color.css b/plugin/rss/resources/color.css new file mode 100644 index 0000000000..de6366f445 --- /dev/null +++ b/plugin/rss/resources/color.css @@ -0,0 +1,41 @@ + +.gfg-root a:link, +.gfg-root a:visited, +.gfg-root a:focus, +.gfg-root a:active +{ + color: #CC0066; +} + +.gfg-subtitle, .gfg-title{ + background-color: #CC0066 !important; + color: #FFFFFF !important; +} + +.gfg-subtitle > a{ + color: #FFFFFF !important; +} + +.gfg-subtitle > a:hover{ + color: black !important; +} + +.gfg-root a:hover, .gfg-subtitle:hover { + color: black; +} + +.gfg-listentry-odd:hover{ + background-color: #E9E9F0 !important; +} + +.gfg-listentry-even:hover{ + background-color: #E9E9F0 !important; +} + +.gfg-horizontal-root .gfg-entry .gf-result, .gfg-horizontal-root .gfg-entry, .gfg-horizontal-root .gf-snippet{ + background-color: white !important; +} + +.gfg-horizontal-root .gfg-entry { + background-color: white !important; +} diff --git a/plugin/rss/resources/rss.css b/plugin/rss/resources/rss.css new file mode 100644 index 0000000000..0657d8a391 --- /dev/null +++ b/plugin/rss/resources/rss.css @@ -0,0 +1,103 @@ +@import url(http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css); + +.well.sidebar-nav.rss +{ +} + +/*google feeds*/ + +.gfg-listentry-highlight, +.gfg-listentry +{ + background-position: left center; + background-repeat: no-repeat; + padding-left: 20px; +} + +.gfg-root a:link, +.gfg-root a:visited, +.gfg-root a:focus, +.gfg-root a:active +{ + font-weight: normal; + text-decoration: none; +} + +.gfg-root { + font-family: Verdana,Geneva,Arial,Helvetica,sans-serif !important; + border-left:0px; + border-right:0px; + border-top:0px ; +} +.gfg-listentry { + line-height: 14px !important; +} + +.gfg-listentry{ + white-space: normal; +} + +.gfg-subtitle, .gfg-title{ + font-weight: bold ; +} + +.gfg-title{ + display: none; +} + +.gfg-subtitle a:link, .gfg-title a:link{ + font-weight: bold; +} + +.gfg-root .gfg-entry .gf-result .gf-title{ + white-space: normal !important; +} + +.gfg-entry{ + height:9.5em !important; + /* border: 1px solid grey; + border-radius: 8px 8px 8px 8px; + margin:2px;*/ +} + +.gfg-root, .gfg-entry, .gf-result, .gf-snippet{ + background-color: transparent !important; +} + +.gfg-root a:hover, .gfg-subtitle:hover { + text-decoration: none; +} + +.gfg-listentry{ + height: auto; + padding-top:4px; + padding-bottom: 4px; + border-bottom-style: dotted; + border-bottom-width: 1px; +} + +.gfg-listentry-odd { + background-color: transparent !important; +} + +.gf-author, .gf-relativePublishedDate, .gf-spacer{ + display:none !important; +} + +.gfg-horizontal-root .gfg-entry .gf-result .gf-snippet { + display: block; + clear:both; +} + +.gfg-branding{ + display:none; +} + +.gfg-horizontal-root{ + height: auto; + border:none; +} + +.gfg-horizontal-container{ + display:inline; +} \ No newline at end of file diff --git a/plugin/search_course/index.php b/plugin/search_course/index.php new file mode 100644 index 0000000000..f5701a09a4 --- /dev/null +++ b/plugin/search_course/index.php @@ -0,0 +1,5 @@ +run(); diff --git a/plugin/search_course/lang/english.php b/plugin/search_course/lang/english.php new file mode 100644 index 0000000000..4474823a0f --- /dev/null +++ b/plugin/search_course/lang/english.php @@ -0,0 +1,10 @@ + + */ + +$strings['plugin_title'] = "Search Course"; +$strings['plugin_comment'] = "Allow to search the course catalog and register to courses."; diff --git a/plugin/search_course/lang/french.php b/plugin/search_course/lang/french.php new file mode 100644 index 0000000000..207b07a15a --- /dev/null +++ b/plugin/search_course/lang/french.php @@ -0,0 +1,10 @@ + + */ + +$strings['plugin_title'] = "Rechercher un cours"; +$strings['plugin_comment'] = "Permets de rechercher un cours dans le catalogue et de s'inscrire."; \ No newline at end of file diff --git a/plugin/search_course/lib/register_course_widget.class.php b/plugin/search_course/lib/register_course_widget.class.php new file mode 100644 index 0000000000..397454f30a --- /dev/null +++ b/plugin/search_course/lib/register_course_widget.class.php @@ -0,0 +1,163 @@ +action_subscribe_user(); + } + + /** + * Handle the subscribe action. + * + * @return bool + */ + function action_subscribe_user() + { + $action = self::get('action'); + if ($action != self::ACTION_SUBSCRIBE) + { + return false; + } + + $course_code = self::post(self::PARAM_SUBSCRIBE); + if (empty($course_code)) + { + return false; + } + + $registration_code = self::post(self::PARAM_PASSCODE); + + if ($this->subscribe_user($course_code, $registration_code)) + { + Display::display_confirmation_message(get_lang('EnrollToCourseSuccessful')); + return; + } + if (!empty($registration_code)) + { + Display::display_error_message(get_lang('CourseRegistrationCodeIncorrect')); + } + $this->display_form($course_code); + return true; + } + + /** + * Regiser a user to a course. + * Returns true on success, false otherwise. + * + * @param string $course_code + * @param string $registration_code + * @param int $user_id + * @return bool + */ + function subscribe_user($course_code, $registration_code = '', $user_id = null) + { + $course = $this->retrieve_course($course_code); + $course_regisration_code = $course['registration_code']; + if (!empty($course_regisration_code) && $registration_code != $course_regisration_code) + { + return false; + } + + if (empty($user_id)) + { + global $_user; + $user_id = $_user['user_id']; + } + + return (bool) CourseManager::add_user_to_course($user_id, $course_code); + } + + /** + * Display the course registration form. + * Asks for registration code/password. + * + * @param string $course_code + */ + function display_form($course_code) + { + global $stok; + + $course = $this->retrieve_course($course_code); + $self = $_SERVER['REQUEST_URI']; + $course_code = $course['code']; + $course_visual_code = $course['visual_code']; + $course_title = $course['title']; + $submit_registration_code_label = get_lang("SubmitRegistrationCode"); + $course_requires_password_label = get_lang('CourseRequiresPassword'); + + $result = << + $course_visual_code - $course_title +
+ + + +
+EOT; + echo $result; + } + + /** + * DB functions - DB functions - DB functions + */ + + /** + * + * @param type $course_code + * @return type + */ + function retrieve_course($course_code) + { + require_once api_get_path(SYS_PATH) . '/main/inc/lib/course.lib.php'; + return CourseManager::get_course_information($course_code); + } + +} diff --git a/plugin/search_course/lib/search_course_plugin.class.php b/plugin/search_course/lib/search_course_plugin.class.php new file mode 100644 index 0000000000..31234e1315 --- /dev/null +++ b/plugin/search_course/lib/search_course_plugin.class.php @@ -0,0 +1,33 @@ + + */ +class SearchCoursePlugin extends Plugin +{ + + /** + * + * @return SearchCoursePlugin + */ + static function create() + { + static $result = null; + return $result ? $result : $result = new self(); + } + + function get_name() + { + return 'search_course'; + } + + protected function __construct() + { + parent::__construct('1.1', 'Laurent Opprecht'); + } + +} \ No newline at end of file diff --git a/plugin/search_course/lib/search_course_widget.class.php b/plugin/search_course/lib/search_course_widget.class.php new file mode 100644 index 0000000000..8ac60850af --- /dev/null +++ b/plugin/search_course/lib/search_course_widget.class.php @@ -0,0 +1,435 @@ +get_lang($name); + } + + /** + * + * @return bool + */ + function is_homepage() + { + + $url = self::server('REQUEST_URI'); + $url = explode('?', $url); + $url = reset($url); + $url = self::server('SERVER_NAME') . $url; + + $root = api_get_path('WEB_PATH'); + $root = str_replace('https://', '', $root); + $root = str_replace('http://', '', $root); + $index_url = $root . 'index.php'; + + return $url == $index_url || $url == $root; + } + + /** + * + * @return bool + */ + function is_user_portal() + { + + $url = self::server('REQUEST_URI'); + $url = explode('?', $url); + $url = reset($url); + $url = self::server('SERVER_NAME') . $url; + + $root = api_get_path('WEB_PATH'); + $root = str_replace('https://', '', $root); + $root = str_replace('http://', '', $root); + $index_url = $root . 'user_portal.php'; + + return $url == $index_url || $url == $root; + } + + /** + * + */ + function accept() + { + return $this->is_homepage() || $this->is_user_portal(); + } + + /** + * Display the search course widget: + * + * Title + * Search form + * + * Search results + */ + function run() + { + if (!$this->accept()) + { + return; + } + $this->display_header(); + + $this->display_form(); + + $search_term = self::post('search_term'); + $action = self::get('action'); + + $has_content = !empty($search_term) || !empty($action); + if ($has_content) + { + echo '
'; + } + else + { + echo '
'; + } + + if (RegisterCourseWidget::factory()->run()) + { + $result = true; + } + else + { + $result = $this->action_display(); + } + + echo '
'; + + $this->display_footer(); + return $result; + } + + function get_url($action = '') + { + $self = $_SERVER['PHP_SELF']; + $parameters = array(); + if ($action) + { + $parameters[self::PARAM_ACTION] = $action; + } + $parameters = implode('&', $parameters); + $parameters = $parameters ? '?' . $parameters : ''; + return $self . $parameters; + } + + /** + * Handle the display action + */ + function action_display() + { + global $charset; + + $search_term = self::post('search_term'); + if ($search_term) + { + $search_result_for_label = self::get_lang('SearchResultsFor'); + $search_term_html = htmlentities($search_term, ENT_QUOTES, $charset); + echo "
$search_result_for_label $search_term_html
"; + + $courses = $this->retrieve_courses($search_term); + $this->display_list($courses); + } + return true; + } + + function display_header() + { + $search_course_label = self::get_lang('SearchCourse'); + echo << +
'; + } + + /** + * Display the search course form. + */ + function display_form() + { + global $stok; + + $search_label = self::get_lang('_search'); + $self = api_get_self(); + $search_term = self::post('search_term'); + $form = << + + + +   + +EOT; + echo $form; + } + + /** + * + * @param array $courses + * @return bool + */ + function display_list($courses) + { + if (empty($courses)) + { + return false; + } + + $user_courses = $this->retrieve_user_courses(); + + $display_coursecode = (get_setting('display_coursecode_in_courselist') == 'true'); + $display_teacher = (get_setting('display_teacher_in_courselist') == 'true'); + + echo ''; + foreach ($courses as $key => $course) + { + $details = array(); + if ($display_coursecode) + { + $details[] = $course['visual_code']; + } + if ($display_teacher) + { + $details[] = $course['tutor']; + } + $details = implode(' - ', $details); + $title = $course['title']; + + $href = api_get_path(WEB_PATH) . 'courses/' . $course['code']; + echo ''; + } + echo '
' . "$title
$details
"; + if ($course['registration_code']) + { + Display::display_icon('passwordprotected.png', '', array('style' => 'float:left;')); + } + $this->display_subscribe_icon($course, $user_courses); + echo '
'; + return true; + } + + /** + * Displays the subscribe icon if subscribing is allowed and + * if the user is not yet subscribed to this course + * + * @global type $stok + * @param array $current_course + * @param array $user_courses + * @return bool + */ + function display_subscribe_icon($current_course, $user_courses) + { + global $stok; + + //Already subscribed + $code = $current_course['code']; + if (isset($user_courses[$code])) + { + echo self::get_lang('AlreadySubscribed'); + return false; + } + + //Not authorized to subscribe + if ($current_course['subscribe'] != SUBSCRIBE_ALLOWED) + { + echo self::get_lang('SubscribingNotAllowed'); + return false; + } + + //Subscribe form + $self = $_SERVER['PHP_SELF']; + echo << + + +EOT; + + $search_term = $this->post('search_term'); + if ($search_term) + { + $search_term = Security::remove_XSS($search_term); + echo << + +EOT; + } + + $web_path = api_get_path(WEB_PATH); + $subscribe_label = get_lang('Subscribe'); + echo <<$subscribe_label + +EOT; + return true; + } + + /** + * DB functions - DB functions - DB functions + */ + + /** + * Search courses that match the search term. + * Search is done on the code, title and tutor fields. + * + * @param string $search_term + * @return array + */ + function retrieve_courses($search_term) + { + if (empty($search_term)) + { + return array(); + } + $search_term = Database::escape_string($search_term); + $course_table = Database::get_main_table(TABLE_MAIN_COURSE); + + $sql = << $code, + 'directory' => $row['directory'], + 'db' => $row['db_name'], + 'visual_code' => $row['visual_code'], + 'title' => $row['title'], + 'tutor' => $row['tutor_name'], + 'subscribe' => $row['subscribe'], + 'unsubscribe' => $row['unsubscribe'] + ); + } + return $result; + } + + /** + * Retrieves courses that the user is subscribed to + * + * @param int $user_id + * @return array + */ + function retrieve_user_courses($user_id = null) + { + if (is_null($user_id)) + { + global $_user; + $user_id = $_user['user_id']; + } + $course_table = Database::get_main_table(TABLE_MAIN_COURSE); + $user_course_table = Database::get_main_table(TABLE_MAIN_COURSE_USER); + + $user_id = intval($user_id); + $sql_select_courses = "SELECT course.code k, course.visual_code vc, course.subscribe subscr, course.unsubscribe unsubscr, + course.title i, course.tutor_name t, course.db_name db, course.directory dir, course_rel_user.status status, + course_rel_user.sort sort, course_rel_user.user_course_cat user_course_cat + FROM $course_table course, $user_course_table course_rel_user + WHERE course.code = course_rel_user.course_code + AND course_rel_user.user_id = $user_id + ORDER BY course_rel_user.sort ASC"; + $result = array(); + $resultset = api_sql_query($sql_select_courses, __FILE__, __LINE__); + while ($row = Database::fetch_array($resultset)) + { + $code = $row['k']; + $result[$code] = array( + 'db' => $row['db'], + 'code' => $code, + 'visual_code' => $row['vc'], + 'title' => $row['i'], + 'directory' => $row['dir'], + 'status' => $row['status'], + 'tutor' => $row['t'], + 'subscribe' => $row['subscr'], + 'unsubscribe' => $row['unsubscr'], + 'sort' => $row['sort'], + 'user_course_category' => $row['user_course_cat']); + } + return $result; + } + + /* + * Utility functions - Utility functions - Utility functions + */ + + /** + * Removes from $courses all courses the user is subscribed to. + * + * @global array $_user + * @param array $courses + * @return array + */ + function filter_out_user_courses($courses) + { + if (empty($courses)) + { + return $courses; + } + + global $_user; + $user_id = $_user['user_id']; + + $user_courses = $this->retrieve_user_courses($user_id); + foreach ($user_courses as $key => $value) + { + unset($courses[$key]); + } + return $courses; + } + +} diff --git a/plugin/search_course/plugin.php b/plugin/search_course/plugin.php new file mode 100644 index 0000000000..13e5d7c6c5 --- /dev/null +++ b/plugin/search_course/plugin.php @@ -0,0 +1,11 @@ +get_info(); \ No newline at end of file diff --git a/plugin/search_course/readme.txt b/plugin/search_course/readme.txt new file mode 100644 index 0000000000..386c386c14 --- /dev/null +++ b/plugin/search_course/readme.txt @@ -0,0 +1 @@ +Search courses in the main catalogue and register. \ No newline at end of file diff --git a/plugin/static/index.php b/plugin/static/index.php new file mode 100644 index 0000000000..3a30581014 --- /dev/null +++ b/plugin/static/index.php @@ -0,0 +1,28 @@ +get_content(); + +$title = $plugin->get_block_title(); +$title = $title ? "

$title

" : ''; + +$css = $plugin->get_css(); +$css = $css ? "" : ''; + +if (empty($content)) +{ + echo ''; +} + +echo << + $css + + +EOT; diff --git a/plugin/static/lang/english.php b/plugin/static/lang/english.php new file mode 100644 index 0000000000..6ee967fc00 --- /dev/null +++ b/plugin/static/lang/english.php @@ -0,0 +1,15 @@ + + */ + +$strings['plugin_title'] = "Static"; +$strings['plugin_comment'] = "Display static html content."; + +$strings['content'] = "Content"; +$strings['block_title'] = "Block title"; + +//$strings['title'] = "Title"; \ No newline at end of file diff --git a/plugin/static/lang/french.php b/plugin/static/lang/french.php new file mode 100644 index 0000000000..4d57ed2a28 --- /dev/null +++ b/plugin/static/lang/french.php @@ -0,0 +1,13 @@ + + */ + +$strings['plugin_title'] = "Statique"; +$strings['plugin_comment'] = "Affiche du contenu html."; + +$strings['content'] = "Contenu"; +$strings['block_title'] = "Titre du bloc"; diff --git a/plugin/static/lib/static_plugin.class.php b/plugin/static/lib/static_plugin.class.php new file mode 100644 index 0000000000..9f9018bd9d --- /dev/null +++ b/plugin/static/lib/static_plugin.class.php @@ -0,0 +1,38 @@ + + */ +class StaticPlugin extends Plugin +{ + + /** + * + * @return StaticPlugin + */ + static function create() + { + static $result = null; + return $result ? $result : $result = new self(); + } + + function get_block_title() + { + return $this->get('block_title'); + } + + function get_content() + { + return $this->get('content'); + } + + protected function __construct() + { + parent::__construct('1.1', 'Laurent Opprecht', array('block_title' => 'text', 'content' => 'wysiwyg')); + } + +} \ No newline at end of file diff --git a/plugin/static/plugin.php b/plugin/static/plugin.php new file mode 100644 index 0000000000..0f35efd14f --- /dev/null +++ b/plugin/static/plugin.php @@ -0,0 +1,12 @@ +get_info(); \ No newline at end of file diff --git a/plugin/static/readme.txt b/plugin/static/readme.txt new file mode 100644 index 0000000000..74b109273a --- /dev/null +++ b/plugin/static/readme.txt @@ -0,0 +1 @@ +Display static content. \ No newline at end of file diff --git a/plugin/static/resources/static.css b/plugin/static/resources/static.css new file mode 100644 index 0000000000..ac3a72b998 --- /dev/null +++ b/plugin/static/resources/static.css @@ -0,0 +1,4 @@ + +.well.sidebar-nav.rss +{ +}