Alex Aragon 9 years ago
commit 53517392f2
  1. 16
      README.md
  2. 3
      app/AppKernel.php
  3. 12
      app/Migrations/Schema/V110/Version110.php
  4. 2
      app/Migrations/Schema/V111/Version111.php
  5. 68
      app/Resources/public/css/base.css
  6. 2
      app/config/config.yml
  7. 5
      app/config/routing.yml
  8. 1
      app/config/sonata/sonata_admin.yml
  9. 1
      app/config/sonata/sonata_page.yml
  10. 10
      composer.json
  11. 11
      main/badge/issued.php
  12. 2
      main/gradebook/lib/be/category.class.php
  13. 1
      main/inc/lib/api.lib.php
  14. 180
      main/inc/lib/formvalidator/Element/DatePicker.php
  15. 6
      main/inc/lib/social.lib.php
  16. 39
      main/inc/lib/template.lib.php
  17. 5
      main/newscorm/final_item_template/template.html
  18. 191
      main/newscorm/learnpath.class.php
  19. 10
      main/newscorm/lp_add_item.php
  20. 29
      main/newscorm/lp_controller.php
  21. 5
      main/newscorm/lp_edit_item.php
  22. 128
      main/newscorm/lp_final_item.php
  23. 2
      main/newscorm/lp_view.php
  24. 3
      main/newscorm/resourcelinker.inc.php
  25. 1
      main/template/default/layout/menu.tpl
  26. 9
      main/template/default/skill/issued.tpl
  27. 2
      plugin/ticket/src/myticket.php
  28. 7
      plugin/ticket/src/ticket.class.php
  29. 5
      plugin/ticket/src/ticket_details.php
  30. 51
      src/Chamilo/ContactBundle/Admin/CategoryAdmin.php
  31. 15
      src/Chamilo/ContactBundle/ChamiloContactBundle.php
  32. 93
      src/Chamilo/ContactBundle/Controller/ContactController.php
  33. 26
      src/Chamilo/ContactBundle/DependencyInjection/ChamiloContactExtension.php
  34. 81
      src/Chamilo/ContactBundle/Entity/Category.php
  35. 13
      src/Chamilo/ContactBundle/Entity/Contact.php
  36. 78
      src/Chamilo/ContactBundle/Form/Type/ContactType.php
  37. 9
      src/Chamilo/ContactBundle/Resources/config/admin.yml
  38. 3
      src/Chamilo/ContactBundle/Resources/config/routing.yml
  39. 11
      src/Chamilo/ContactBundle/Resources/views/contact.html.twig
  40. 12
      src/Chamilo/ContactBundle/Resources/views/index.html.twig
  41. 37
      src/Chamilo/CoreBundle/Resources/views/layout_one_col.html.twig
  42. 48
      src/Chamilo/CoreBundle/Resources/views/layout_two_col.html.twig
  43. 20
      src/Chamilo/ThemeBundle/Resources/views/Layout/base-layout.html.twig
  44. 20
      src/Chamilo/ThemeBundle/Resources/views/Layout/footer.js.twig
  45. 18
      src/Chamilo/ThemeBundle/Resources/views/Layout/header.js.twig
  46. 2
      tests/scripts/fix_migrations_1.9.x_1.10.0.php

@ -111,6 +111,17 @@ Typically:
DELETE FROM access_url_rel_course WHERE access_url_id NOT IN (SELECT id FROM access_url);
</pre>
### Upgrading from non-Git Chamilo 1.10 ###
In the *very unlikely* case of upgrading a "normal" Chamilo 1.10 installation (done with the downloadable zip package) to a Git-based installation, make sure you delete the contents of a few folders first. These folders are re-generated later by the ```composer update``` command. This is likely to increase the downtime of your Chamilo portal of a few additional minutes (plan for 10 minutes on a reasonnable internet connection).
```
rm composer.lock
rm -rf web/*
rm -rf vendor/*
```
# For developers and testers only
This section is for developers only (or for people who have a good reason to use
@ -151,6 +162,11 @@ version and type the following (assuming you want to execute Version201505271207
php bin/doctrine.php migrations:execute 20150527120703 --up --configuration=app/config/migrations.yml
```
You can also print the differences between your database and what it should be by issuing the following command from the Chamilo base folder:
```
php bin/doctrine.php orm:schema:update --dump-sql
```
## Contributing
If you want to submit new features or patches to Chamilo, please follow the

@ -98,10 +98,11 @@ class AppKernel extends Kernel
new Chamilo\CoreBundle\ChamiloCoreBundle(),
new Chamilo\CourseBundle\ChamiloCourseBundle(),
// new Chamilo\SettingsBundle\ChamiloSettingsBundle(),
new Chamilo\ThemeBundle\ChamiloThemeBundle(),
new Chamilo\ThemeBundle\ChamiloThemeBundle(),
//new Chamilo\NotificationBundle\ChamiloNotificationBundle(),
new Chamilo\AdminBundle\ChamiloAdminBundle(),
new Chamilo\TimelineBundle\ChamiloTimelineBundle(),
new \Chamilo\ContactBundle\ChamiloContactBundle(),
// Based in Sonata
new Chamilo\ClassificationBundle\ChamiloClassificationBundle(),

@ -76,8 +76,16 @@ class Version110 extends AbstractMigrationChamilo
);
}
$this->addSql("ALTER TABLE session ADD COLUMN duration int");
$this->addSql("ALTER TABLE session_rel_user ADD COLUMN duration int");
$sessionTable = $schema->getTable('session');
if (!$sessionTable->hasColumn('duration')) {
$this->addSql("ALTER TABLE session ADD COLUMN duration int");
}
$sessionRelUser = $schema->getTable('session_rel_user');
if (!$sessionRelUser->hasColumn('duration')) {
$this->addSql("ALTER TABLE session_rel_user ADD COLUMN duration int");
}
$this->addSql("ALTER TABLE skill ADD COLUMN criteria text");
$this->addSql("ALTER TABLE gradebook_category ADD COLUMN generate_certificates TINYINT NOT NULL DEFAULT 0");
$this->addSql("ALTER TABLE track_e_access ADD COLUMN c_id int NOT NULL");

@ -57,6 +57,8 @@ class Version111 extends AbstractMigrationChamilo
$this->addSql("ALTER TABLE faq_category_translation ADD CONSTRAINT FK_5493B0FC2C2AC5D3 FOREIGN KEY (translatable_id) REFERENCES faq_category (id) ON DELETE CASCADE;");
$this->addSql("ALTER TABLE faq_question ADD CONSTRAINT FK_4A55B05912469DE2 FOREIGN KEY (category_id) REFERENCES faq_category (id);");
$this->addSql("CREATE TABLE contact_category (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;");
$table = $schema->getTable('session_rel_user');
if (!$table->hasColumn('duration')) {
$this->addSql("ALTER TABLE session_rel_user ADD duration INT DEFAULT NULL");

@ -5244,6 +5244,8 @@ div#chat-remote-video video {
.ui-tabs .ui-widget-content a.btn-success{
color: #fff;
}
.ui-priority-secondary,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary{
@ -5281,6 +5283,7 @@ div#chat-remote-video video {
.ui-dialog .ui-dialog-buttonpane{
border-top: 1px solid #DDD;
}
.ui-button.ui-widget.ui-state-default {
background-color:#f5f5f5;
background-image:-moz-linear-gradient(top,#fff,#e6e6e6);
@ -5306,6 +5309,9 @@ div#chat-remote-video video {
font-weight:normal;
color:#333333;
}
.select2-container .select2-selection--single{
height: 32px !important;
border-color: #CCCCCC !important;
@ -5362,6 +5368,58 @@ div#chat-remote-video video {
.filler-report .filler-report-data-init{
width: 60%;
}
.items-course{
padding: 10px;
border: 1px solid #e6e6e6;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
min-height: 320px;
margin-bottom: 10px;
}
.items-course .items-course-info .title{
font-size: 14px;
min-height: 32px;
line-height: 1.3;
}
.items-course .items-course-info .teachers{
font-size: 12px;
color: #666666;
}
.items-course .items-course-info .ranking{
font-size: 10px;
color: #666666;
}
.items-course .items-course-info .user-register{
font-size: 11px;
background-color: #FCF8E3;
border: 1px solid #FAEBCC;
text-align: center;
display: inline-block;
width: 100%;
margin-left: 5px;
margin-bottom: 3px;
padding-top: 3px;
padding-bottom: 5px;
border-radius: 5px;
}
.items-course .items-course-info .toolbar{
text-align: center;
padding-top: 5px;
}
.items-course .items-course-info .vote_label_info{
margin-bottom: 5px;
}
.hot-course-head{
padding-top: 10px;
padding-bottom: 10px;
}
.hot-course-head .hot-course-title{
padding-bottom: 10px;
border-bottom: 1px solid #E5E5E5;
font-size: 21px;
}
.create-groups .separate td{
padding-left: 15px;
padding-right: 15px;
@ -5943,6 +6001,16 @@ a.sessionView {
color: black !important;
}
.skill-badge-img{
width: 150px;
overflow: hidden;
}
.text-light{
color: #00CCFF;
}
#dropzone {
position: relative;
overflow: hidden;

@ -86,7 +86,7 @@ twig:
form:
resources:
- 'bootstrap_3_layout.html.twig'
- 'bootstrap_3_horizontal_layout.html.twig'
- 'SonataFormatterBundle:Form:formatter.html.twig'
- 'SonataMediaBundle:Form:media_widgets.html.twig'
- 'SonataCoreBundle:Form:datepicker.html.twig'

@ -51,6 +51,11 @@ sonata_user_admin_security_logout:
# resource: "@ChamiloCourseBundle/Resources/config/routing.yml"
# prefix: /
chamilo_contact:
resource: "@ChamiloContactBundle/Resources/config/routing.yml"
prefix: /contact
#_courses:
# resource: routing_courses.yml
#

@ -74,6 +74,7 @@ sonata_admin:
items:
- sonata.page.admin.page
- sonata.page.admin.site
- sonata.admin.contact_category
sonata.admin.group.faq:
label: FAQ

@ -44,6 +44,7 @@ sonata_page:
- ^/faq
- ^/courses/(.*)
- ^/front/editor
- ^/contact(.*) # sonata admin
ignore_route_patterns:
- (.*)administration(.*) # ignore admin route, ie route containing 'admin' # sonata admin

@ -76,22 +76,22 @@
"sonata-project/seo-bundle": "~2.0",
"sonata-project/doctrine-extensions": "~1@dev",
"sonata-project/intl-bundle": "~2.2@dev",
"sonata-project/admin-bundle": "~2.4@dev",
"sonata-project/doctrine-orm-admin-bundle": "~2.4@dev",
"sonata-project/admin-bundle": "dev-master as 2.4",
"sonata-project/doctrine-orm-admin-bundle": "dev-master as 2.4",
"sonata-project/notification-bundle": "~2.2@dev",
"sonata-project/block-bundle": "~2.3@dev",
"sonata-project/media-bundle": "~2.4@dev",
"sonata-project/user-bundle": "~2.2@dev",
"sonata-project/cache-bundle": "~2.1@dev",
"sonata-project/cache": "~1.0@dev",
"sonata-project/page-bundle": "~2.4@dev",
"sonata-project/page-bundle": "dev-master",
"sonata-project/core-bundle": "2.3.x-dev",
"sonata-project/formatter-bundle": "~2.4@dev",
"sonata-project/news-bundle": "~2.3@dev",
"sonata-project/datagrid-bundle": "~2.2@dev",
"sonata-project/exporter": "~1.3@dev",
"sonata-project/timeline-bundle": "~2.3@dev",
"sonata-project/classification-bundle": "~2.2@dev",
"sonata-project/classification-bundle": "~2.3@dev",
"sonata-project/comment-bundle": "~2.2@dev",
"sonata-project/sonata-composer": "dev-master",

@ -59,6 +59,17 @@ $skillInfo = [
'courses' => []
];
// Open Graph Markup
$htmlHeadXtra[] = "
<meta property='og:type' content='article' />
<meta property='og:title' content='".sprintf(get_lang('IHaveObtainedSkillXOnY'), $skillInfo['name'], api_get_setting('siteName'))."' />
<meta property='og:url' content='".api_get_path(WEB_PATH)."badge/".$skillId."/user/".$userId."' />
<meta property='og:description' content='".$skillInfo['description']."' />
<meta property='og:image' content='".$skillInfo['badge_image']."' />
";
$badgeAssertions = [];
foreach ($userSkills as $userSkill) {

@ -1952,7 +1952,7 @@ class Category implements GradebookItem
$userHasSkills = false;
if ($skillToolEnabled) {
if (!$category->getGenerateCertificates()) {
if ($category->getGenerateCertificates()) {
$skill = new Skill();
$skill->add_skill_to_user(
$user_id,

@ -96,6 +96,7 @@ define('SURVEY_VISIBLE_PUBLIC', 2);
// CONSTANTS defining all tools, using the english version
/* When you add a new tool you must add it into function api_get_tools_lists() too */
define('TOOL_DOCUMENT', 'document');
define('TOOL_LP_FINAL_ITEM', 'final_item');
define('TOOL_THUMBNAIL', 'thumbnail');
define('TOOL_HOTPOTATOES', 'hotpotatoes');
define('TOOL_CALENDAR_EVENT', 'calendar_event');

@ -1,180 +0,0 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Form element to select a date.
*
* Class DatePicker
*/
class DatePicker extends HTML_QuickForm_text
{
/**
* @param string $elementName
* @param string $elementLabel
* @param array $attributes
*/
public function __construct($elementName = null, $elementLabel = null, $attributes = null)
{
if (!isset($attributes['id'])) {
$attributes['id'] = $elementName;
}
$attributes['class'] = 'form-control';
parent::__construct($elementName, $elementLabel, $attributes);
$this->_appendName = true;
$this->_type = 'date_picker';
}
/**
* HTML code to display this datepicker
*
* @return string
*/
public function toHtml()
{
if ($this->_flagFrozen) {
return $this->getFrozenHtml();
}
$id = $this->getAttribute('id');
$value = $this->getValue();
$label = $this->getLabel();
if (!empty($value)) {
$value = api_format_date($value, DATE_TIME_FORMAT_LONG_24H);
}
return $this->getElementJS() . '
<div class="input-group">
<span class="input-group-addon">
<input ' . $this->_getAttrString($this->_attributes) . '>
</span>
<input class="form-control" type="text" readonly id="' . $id . '_alt" value="' . $value . '">
</div>
';
}
/**
* @param string $value
*/
public function setValue($value)
{
$value = substr($value, 0, 16);
$this->updateAttributes(
array(
'value' => $value
)
);
}
/**
* Get the necessary javascript for this datepicker
* @return string
*/
private function getElementJS()
{
$js = null;
$id = $this->getAttribute('id');
$js .= "<script>
$(function() {
$('#$id').hide().datepicker({
defaultDate: '" . $this->getValue() . "',
dateFormat: 'yy-mm-dd',
altField: '#{$id}_alt',
altFormat: \"" . get_lang('DateFormatLongNoDayJS') . "\",
showOn: 'both',
buttonImage: '" . Display::return_icon('attendance.png', null, [], ICON_SIZE_TINY, true, true) . "',
buttonImageOnly: true,
buttonText: '" . get_lang('SelectDate') . "',
changeMonth: true,
changeYear: true,
yearRange: 'c-60y:c+5y'
});
});
</script>";
return $js;
}
/**
* @param string $layout
*
* @return string
*/
public function getTemplate($layout)
{
$size = $this->getColumnsSize();
$id = $this->getAttribute('id');
$value = $this->getValue();
if (empty($size)) {
$sizeTemp = $this->getInputSize();
if (empty($size)) {
$sizeTemp = 8;
}
$size = array(2, $sizeTemp, 2);
} else {
if (is_array($size)) {
if (count($size) != 3) {
$sizeTemp = $this->getInputSize();
if (empty($size)) {
$sizeTemp = 8;
}
$size = array(2, $sizeTemp, 2);
}
// else just keep the $size array as received
} else {
$size = array(2, intval($size), 2);
}
}
if (!empty($value)) {
$value = api_format_date($value, DATE_FORMAT_LONG_NO_DAY);
}
switch ($layout) {
case FormValidator::LAYOUT_INLINE:
return '
<div class="form-group {error_class}">
<label {label-for} >
<!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
{label}
</label>
{element}
</div>';
break;
case FormValidator::LAYOUT_HORIZONTAL:
return '
<div class="form-group {error_class}">
<label {label-for} class="col-sm-'.$size[0].' control-label" >
<!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
{label}
</label>
<div class="col-sm-'.$size[1].'">
{icon}
{element}
<!-- BEGIN label_2 -->
<p class="help-block">{label_2}</p>
<!-- END label_2 -->
<!-- BEGIN error -->
<span class="help-inline">{error}</span>
<!-- END error -->
</div>
<div class="col-sm-'.$size[2].'">
<!-- BEGIN label_3 -->
{label_3}
<!-- END label_3 -->
</div>
</div>';
break;
case FormValidator::LAYOUT_BOX_NO_LABEL:
return '{element}';
break;
}
}
}

@ -976,7 +976,8 @@ class SocialManager extends UserManager
}
if ($show_delete_account_button) {
$html .= '<div class="sidebar-nav"><ul><li>';
$html .= '<div class="panel panel-default"><div class="panel-body">';
$html .= '<ul class="nav nav-pills nav-stacked"><li>';
$url = api_get_path(WEB_CODE_PATH).'auth/unsubscribe_account.php';
$html .= Display::url(
Display::return_icon(
@ -987,7 +988,8 @@ class SocialManager extends UserManager
).get_lang('Unsubscribe'),
$url
);
$html .= '</li></ul></div>';
$html .= '</li></ul>';
$html .= '</div></div>';
}
$html .= '';

@ -939,6 +939,11 @@ class Template
$this->assign('message_link', $message_link);
$this->assign('message_url', $message_url);
//Certificate Link
$certificatesUrl = api_get_path(WEB_CODE_PATH).'gradebook/my_certificates.php';
$certificateLink = Display::url(get_lang('MyCertificates'), $certificatesUrl);
$this->assign('certificate_link', $certificateLink);
$institution = api_get_setting('Institution');
$portal_name = empty($institution) ? api_get_setting('siteName') : $institution;
@ -999,12 +1004,6 @@ class Template
$metaTitle = api_get_setting('meta_title');
if (!empty($metaTitle)) {
$socialMeta .= '<meta name="twitter:card" content="summary" />' . "\n";
$socialMeta .= '<meta property="og:title" content="' . $metaTitle . '" />' . "\n";
$socialMeta .= '<meta property="og:url" content="' . api_get_path(WEB_PATH) . '" />' . "\n";
$metaDescription = api_get_setting('meta_description');
if (!empty($metaDescription)) {
$socialMeta .= '<meta property="og:description" content="' . $metaDescription . '" />' . "\n";
}
$metaSite = api_get_setting('meta_twitter_site');
if (!empty($metaSite)) {
$socialMeta .= '<meta name="twitter:site" content="' . $metaSite . '" />' . "\n";
@ -1013,11 +1012,29 @@ class Template
$socialMeta .= '<meta name="twitter:creator" content="' . $metaCreator . '" />' . "\n";
}
}
$metaImage = api_get_setting('meta_image_path');
if (!empty($metaImage)) {
if (is_file(api_get_path(SYS_PATH) . $metaImage)) {
$path = api_get_path(WEB_PATH) . $metaImage;
$socialMeta .= '<meta property="og:image" content="' . $path . '" />' . "\n";
// The user badge page emits its own meta tags, so if this is
// enabled, ignore the global ones
$userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
$skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
if (!$userId && !$skillId) {
// no combination of user and skill ID has been defined,
// so print the normal OpenGraph meta tags
$socialMeta .= '<meta property="og:title" content="' . $metaTitle . '" />' . "\n";
$socialMeta .= '<meta property="og:url" content="' . api_get_path(WEB_PATH) . '" />' . "\n";
$metaDescription = api_get_setting('meta_description');
if (!empty($metaDescription)) {
$socialMeta .= '<meta property="og:description" content="' . $metaDescription . '" />' . "\n";
}
$metaImage = api_get_setting('meta_image_path');
if (!empty($metaImage)) {
if (is_file(api_get_path(SYS_PATH) . $metaImage)) {
$path = api_get_path(WEB_PATH) . $metaImage;
$socialMeta .= '<meta property="og:image" content="' . $path . '" />' . "\n";
}
}
}
}

@ -0,0 +1,5 @@
<div>
Congratulations! You have finished this learning path
</div>
((certificate)) <br />
((skill))

@ -1947,7 +1947,7 @@ class learnpath
error_log('New LP - In learnpath::get_last()', 0);
}
//This is just in case the lesson doesn't cointain a valid scheme, just to avoid "Notices"
if ($this->index > 0) {
if (count($this->ordered_items) > 0) {
$this->index = count($this->ordered_items) - 1;
return $this->ordered_items[$this->index];
}
@ -3401,7 +3401,7 @@ class learnpath
}
// Fixed issue BT#1272 - If the item type is a Chamilo Item (quiz, link, etc), then change the lp type to thread it as a normal Chamilo LP not a SCO.
if (in_array($lp_item_type, array('quiz', 'document', 'link', 'forum', 'thread', 'student_publication'))) {
if (in_array($lp_item_type, array('quiz', 'document', 'final_item', 'link', 'forum', 'thread', 'student_publication'))) {
$lp_type = 1;
}
@ -5605,6 +5605,11 @@ class learnpath
);
}
// Detect if type is FINAL_ITEM to set path_id to SESSION
if ($arrLP[$i]['item_type'] == TOOL_LP_FINAL_ITEM) {
$_SESSION['pathItem'] = $arrLP[$i]['path'];
}
if (($i % 2) == 0) {
$oddClass = 'row_odd';
} else {
@ -5620,7 +5625,11 @@ class learnpath
if (file_exists('../img/lp_' . $icon_name . '.gif')) {
$icon = Display::return_icon('lp_' . $icon_name . '.gif');
} else {
$icon = Display::return_icon('folder_document.gif');
if ($arrLP[$i]['item_type'] === TOOL_LP_FINAL_ITEM) {
$icon = Display::return_icon('certificate.png');
} else {
$icon = Display::return_icon('folder_document.gif');
}
}
}
@ -5656,13 +5665,15 @@ class learnpath
if ($is_allowed_to_edit) {
if (!$update_audio || $update_audio <> 'true') {
$move_icon .= '<a class="moved" href="#">';
$move_icon .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
$move_icon .= '</a>';
if ($arrLP[$i]['item_type'] !== TOOL_LP_FINAL_ITEM) {
$move_icon .= '<a class="moved" href="#">';
$move_icon .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
$move_icon .= '</a>';
}
}
// No edit for this item types
if (!in_array($arrLP[$i]['item_type'], array('sco', 'asset'))) {
if (!in_array($arrLP[$i]['item_type'], array('sco', 'asset', 'final_item'))) {
if (!in_array($arrLP[$i]['item_type'], array('dokeos_chapter', 'dokeos_module'))) {
$edit_icon .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=edit_item&view=build&id=' . $arrLP[$i]['id'] . '&lp_id=' . $this->lp_id . '&path_item=' . $arrLP[$i]['path'] . '" class="btn btn-default">';
$edit_icon .= Display::return_icon('edit.png', get_lang('LearnpathEditModule'), array(), ICON_SIZE_TINY);
@ -6215,7 +6226,6 @@ class learnpath
if (!is_dir($filepath)) {
$filepath = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document/';
$dir = '/';
}
$table_doc = Database :: get_course_table(TABLE_DOCUMENT);
@ -6337,7 +6347,6 @@ class learnpath
WHERE c_id = ".$course_id." AND id = " . intval($item_id);
$res = Database::query($sql);
$row = Database::fetch_array($res);
switch ($row['item_type']) {
case 'dokeos_chapter' :
case 'dir' :
@ -6361,7 +6370,7 @@ class learnpath
doc.c_id = $course_id AND
lp.id = " . intval($item_id);
$res_step = Database::query($sql);
$row_step = Database :: fetch_array($res_step);
$row_step = Database :: fetch_array($res_step, 'ASSOC');
$return .= $this->display_manipulate($item_id, $row['item_type']);
$return .= $this->display_document_form('edit', $item_id, $row_step);
break;
@ -6380,6 +6389,22 @@ class learnpath
$return .= $this->display_manipulate($item_id, $row['item_type']);
$return .= $this->display_link_form('edit', $item_id, $row);
break;
case TOOL_LP_FINAL_ITEM :
$_SESSION['finalItem'] = true;
$tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
$sql = "SELECT lp.*, doc.path as dir
FROM " . $tbl_lp_item . " as lp
LEFT JOIN " . $tbl_doc . " as doc
ON doc.id = lp.path
WHERE
lp.c_id = $course_id AND
doc.c_id = $course_id AND
lp.id = " . intval($item_id);
$res_step = Database::query($sql);
$row_step = Database :: fetch_array($res_step, 'ASSOC');
$return .= $this->display_manipulate($item_id, $row['item_type']);
$return .= $this->display_document_form('edit', $item_id, $row_step);
break;
case 'dokeos_module' :
if (isset ($_GET['view']) && $_GET['view'] == 'build') {
$return .= $this->display_manipulate($item_id, $row['item_type']);
@ -6432,26 +6457,30 @@ class learnpath
// Get all the links.
$links = $this->get_links();
// Get al the student publications.
// Get all the student publications.
$works = $this->get_student_publications();
// Get al the forums.
// Get all the forums.
$forums = $this->get_forums(null, $course_code);
// Get the final item form (see BT#11048) .
$finish = $this->getFinalItemForm();
$headers = array(
Display::return_icon('folder_document.png', get_lang('Documents'), array(), ICON_SIZE_BIG),
Display::return_icon('quiz.png', get_lang('Quiz'), array(), ICON_SIZE_BIG),
Display::return_icon('links.png', get_lang('Links'), array(), ICON_SIZE_BIG),
Display::return_icon('works.png', get_lang('Works'), array(), ICON_SIZE_BIG),
Display::return_icon('forum.png', get_lang('Forums'), array(), ICON_SIZE_BIG),
Display::return_icon('add_learnpath_section.png', get_lang('NewChapter'), array(), ICON_SIZE_BIG)
Display::return_icon('add_learnpath_section.png', get_lang('NewChapter'), array(), ICON_SIZE_BIG),
Display::return_icon('certificate.png', get_lang('Certificate'), [], ICON_SIZE_BIG),
);
echo Display::display_normal_message(get_lang('ClickOnTheLearnerViewToSeeYourLearningPath'));
$chapter = $_SESSION['oLP']->display_item_form('chapter', get_lang('EnterDataNewChapter'), 'add_item');
echo Display::tabs(
$headers,
array($documents, $exercises, $links, $works, $forums, $chapter), 'resource_tab'
array($documents, $exercises, $links, $works, $forums, $chapter, $finish), 'resource_tab'
);
return true;
@ -7748,10 +7777,10 @@ class learnpath
//POSITION
for ($i = 0; $i < count($arrLP); $i++) {
if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
if (isset($extra_info['previous_item_id']) && $extra_info['previous_item_id'] == $arrLP[$i]['id'])
if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id || $arrLP[$i]['item_type'] == TOOL_LP_FINAL_ITEM) {
if (isset($extra_info['previous_item_id']) && $extra_info['previous_item_id'] == $arrLP[$i]['id'] || $action == 'add') {
$s_selected_position = $arrLP[$i]['id'];
elseif ($action == 'add') $s_selected_position = $arrLP[$i]['id'];
}
$arrHide[$arrLP[$i]['id']]['value'] = get_lang('After') . ' "' . $arrLP[$i]['title'] . '"';
}
}
@ -7763,6 +7792,7 @@ class learnpath
$padding = isset($value['padding']) ? $value['padding']: 20;
$position->addOption($value['value'], $key, 'style="padding-left:' . $padding . 'px;"');
}
$position->setSelected($s_selected_position);
if (is_array($arrLP)) {
@ -7782,7 +7812,7 @@ class learnpath
$arrHide = array();
for ($i = 0; $i < count($arrLP); $i++) {
if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter') {
if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter' && $arrLP[$i]['item_type'] !== TOOL_LP_FINAL_ITEM) {
if (isset($extra_info['previous_item_id']) && $extra_info['previous_item_id'] == $arrLP[$i]['id'])
$s_selected_position = $arrLP[$i]['id'];
elseif ($action == 'add') $s_selected_position = $arrLP[$i]['id'];
@ -7795,7 +7825,7 @@ class learnpath
if (!$no_display_add) {
$item_type = isset($extra_info['item_type']) ? $extra_info['item_type'] : null;
$edit = isset($_GET['edit']) ? $_GET['edit'] : null;
if (($extra_info == 'new' || $item_type == TOOL_DOCUMENT || $edit == 'true')) {
if (($extra_info == 'new' || $item_type == TOOL_DOCUMENT || $item_type == TOOL_LP_FINAL_ITEM || $edit == 'true')) {
if (isset ($_POST['content']))
$content = stripslashes($_POST['content']);
elseif (is_array($extra_info)) {
@ -8343,7 +8373,7 @@ class learnpath
// Commented the message cause should not show it.
//$lang = get_lang('TitleManipulateModule');
break;
case TOOL_LP_FINAL_ITEM :
case TOOL_DOCUMENT :
// Commented the message cause should not show it.
//$lang = get_lang('TitleManipulateDocument');
@ -8417,7 +8447,7 @@ class learnpath
$return .= get_lang('File').': '.$document_data['absolute_path_from_document'];
}
if ($item_type == TOOL_DOCUMENT ) {
if ($item_type == TOOL_DOCUMENT || $item_type == TOOL_LP_FINAL_ITEM) {
$document_data = DocumentManager::get_document_data_by_id($row['path'], $course_code);
$return .= get_lang('File').': '.$document_data['absolute_path_from_document'];
}
@ -10951,6 +10981,125 @@ EOD;
return $forumId;
}
/**
* Check and obtain the lp final item if exist
*
* @return array lp items
*/
private function getFinalItem()
{
if (empty($this->items)) {
return null;
}
foreach ($this->items as $item) {
if ($item->type !== 'final_item') {
continue;
}
return $item;
}
}
/**
* Get the LP Final Item Template
*
* @return html
*/
private function getFinalItemTemplate()
{
return file_get_contents(api_get_path(SYS_CODE_PATH) . 'newscorm/final_item_template/template.html');
}
/**
* Get the LP Final Item Url
*
* @return String
*/
private function getSavedFinalItem()
{
$finalItem = $this->getFinalItem();
$doc = DocumentManager::get_document_data_by_id($finalItem->path, $this->cc);
return file_get_contents($doc['absolute_path']);
}
/**
* Get the LP Final Item form
*
* @return html
*/
public function getFinalItemForm()
{
$finalItem = $this->getFinalItem();
$title = '';
$content = '';
if ($finalItem) {
$title = $finalItem->title;
$buttonText = get_lang('Save');
$content = $this->getSavedFinalItem();
} else {
$buttonText = get_lang('LPCreateDocument');
$content = $this->getFinalItemTemplate();
}
$courseInfo = api_get_course_info();
$result = $this->generate_lp_folder($courseInfo);
$relative_path = api_substr($result['dir'], 1, strlen($result['dir']));
$relative_prefix = '../../';
$editorConfig = [
'ToolbarSet' => 'LearningPathDocuments',
'Width' => '100%',
'Height' => '500',
'FullPage' => true,
'CreateDocumentDir' => $relative_prefix,
'CreateDocumentWebDir' => api_get_path(WEB_COURSE_PATH) . api_get_course_path() . '/document/',
'BaseHref' => api_get_path(WEB_COURSE_PATH) . api_get_course_path() . '/document/' . $relative_path
];
$url = api_get_self() . '?' . api_get_cidreq() . '&' . http_build_query([
'type' => 'document',
'lp_id' => $this->lp_id
]);
$form = new FormValidator('final_item', 'POST', $url);
$form->addText('title', get_lang('Title'));
$form->addButtonSave($buttonText);
$form->addHtml('<div class="alert alert-info">Variables :</br></br> <b>((certificate))</b> </br> <b>((skill))</b></div>');
$renderer = $form->defaultRenderer();
$renderer->setElementTemplate('<div class="editor-lp">&nbsp;{label}{element}</div>', 'content_lp');
$form->addHtmlEditor('content_lp', null, null, true, $editorConfig, true);
$form->addHidden('action', 'add_final_item');
$form->addHidden('path', isset($_SESSION['pathItem']) ? $_SESSION['pathItem'] : '');
$form->addHidden('previous', $this->get_last());
$form->setDefaults(['title' => $title, 'content_lp' => $content]);
if ($form->validate()) {
$values = $form->exportValues();
$lastItemId = $this->get_last();
if (!$finalItem) {
$documentId = $this->create_document($this->course_info, $values['content_lp'], $values['title']);
$this->add_item(
0,
$lastItemId,
'final_item',
$documentId,
$values['title'],
''
);
} else {
$this->edit_document($this->course_info);
}
}
return $form->returnForm();
}
}
if (!function_exists('trim_value')) {

@ -288,7 +288,7 @@ if (isset($new_item_id) && is_numeric($new_item_id)) {
case 'module':
echo $learnPath->display_item_form($type, get_lang('EnterDataNewModule'));
break;
case 'document':
case TOOL_DOCUMENT:
if (isset($_GET['file']) && is_numeric($_GET['file'])) {
echo $learnPath->display_document_form('add', 0, $_GET['file']);
} else {
@ -298,20 +298,20 @@ if (isset($new_item_id) && is_numeric($new_item_id)) {
case 'hotpotatoes':
echo $learnPath->display_hotpotatoes_form('add', 0, $_GET['file']);
break;
case 'quiz':
case TOOL_QUIZ:
echo Display::display_warning_message(get_lang('ExerciseCantBeEditedAfterAddingToTheLP'));
echo $learnPath->display_quiz_form('add', 0, $_GET['file']);
break;
case 'forum':
case TOOL_FORUM:
echo $learnPath->display_forum_form('add', 0, $_GET['forum_id']);
break;
case 'thread':
echo $learnPath->display_thread_form('add', 0, $_GET['thread_id']);
break;
case 'link':
case TOOL_LINK:
echo $learnPath->display_link_form('add', 0, $_GET['file']);
break;
case 'student_publication':
case TOOL_STUDENTPUBLICATION:
$extra = isset($_GET['file']) ? $_GET['file'] : null;
echo $learnPath->display_student_publication_form('add', 0, $extra);
break;

@ -364,8 +364,11 @@ if (isset($_POST['title'])) {
}
}
$redirectTo = null;
switch ($action) {
case 'add_item':
if (!$is_allowed_to_edit) {
api_not_allowed(true);
}
@ -1400,6 +1403,28 @@ switch ($action) {
'lp_id' => $_SESSION['oLP']->lp_id
]));
break;
case 'add_final_item':
if (!$lp_found) {
Display::addFlash(
Display::return_message(get_lang('NoLPFound'), 'error')
);
break;
}
$_SESSION['refresh'] = 1;
if (!isset($_POST['submit']) || empty($post_title)) {
break;
}
$_SESSION['oLP']->getFinalItemForm();
$redirectTo = api_get_self() . '?' . http_build_query([
'action' => 'add_item',
'type' => 'step',
'lp_id' => intval($_SESSION['oLP']->lp_id)
]);
break;
default:
if ($debug > 0) error_log('New LP - default action triggered', 0);
require 'lp_list.php';
@ -1410,3 +1435,7 @@ if (!empty($_SESSION['oLP'])) {
$_SESSION['lpobject'] = serialize($_SESSION['oLP']);
if ($debug > 0) error_log('New LP - lpobject is serialized in session', 0);
}
if (!empty($redirectTo)) {
header("Location: $redirectTo");
}

@ -161,7 +161,6 @@ echo $_SESSION['oLP']->build_action_menu();
echo '<div class="row">';
echo '<div class="col-md-3">';
$path_item = isset($_GET['path_item']) ? $_GET['path_item'] : 0;
$path_item = Database::escape_string($path_item);
$tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
@ -191,6 +190,10 @@ if (isset($is_success) && $is_success === true) {
echo $_SESSION['oLP']->display_item($_GET['id'], $msg);
} else {
echo $_SESSION['oLP']->display_edit_item($_GET['id']);
if (isset($_SESSION['finalItem'])) {
echo '<script>$("#frmModel").remove()</script>';
}
unset($_SESSION['finalItem']);
}
echo '</div>';

@ -0,0 +1,128 @@
<?php
$_in_course = true;
require_once '../inc/global.inc.php';
$current_course_tool = TOOL_GRADEBOOK;
api_protect_course_script(true);
$courseCode = api_get_course_id();
$userId = api_get_user_id();
$sessionId = api_get_session_id();
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$lpId = isset($_GET['lp_id']) ? intval($_GET['lp_id']) : 0;
if (!$id && !$lpId) {
Display::display_warning_message(get_lang('FileNotFound'));
exit;
}
$catLoad = Category::load(null, null, $courseCode, null, null, $sessionId, 'ORDER By id');
if (!$catLoad) {
Display::display_warning_message(get_lang('FileNotFound'));
exit;
}
$categoryId = $catLoad[0]->get_id();
$link = LinkFactory::load(null, null, $lpId, null, $courseCode, $categoryId);
$downloadCertificateLink = '';
$viewCertificateLink = '';
$badgeLink = '';
if ($link) {
$cat = new Category();
$catCourseCode = CourseManager::get_course_by_category($categoryId);
$show_message = $cat->show_message_resource_delete($catCourseCode);
if ($show_message == '') {
if (!api_is_allowed_to_edit() && !api_is_excluded_user_type()) {
$certificate = Category::register_user_certificate(
$categoryId,
$userId
);
if (isset($certificate['pdf_url']) && isset($certificate['certificate_link']) && isset($certificate['badge_link'])) {
$downloadCertificateLink .= Display::url(Display::returnFontAwesomeIcon('file-pdf-o') .
get_lang('DownloadCertificatePdf'),
$certificate['pdf_url'],
['class' => 'btn btn-default']
);
$viewCertificateLink .= $certificate['certificate_link'];
$downloadCertificateLink = "
<div class='panel panel-default'>
<div class='panel-body'>
<h3 class='text-center'>".get_lang('NowDownloadYourCertificateClickHere')."</h3>
<div class='text-center'>$downloadCertificateLink $viewCertificateLink</div>
</div>
</div>
";
$skillRelUser = new SkillRelUser();
$courseId = api_get_course_int_id();
$userSkills = $skillRelUser->get_user_skills($userId, $courseId, $sessionId);
$skillList = '';
if ($userSkills) {
$skill = new Skill();
foreach ($userSkills as $userSkill) {
$oneSkill = $skill->get($userSkill['skill_id']);
$skillList .= "
<div class='row'>
<div class='col-md-2 col-xs-6'>
<div class='thumbnail'>
<img class='skill-badge-img' src='".$oneSkill['web_icon_path']."' >
</div>
</div>
<div class='col-md-8 col-xs-6'>
<h5><b>".$oneSkill['name']."</b></h5>
".$oneSkill['description']."
</div>
<div class='col-md-2 col-xs-12'>
<h5><b>".get_lang('ShareWithYourFriends')."</b></h5>
<a href='http://www.facebook.com/sharer.php?u=".api_get_path(WEB_PATH)."badge/".$oneSkill['id']."/user/".$userId."' target='_new'>
<em class='fa fa-facebook-square fa-3x text-info' aria-hidden='true'></em>
</a>
<a href='https://twitter.com/home?status=".api_get_path(WEB_PATH)."badge/".$oneSkill['id']."/user/".$userId."' target='_new'>
<em class='fa fa-twitter-square fa-3x text-light' aria-hidden='true'></em>
</a>
</div>
</div>
";
}
$badgeLink .= "
<div class='panel panel-default'>
<div class='panel-body'>
<h3 class='text-center'>".get_lang('AdditionallyYouHaveObtainedTheFollowingSkills')."</h3>
$skillList
</div>
</div>
";
}
$documentInfo = DocumentManager::get_document_data_by_id(
$id,
$courseCode,
true,
$sessionId
);
$finalItemTemplate = file_get_contents($documentInfo['absolute_path']);
$finalItemTemplate = str_replace('((certificate))', $downloadCertificateLink, $finalItemTemplate);
$finalItemTemplate = str_replace('((skill))', $badgeLink, $finalItemTemplate);
} else {
Display::display_warning_message(get_lang('LearnpathPrereqNotCompleted'));
$finalItemTemplate = '';
}
$currentScore = Category::getCurrentScore($userId, $categoryId, $courseCode, $sessionId, true);
Category::registerCurrentScore($currentScore, $userId, $categoryId);
}
}
}
// Instance a new template : No page tittle, No header, No footer
$tpl = new Template(null, false, false);
$tpl->assign('content', $finalItemTemplate);
$tpl->display_one_col_template();

@ -25,7 +25,6 @@ if ($lp_controller_touched != 1) {
}
require_once '../inc/global.inc.php';
//To prevent the template class
$show_learnpath = true;
@ -174,6 +173,7 @@ if (!isset($src)) {
$_SESSION['oLP']->stop_previous_item();
$htmlHeadXtra[] = '<script src="scorm_api.php" type="text/javascript" language="javascript"></script>';
$preReqCheck = $_SESSION['oLP']->prerequisites_match($lp_item_id);
if ($preReqCheck === true) {
$src = $_SESSION['oLP']->get_link(
'http',

@ -1724,6 +1724,9 @@ function rl_get_resource_link_for_learnpath($course_id, $learnpath_id, $id_in_pa
Session::write('openmethod',$openmethod);
Session::write('officedoc',$officedoc);
break;
case TOOL_LP_FINAL_ITEM:
$link .= api_get_path(WEB_CODE_PATH).'newscorm/lp_final_item.php?id='.$id.'&lp_id='.$learnpath_id;
break;
case 'assignments':
$link .= $main_dir_path.'work/work.php?origin='.$origin;
break;

@ -28,6 +28,7 @@
<li>
{{ profile_link }}
{{ message_link }}
{{ certificate_link }}
</li>
</ul>
</li>

@ -36,6 +36,15 @@
</a>
</p>
{% endif %}
<div class='col-md-12 text-center'>
<h5><b> {{ 'ShareWithYourFriends' | get_lang }} </b></h5>
<a href='http://www.facebook.com/sharer.php?u={{ _p.web }}badge/{{ skill_info.id }}/user/{{ user_info.id }}' target='_new'>
<em class='fa fa-facebook-square fa-3x text-info' aria-hidden='true'></em>
</a>
<a href='https://twitter.com/home?status={{ 'IHaveObtainedSkillXOnY' | get_lang |format(skill_info.name, _s.site_name)}} - {{ _p.web }}badge/{{ skill_info.id }}/user/{{ user_info.id }}' target='_new'>
<em class='fa fa-twitter-square fa-3x text-light' aria-hidden='true'></em>
</a>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">

@ -403,7 +403,6 @@ if ($isAdmin) {
}
}
if ($isAdmin) {
$table->set_header(0, $plugin->get_lang('TicketNum'), true);
$table->set_header(1, $plugin->get_lang('Date'), true);
@ -414,7 +413,6 @@ if ($isAdmin) {
$table->set_header(6, $plugin->get_lang('Status'), true);
$table->set_header(7, $plugin->get_lang('Message'), true);
$table->set_header(8, get_lang('Actions'), true);
$table->set_header(9, get_lang('Description'), true, array("style" => "width:200px"));
} else {
echo '<center><h1>' . $plugin->get_lang('MyTickets') . '</h1></center>';
echo '<center><p>' . $plugin->get_lang('MsgWelcome') . '</p></center>';

@ -829,6 +829,7 @@ class TicketManager
status.name AS col7,
ticket.total_messages AS col8,
msg.message AS col9,
msg.subject AS subject,
ticket.request_user AS user_id,
ticket.assigned_last_user AS responsible
FROM $table_support_tickets ticket,
@ -1052,7 +1053,7 @@ class TicketManager
}
$ticket = array(
$row['col0'],
$row['col0'].' '.$row['subject'],
api_format_date($row['col1'], '%d/%m/%y - %I:%M:%S %p'),
api_format_date($row['col2'], '%d/%m/%y - %I:%M:%S %p'),
$row['col3'],
@ -1061,7 +1062,7 @@ class TicketManager
$row['col7'],
$row['col8'],
$actions,
$row['col9']
//$row['col9']
);
} else {
$actions = "";
@ -1069,7 +1070,7 @@ class TicketManager
'synthese_view.gif', get_lang('Info')
) . '</a>&nbsp;&nbsp;';
$row['col0'] = Display::return_icon(
$img_source, get_lang('Info')
$img_source, get_lang('Info')
) . '<a href="ticket_details.php?ticket_id=' . $row['col0'] . '">' . $row['ticket_code'] . '</a>';
$now = api_strtotime(api_get_utc_datetime());
$last_edit_date = api_strtotime($row['sys_lastedit_datetime']);

@ -330,7 +330,7 @@ if (!isset($_POST['compose'])) {
$admins = UserManager::get_user_list_like(array("status" => "1"), array("username"), true);
foreach ($admins as $admin) {
$select_admins.= "<option value = '" . $admin['user_id'] . "' " . (($user_id == $admin['user_id']) ? ("selected='selected'") : "") . ">" . $admin['lastname'] . " ," . $admin['firstname'] . "</option>";
$select_admins.= "<option value = '" . $admin['user_id'] . "' " . (($user_id == $admin['user_id']) ? ("selected='selected'") : "") . ">" . $admin['lastname'] . ", " . $admin['firstname'] . "</option>";
}
$select_admins .= "</select>";
echo '<div id="dialog-form" title="' . $plugin->get_lang('AssignTicket') . '" >';
@ -457,10 +457,8 @@ function show_form_send_message()
);
}
$form->addElement('file', 'attach_1', get_lang('FilesAttachment'));
$form->addLabel('', '<span id="filepaths"><div id="filepath_1"></div></span>');
$form->addLabel('',
'<span id="link-more-attach">
<span class="btn btn-success" onclick="return add_image_form()">' . get_lang('AddOneMoreFile') . '</span>
@ -468,7 +466,6 @@ function show_form_send_message()
('.sprintf(get_lang('MaximunFileSizeX'), format_file_size(api_get_setting('message_max_upload_filesize'))).')
');
$form->addElement('html', '<br/>');
$form->addElement(
'button',

@ -0,0 +1,51 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ContactBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
/**
* Class UserAdmin
* @package Chamilo\ContactBundle\Admin
*/
class CategoryAdmin extends Admin
{
/**
* @param ListMapper $listMapper
*/
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
//->add('headline', null, array('identifier' => true))
->add('name', null, array('identifier' => true))
->add('email')
;
}
/**
* {@inheritdoc}
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('email')
;
}
/**
* @param DatagridMapper $datagridMapper
*/
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('name')
->add('email')
;
}
}

@ -0,0 +1,15 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ContactBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* Class ChamiloContactBundle
* @package Chamilo\ChamiloContactBundle
*/
class ChamiloContactBundle extends Bundle
{
}

@ -0,0 +1,93 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ContactBundle\Controller;
use Chamilo\ContactBundle\Entity\Category;
use Chamilo\ContactBundle\Form\Type\ContactType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chamilo\UserBundle\Entity\User;
/**
*
* Class ContactController
*
* @Route("/")
*
* @package Chamilo\ContactBundle\Controller
*/
class ContactController extends Controller
{
/**
* @Route("/", name="contact")
*
* @param Request $request
* @return mixed
*/
public function indexAction(Request $request)
{
$type = new ContactType();
/** @var User $user */
$user = $this->getUser();
$data = [];
if ($user) {
$data = [
'firstname' => $user->getFirstname(),
'lastname' => $user->getFirstname(),
'email' => $user->getEmail(),
];
}
$form = $this->createForm($type, $data);
if ($request->isMethod('POST')) {
$form->bind($request);
$em = $this->getDoctrine()->getManager();
$category = $form->get('category')->getData();
/** @var Category $category */
$category = $em->getRepository('ChamiloContactBundle:Category')->find($category);
if ($form->isValid()) {
$message = \Swift_Message::newInstance()
->setSubject($form->get('subject')->getData())
->setFrom($form->get('email')->getData())
->setTo($category->getEmail())
->setBody(
$this->renderView(
'@ChamiloContact/contact.html.twig',
array(
'ip' => $request->getClientIp(),
'firstname' => $form->get('firstname')->getData(),
'lastname' => $form->get('lastname')->getData(),
'subject' => $form->get('subject')->getData(),
'email' => $form->get('email')->getData(),
'message' => $form->get('message')->getData()
)
)
);
$this->get('mailer')->send($message);
$this->addFlash(
'success',
'Your email has been sent! Thanks!'
);
return $this->redirect($this->generateUrl('contact'));
}
}
return $this->render(
'@ChamiloContact/index.html.twig',
array(
'form' => $form->createView()
)
);
}
}

@ -0,0 +1,26 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ContactBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class ChamiloContactExtension extends Extension
{
/**
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('admin.yml');
}
}

@ -0,0 +1,81 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ContactBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Class Category
*
* @ORM\Entity
* @ORM\Table(
* name="contact_category"
* )
*
* @package Chamilo\FaqBundle\Entity
*/
class Category
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue()
*/
protected $id;
/**
* @var string
* @ORM\Column(name="name", type="string", nullable=false)
*/
protected $name;
/**
* @var string
* @ORM\Column(name="email", type="string")
*/
protected $email;
public function __toString()
{
return (string) $this->getName();
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
* @return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* @param string $email
* @return Category
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
}

@ -0,0 +1,13 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ContactBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Contact
{
}

@ -0,0 +1,78 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\ContactBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints\Collection;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
/**
* Class ContactType
* @package Chamilo\ContactBundle\Form\Type
*/
class ContactType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'category',
EntityType::class,
['class' => 'Chamilo\ContactBundle\Entity\Category']
)
->add('firstname')
->add('lastname')
->add('email')
->add('subject')
->add('message', 'textarea')
->add('send', SubmitType::class, ['attr' => ['class' => 'btn btn-primary']])
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$collectionConstraint = new Collection(array(
'category' => array(
new NotBlank(array('message' => 'Category should not be blank.'))
),
'firstname' => array(
new NotBlank(array('message' => 'firstname should not be blank.')),
new Length(array('min' => 2))
),
'lastname' => array(
new NotBlank(array('message' => 'lastname should not be blank.')),
new Length(array('min' => 2))
),
'email' => array(
new NotBlank(array('message' => 'Email should not be blank.')),
new Email(array('message' => 'Invalid email address.'))
),
'subject' => array(
new NotBlank(array('message' => 'Subject should not be blank.')),
new Length(array('min' => 3))
),
'message' => array(
new NotBlank(array('message' => 'Message should not be blank.')),
new Length(array('min' => 5))
)
));
$resolver->setDefaults(array(
'constraints' => $collectionConstraint
));
}
}

@ -0,0 +1,9 @@
services:
sonata.admin.contact_category:
class: Chamilo\ContactBundle\Admin\CategoryAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "LMS", label: "Contact category" }
arguments:
- ~
- Chamilo\ContactBundle\Entity\Category
- ~

@ -0,0 +1,3 @@
contact:
resource: "@ChamiloContactBundle/Controller/ContactController.php"
type: annotation

@ -0,0 +1,11 @@
{{ 'You had a new message from %url%' | trans({'%url%': url(app.request.attributes.get('_route'))} ) }}
{{ 'Firstname' | trans }} : {{ firstname }}
{{ 'Lirstname' | trans }} : {{ lastname }}
Email: {{ email }}
IP: {{ ip }}
{{ 'Subject' | trans }} : {{ subject }}
{{ 'Message' | trans }} :
{{ message|raw }}

@ -0,0 +1,12 @@
{% extends '@ChamiloCore/layout_one_col.html.twig' %}
{% block content %}
<section id="main_content">
<div class="page-header"><h2>{{ 'Contact' | trans }}</h2>
</div>
{{ form_start(form) }}
{{ form_widget(form, {'attr': {'class': ''}}) }}
{{ form_end(form) }}
</section>
{% endblock %}

@ -0,0 +1,37 @@
{% extends "@ChamiloTheme/Layout/base-layout.html.twig" %}
{% block page_content %}
{% if js is defined %}
{% autoescape false %}
{% for item in js %}
{{ item }}
{% endfor %}
{% endautoescape %}
{% endif %}
<div class="row">
<div class="col-xs-12 col-md-12">
{# Breadcrumb #}
{% block chamilo_breadcrumb %}
{# {% include '@ChamiloCore/breadcrumb.html.twig' %}#}
{% endblock %}
{% block chamilo_messages %}
{# Flash messages #}
{% include 'SonataCoreBundle:FlashMessage:render.html.twig' %}
{% endblock %}
{# Content #}
{% block content %}
<section id="main_content">
{% autoescape false %}
{{ content }}
{% endautoescape %}
</section>
{% endblock %}
</div>
</div>
{% endblock %}

@ -0,0 +1,48 @@
{% extends "@ChamiloTheme/Layout/base-layout.html.twig" %}
{% set pathInfo = path(
app.request.attributes.get('_route'),
app.request.attributes.get('_route_params'))
%}
{% block page_content %}
{# Left column #}
<div class="col-md-3">
{% block chamilo_left_column %}
<section class="left_column">
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
{{ render(controller('ChamiloThemeBundle:Sidebar:userPanel', {'pathInfo': pathInfo })) }}
{#{{ render(controller('ChamiloThemeBundle:Sidebar:searchForm')) }}#}
{% endif %}
{# Sidebar menu #}
{{ render(controller('ChamiloThemeBundle:Sidebar:menuKnp', {'request' : app.request, pathInfo: pathInfo })) }}
{# Skill block see SkillBlockService.php #}
{#{{ sonata_block_render({'type': 'chamilo_core.block.skill'}) }}#}
</section>
{% endblock %}
</div>
{# Right column #}
<div class="col-md-9">
{% block chamilo_breadcrumb %}
{% include '@ChamiloCore/breadcrumb.html.twig' %}
{% endblock %}
{% block chamilo_messages %}
{# Flash messages #}
{% include 'SonataCoreBundle:FlashMessage:render.html.twig' %}
{% endblock %}
{% block chamilo_right_column %}
{% block content %}
<section class="right_column">
{% autoescape false %}
{{ content }}
{% endautoescape %}
</section>
{% endblock %}
{% endblock %}
</div>
{% endblock %}

@ -74,6 +74,8 @@
<script src="{{ asset('assets/modernizr/modernizr.js') }}"></script>
<script src="{{ asset('assets/moment/moment.js') }}"></script>
{# Check chamilo_js key in assetic.yml #}
{% block javascripts %}
{#{%- javascripts '@chamilo_js' -%}#}
@ -93,12 +95,12 @@
{#'@MopaBootstrapBundle/Resources/public/js/eyecon-bootstrap-datepicker.js'#}
{% javascripts
'bundles/mopabootstrap/js/mopabootstrap-collection.js'
'bundles/mopabootstrap/js/mopabootstrap-subnav.js'
%}
<script type="text/javascript" src="{{ asset_url | replace({'/app_dev.php': ''}) }}"></script>
{% endjavascripts %}
{#{% javascripts#}
{#'bundles/mopabootstrap/js/mopabootstrap-collection.js'#}
{#'bundles/mopabootstrap/js/mopabootstrap-subnav.js'#}
{#%}#}
{#<script type="text/javascript" src="{{ asset_url | replace({'/app_dev.php': ''}) }}"></script>#}
{#{% endjavascripts %}#}
</head>
{#<body class="{{ admin_skin|default('skin-blue')}}">#}
<body>
@ -222,6 +224,8 @@
{#</header>#}
{% endblock %}
{% include 'SonataCoreBundle:FlashMessage:render.html.twig' %}
{% block chamilo_content %}
{#Check sonata_block.yml settings#}
{#{% include 'SonataSeoBundle:Block:_facebook_sdk.html.twig' %}#}
@ -230,6 +234,10 @@
{% endblock %}
{% block page_content %}
{% endblock %}
{% block sonata_page_container %}
{% endblock %}

@ -3,17 +3,17 @@
$(document).ready( function() {
// Date time settings.
moment.locale('{{ app.request.locale }}');
$.datepicker.setDefaults($.datepicker.regional["{{ app.request.locale }}"]);
$.datepicker.regional["local"] = $.datepicker.regional["{{ app.request.locale }}"];
//$.datepicker.setDefaults($.datepicker.regional["{{ app.request.locale }}"]);
//$.datepicker.regional["local"] = $.datepicker.regional["{{ app.request.locale }}"];
// Chosen select
$(".chzn-select").chosen({
disable_search_threshold: 10,
no_results_text: '{{ 'SearchNoResultsFound' | trans }}',
placeholder_text_multiple: '{{ 'SelectSomeOptions' | trans }}',
placeholder_text_single: '{{ 'SelectAnOption' | trans }}',
width: "100%"
});
{#$(".chzn-select").chosen({#}
{#disable_search_threshold: 10,#}
{#no_results_text: '{{ 'SearchNoResultsFound' | trans }}',#}
{#placeholder_text_multiple: '{{ 'SelectSomeOptions' | trans }}',#}
{#placeholder_text_single: '{{ 'SelectAnOption' | trans }}',#}
{#width: "100%"#}
{#});#}
// Bootstrap tabs.
$('.tab-wrapper a').click(function (e) {
@ -69,7 +69,7 @@
$(".jp-jplayer audio").addClass('skip');
// Mediaelement
jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer(/* Options */);
//jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer(/* Options */);
// Table highlight.
$("form .data_table input:checkbox").click(function () {

@ -126,12 +126,12 @@ $(document).ready(function() {
});
}
$(".accordion_jquery").accordion({
autoHeight: false,
active: false, // all items closed by default
collapsible: true,
header: ".accordion-heading"
});
{#$(".accordion_jquery").accordion({#}
{#autoHeight: false,#}
{#active: false, // all items closed by default#}
{#collapsible: true,#}
{#header: ".accordion-heading"#}
{#});#}
// Global popup
$('body').on('click', 'a.ajax', function(e) {
@ -212,7 +212,7 @@ $(document).ready(function() {
);
/* Make responsive image maps */
$('map').imageMapResize();
// $('map').imageMapResize();
jQuery.fn.filterByText = function(textbox) {
return this.each(function() {
@ -260,10 +260,10 @@ $(document).scroll(function() {
}
if (fixed.attr('data-top') - fixed.outerHeight() <= $(this).scrollTop()) {
fixed.addClass('subnav-fixed');
fixed.addClass('navbar-fixed-top');
fixed.css('width', '100%');
} else {
fixed.removeClass('subnav-fixed');
fixed.removeClass('navbar-fixed-top');
fixed.css('width', '200px');
}
}

@ -47,7 +47,7 @@ Database::query("UPDATE session SET id_coach = NULL WHERE id_coach = 0");
Database::query("UPDATE session SET session_category_id = NULL WHERE session_category_id = 0");
Database::query("ALTER TABLE session ADD CONSTRAINT FK_D044D5D4D1DC2CFC FOREIGN KEY (id_coach) REFERENCES user (id)");
Database::query("ALTER TABLE session ADD CONSTRAINT FK_D044D5D4EE1F8395 FOREIGN KEY (session_category_id) REFERENCES session_category (id)");
Database::query("ALTER TABLE session_rel_user ADD moved_status INT DEFAULT NULL, ADD moved_at DATETIME DEFAULT NULL, CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE session_id session_id INT DEFAULT NULL, CHANGE user_id user_id INT DEFAULT NULL, CHANGE relation_type relation_type INT NOT NULL, CHANGE duration moved_to INT DEFAULT NULL");
Database::query("ALTER TABLE session_rel_user ADD moved_status INT DEFAULT NULL, ADD moved_at DATETIME DEFAULT NULL, CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE session_id session_id INT DEFAULT NULL, CHANGE user_id user_id INT DEFAULT NULL, CHANGE relation_type relation_type INT NOT NULL");
Database::query("ALTER TABLE session_rel_user ENGINE=InnoDB");
Database::query("ALTER TABLE session_rel_user ADD CONSTRAINT FK_B0D7D4C0613FECDF FOREIGN KEY (session_id) REFERENCES session (id)");
Database::query("ALTER TABLE session_rel_user ADD CONSTRAINT FK_B0D7D4C0A76ED395 FOREIGN KEY (user_id) REFERENCES user (id)");

Loading…
Cancel
Save