Merge branch 'master' of github.com:chamilo/chamilo-lms

pull/5213/head
Yannick Warnier 2 years ago
commit 4147746706
  1. 8
      assets/css/app.scss
  2. 73
      assets/css/scss/_forums.scss
  3. 4
      assets/vue/components/userreluser/InvitationList.vue
  4. 180
      public/main/forum/forumfunction.inc.php
  5. 12
      public/main/forum/index.php
  6. 9
      public/main/inc/lib/document.lib.php
  7. 13
      public/main/lp/learnpath.class.php
  8. 3
      public/main/lp/learnpathList.class.php
  9. 5
      public/main/lp/lp_add_item.php
  10. 2
      public/main/session/session_add.php
  11. 11
      public/main/template/default/forum/list.html.twig
  12. 2
      src/CourseBundle/Entity/CQuiz.php
  13. 8
      webpack.config.js

@ -37,6 +37,14 @@
.collapse {
visibility: inherit !important;
}
.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgba(156, 163, 175, var(--tw-border-opacity));
}
.border-gray-100 {
--tw-border-opacity: 1;
border-color: rgba(247, 250, 252, var(--tw-border-opacity));
}
}
@layer components {

@ -4,4 +4,75 @@
.forum_display {
@apply flex flex-row w-full;
}
}
.category-forum {
@apply flex flex-row w-full;
}
.forum_display {
@apply flex flex-row w-full;
}
.custom-panel-heading {
@apply flex items-center justify-between;
}
.open {
@apply flex-shrink-0;
}
.custom-panel-heading h4 {
@apply m-0 flex-grow pl-2.5;
}
.actions {
@apply flex items-center gap-2.5;
}
.actions a,
.actions button {
@apply flex items-center;
}
.custom-panel-heading {
@apply bg-gray-25 border-b border-gray-300 py-2.5 px-4 flex items-center justify-between;
}
.custom-panel-title span {
@apply font-bold text-lg text-gray-90;
}
.custom-panel-heading a {
@apply text-gray-90 no-underline;
}
.custom-panel-heading a:hover,
.custom-panel-heading a:focus {
@apply underline;
}
.custom-panel-body {
@apply p-4;
}
.forum_display {
@apply border-t border-gray-300 py-2.5;
}
.forum_display:first-child {
@apply border-t-0;
}
.forum-description,
.description {
@apply text-gray-50 text-sm mt-1.5;
}
.custom-panel-heading .mdi-folder {
@apply text-gray-90;
}
.ch-tool-icon-disabled {
@apply text-gray-50;
}

@ -22,14 +22,14 @@
label="Accept"
icon="check"
type="success"
@click="emitEvent('accept', invitation.id)"
@click="emitEvent('accept', invitation.itemId)"
/>
<BaseButton
v-if="invitation.canDeny"
label="Deny"
icon="times"
type="danger"
@click="emitEvent('deny', invitation.id)"
@click="emitEvent('deny', invitation.itemId)"
/>
</div>
</div>

@ -990,169 +990,73 @@ function returnLockUnlockIcon(
}
/**
* This function takes care of the display of the up and down icon.
*
* @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
* @param int $id is the id of the item we want to display the icons for
* @param array $list is an array of all the items. All items in this list should have
* an up and down icon except for the first (no up icon) and the last (no down icon)
* The key of this $list array is the id of the item.
*
* @return string HTML
* Generates HTML for up and down icons with links to move an item up or down in a list.
*/
function returnUpDownIcon(string $content, int $id, array $list): string
{
$total_items = count($list);
$position = 0;
$internal_counter = 0;
function returnUpDownIcon(string $content, int $id, array $list): string {
$forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
if (!empty($list)) {
foreach ($list as $item) {
$internal_counter++;
$totalItemsOfType = 0;
$position = 0;
foreach ($list as $key => $item) {
if (($content === 'forumcategory' && $item instanceof CForumCategory) ||
($content === 'forum' && $item instanceof CForum)) {
$totalItemsOfType++;
if ($id == $item->getIid()) {
$position = $internal_counter;
$position = $key + 1;
}
}
}
if ($position > 1) {
$return_value = '<a
href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'"
title="'.get_lang('Move up').'">'.
Display::getMdiIcon(ActionIcon::UP, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Move up')).'</a>';
} else {
$return_value = Display::url(
Display::getMdiIcon(ActionIcon::UP, 'ch-tool-icon-disabled', null, ICON_SIZE_SMALL, ''),
'javascript:void(0)'
);
}
$upIcon = $position > 1
? '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&id='.$id.'" title="'.get_lang('Move up').'">'.Display::getMdiIcon(ActionIcon::UP, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Move up')).'</a>'
: '<span class="ch-tool-icon-disabled">'.Display::getMdiIcon(ActionIcon::UP, 'ch-tool-icon-disabled', null, ICON_SIZE_SMALL, '').'</span>';
$downIcon = $position < $totalItemsOfType
? '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&id='.$id.'" title="'.get_lang('Move down').'">'.Display::getMdiIcon(ActionIcon::DOWN, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Move down')).'</a>'
: '<span class="ch-tool-icon-disabled">'.Display::getMdiIcon(ActionIcon::DOWN, 'ch-tool-icon-disabled', null, ICON_SIZE_SMALL, '').'</span>';
if ($position < $total_items) {
$return_value .= '<a
href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'"
title="'.get_lang('Move down').'" >'.
Display::getMdiIcon(ActionIcon::DOWN, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Move down')).'</a>';
} else {
$return_value = Display::url(
Display::getMdiIcon(ActionIcon::DOWN, 'ch-tool-icon-disabled', null, ICON_SIZE_SMALL, ''),
'javascript:void(0)'
);
}
return $return_value;
return $upIcon . $downIcon;
}
/**
* This function moves a forum or a forum category up or down.
*
* @param string $content is it that we want to make (in)visible: forum category, forum, thread, post
* @param string $direction we want to move it up or down
* @param int $id id of the content we want to make invisible
*
* @return string language variable
*
* @todo consider removing the table_item_property calls here but this can
* prevent unwanted side effects when a forum does not have an entry in
* the item_property table but does have one in the forum table.
*
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
*
* @version february 2006, dokeos 1.8
* Moves a forum or forum category up or down in the display order.
*/
function moveUpDown(string $content, string $direction, int $id): string
{
$table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
$table_forums = Database::get_course_table(TABLE_FORUM);
$course_id = api_get_course_int_id();
$em = Database::getManager();
// Determine which field holds the sort order.
$entity = null;
if ('forumcategory' === $content) {
$table = $table_categories;
$sort_column = 'cat_order';
$id_column = 'cat_id';
$sort_column = 'cat_order';
$entityRepo = $em->getRepository(CForumCategory::class);
} elseif ('forum' === $content) {
$table = $table_forums;
$sort_column = 'forum_order';
$id_column = 'forum_id';
$sort_column = 'forum_order';
// We also need the forum_category of this forum.
$sql = "SELECT forum_category FROM $table_forums
WHERE forum_id = ".$id;
$result = Database::query($sql);
$row = Database::fetch_array($result);
$forum_category = $row['forum_category'];
} else {
return '';
$entityRepo = $em->getRepository(CForum::class);
}
// Determine the need for sorting ascending or descending order.
if ('down' === $direction) {
$sort_direction = 'ASC';
} elseif ('up' === $direction) {
$sort_direction = 'DESC';
} else {
return '';
if (null === $entityRepo) {
return false;
}
// The SQL statement
if ('forumcategory' === $content) {
$sql = "SELECT *
FROM $table_categories forum_categories
WHERE
forum_categories.c_id = $course_id
ORDER BY forum_categories.cat_order $sort_direction";
}
if ('forum' === $content) {
$sql = "SELECT *
FROM $table
WHERE
c_id = $course_id AND
forum_category = '".Database::escape_string($forum_category)."'
ORDER BY forum_order $sort_direction";
$entity = $entityRepo->find($id);
if (null === $entity) {
return false;
}
// Finding the items that need to be switched.
$result = Database::query($sql);
$found = false;
$next_sort = '';
$this_sort = '';
while ($row = Database::fetch_array($result, 'ASSOC')) {
if ($found) {
$next_id = $row[$id_column];
$next_sort = $row[$sort_column];
$found = false;
}
if ($id == $row[$id_column]) {
$this_id = $id;
$this_sort = $row[$sort_column];
$found = true;
}
$resourceNode = $entity->getResourceNode();
if (null === $resourceNode) {
return false;
}
if ('forum' === $content && $next_sort) {
$repo = Container::getForumRepository();
/** @var CForum $forum */
$forum = $repo->find($id);
$forum->setForumOrder($next_sort);
$repo->update($forum);
$currentDisplayOrder = $resourceNode->getDisplayOrder();
Display::addFlash(Display::return_message(get_lang('Updated')));
} else {
if ($next_sort) {
$repo = Container::getForumCategoryRepository();
/** @var CForumCategory $forum */
$category = $repo->find($id);
if ($category) {
$category->setCatOrder($next_sort);
$repo->update($category);
Display::addFlash(Display::return_message(get_lang('Updated')));
}
}
}
$newPosition = $currentDisplayOrder + ($direction === 'down' ? 1 : -1);
$newPosition = max(0, $newPosition);
return '';
$resourceNode->setDisplayOrder($newPosition);
$em->flush();
Display::addFlash(Display::return_message(get_lang('Updated')));
return true;
}
/**
@ -1171,7 +1075,7 @@ function get_forum_categories(int $courseId = 0, int $sessionId = 0): Array
$course = api_get_course_entity($courseId);
$session = api_get_session_entity($sessionId);
$qb = $repo->getResourcesByCourse($course, $session, null, $course->getResourceNode());
$qb = $repo->getResourcesByCourse($course, $session, null, $course->getResourceNode(), true, true);
return $qb->getQuery()->getResult();
}
@ -1197,7 +1101,7 @@ function get_forums_in_category(int $categoryId, int $courseId = 0)
$qb
->andWhere('resource.forumCategory = :catId')
->setParameter('catId', $categoryId)
->orderBy('resource.forumOrder')
->orderBy('node.displayOrder')
;
return $qb->getQuery()->getResult();

@ -254,7 +254,17 @@ if ($value && isset($value['value']) && !empty($value['value'])) {
$searchFilter = '';
$translate = 'true' === api_get_setting('editor.translate_html');
if ($translate) {
$form = new FormValidator('search_simple', 'get', api_get_self().'?'.api_get_cidreq(), null, null, 'inline');
$htmlHeadXtra[] = api_get_css_asset('select2/css/select2.min.css');
$htmlHeadXtra[] = api_get_asset('select2/js/select2.min.js');
$htmlHeadXtra[] = '<script>
$(document).ready(function() {
$("#extra_language").select2({
placeholder: "'.get_lang('Select a language').'",
allowClear: true
});
});
</script>';
$form = new FormValidator('search_simple', 'get', api_get_self().'?'.api_get_cidreq(), null, null);
$form->addHidden('cid', api_get_course_int_id());
$form->addHidden('sid', api_get_session_id());

@ -513,8 +513,6 @@ class DocumentManager
if ('/chat_files' == $path) {
$condition .= " AND (docs.session_id = '$sessionId') ";
}
// share_folder filter
$condition .= " AND docs.path != '/shared_folder' ";
}
return $condition;
@ -567,10 +565,6 @@ class DocumentManager
}
$show_users_condition = '';
if ('false' === api_get_setting('show_users_folders')) {
$show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
}
if ($can_see_invisible) {
$sessionId = $sessionId ?: api_get_session_id();
$condition_session = " AND (l.session_id = '$sessionId' OR (l.session_id = '0' OR l.session_id IS NULL) )";
@ -638,7 +632,7 @@ class DocumentManager
}
//get visible folders
$sql = "SELECT DISTINCT docs.id, docs.path
$sql = "SELECT DISTINCT docs.id
FROM resource_node AS n
INNER JOIN $TABLE_DOCUMENT AS docs
ON (docs.resource_node_id = n.id)
@ -685,7 +679,6 @@ class DocumentManager
INNER JOIN resource_link l
ON (l.resource_node_id = n.id)
WHERE
docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
docs.filetype = 'folder' AND
$groupCondition AND
l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')

@ -2143,8 +2143,17 @@ class learnpath
*/
public function get_lp_session_id()
{
if (!empty($this->lp_session_id)) {
return (int) $this->lp_session_id;
$lp = Container::getLpRepository()->find($this->lp_id);
if ($lp) {
/* @var ResourceNode $resourceNode */
$resourceNode = $lp->getResourceNode();
if ($resourceNode) {
$link = $resourceNode->getResourceLinks()->first();
if ($link && $link->getSession()) {
return (int) $link->getSession()->getId();
}
}
}
return 0;

@ -137,9 +137,10 @@ class LearnpathList
}
}
$link = $lp->getFirstResourceLink();
$this->list[$lp->getIid()] = [
'lp_type' => $lp->getLpType(),
'lp_session' => 0,
'lp_session' => $link && $link->getSession() ? (int) $link->getSession()->getId() : 0,
'lp_name' => stripslashes($lp->getTitle()),
'lp_desc' => stripslashes($lp->getDescription()),
'lp_path' => $lp->getPath(),

@ -20,11 +20,12 @@ $lpId = isset($_REQUEST['lp_id']) ? (int) $_REQUEST['lp_id'] : 0;
$submit = $_POST['submit_button'] ?? null;
$type = $_GET['type'] ?? null;
$action = $_GET['action'] ?? null;
$is_allowed_to_edit = api_is_allowed_to_edit(null, false);
$checkStudentView = 'true' === $isStudentView;
$is_allowed_to_edit = api_is_allowed_to_edit(null, true, false, $checkStudentView);
$listUrl = api_get_path(WEB_CODE_PATH).
'lp/lp_controller.php?action=view&lp_id='.$lpId.'&'.api_get_cidreq().'&isStudentView=true';
if (!$is_allowed_to_edit) {
if ((!$is_allowed_to_edit) || $checkStudentView) {
header("Location: $listUrl");
exit;
}

@ -82,7 +82,7 @@ function search_coachs($needle)
$urlAction = api_get_self();
$session = null;
$fromSessionId = null;
$accessSelected = 0;
$accessSelected = 1;
if (isset($_GET['fromSessionId'])) {
$fromSessionId = (int) $_GET['fromSessionId'];
$session = api_get_session_entity($fromSessionId);

@ -27,6 +27,17 @@
});
});
});
$(document).ready(function() {
var selectedLanguage = localStorage.getItem('selectedLanguage');
if (selectedLanguage) {
$('#extra_language').val(selectedLanguage).trigger('change');
}
$('#extra_language').on('change', function() {
var selectedLanguage = $(this).val();
localStorage.setItem('selectedLanguage', selectedLanguage);
});
});
</script>
{% endif %}

@ -454,7 +454,7 @@ class CQuiz extends AbstractResource implements ResourceInterface, ResourceShowC
/**
* Set text to display to user when they fail to the test (when pass percentage has been set).
*/
public function setTextWhenFinishedFailure(string $textWhenFinished): self
public function setTextWhenFinishedFailure(?string $textWhenFinished): self
{
$this->textWhenFinishedFailure = $textWhenFinished;

@ -129,6 +129,14 @@ Encore.copyFiles({
from: "node_modules/moment/locale",
to: "libs/locale/[path][name].[ext]",
})
Encore.copyFiles({
from: "./node_modules/select2/dist/css",
to: "libs/select2/css/[name].[ext]",
})
Encore.copyFiles({
from: "./node_modules/select2/dist/js",
to: "libs/select2/js/[name].[ext]",
})
const themes = ["chamilo"]

Loading…
Cancel
Save