diff --git a/.eslintrc.json b/.eslintrc.json index ec56cac52f43..7fcaa3026653 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,59 @@ { + "extends": "airbnb-base", "parserOptions": { - "ecmaVersion": 6 + "ecmaVersion": "latest", + "sourceType": "module" }, - "extends": "airbnb-base" -} \ No newline at end of file + // allow certain globals to be used without declaration. + "globals": { + // globals from the browser environment. + "document": "readonly", + "window": "readonly", + "il": "writable", + // globals from the mocha testing framework. + "beforeEach": "readonly", + "afterEach": "readonly", + "describe": "readonly", + "before": "readonly", + "after": "readonly", + "it": "readonly" + }, + // minified and bundled scripts are exempt from the + // code-style. + "ignorePatterns": [ + "**/dist/*", + "*.min.js" + ], + "rules": { + // allow function hoisting as javascript code is + // compiled before execution. + "no-use-before-define": [ + "error", + "nofunc" + ], + // enforce camelcase for classes as well. + "camelcase": [ + "error", + { + "properties": "always", + "ignoreDestructuring": false, + "ignoreGlobals": false + } + ], + // allow anonymous functions for iife's and mocha.js. + "func-names": [ + "warn", + "never" + ], + // allow unresolved imports due to module-bundling + // and third-party libraries. + "import/no-unresolved": 0, + // allow import of devDependencies in test files. + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": true + } + ] + } +} diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 5fa31574d2e1..18900664eba1 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -12,6 +12,7 @@ jobs: fail-fast: false matrix: php: [8.1, 8.2] + nodejs: [ 19.x ] steps: - name: Checkout code uses: actions/checkout@v2 @@ -22,18 +23,31 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip, gd, json, readline, xsl + extensions: dom, curl, libxml, mbstring, zip, gd, json, readline, xsl, imagick tools: composer:v2 coverage: none - - name: Install dependencies + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.nodejs }} + + - name: Install Composer packages run: composer install --no-interaction --no-progress + - name: Install Node.js packages + run: npm install --ignore-scripts + - name: PHP Unit Test run: CI/PHPUnit/run_tests.sh env: GHRUN: "yes" + - name: JS Unit Test + run: npm test + env: + GHRUN: "yes" + - name: PHP CS Fixer run: CI/PHP-CS-Fixer/run_check.sh env: diff --git a/.github/workflows/style-to-repo_trunk.yml b/.github/workflows/style-to-repo_trunk.yml new file mode 100644 index 000000000000..779d3f693755 --- /dev/null +++ b/.github/workflows/style-to-repo_trunk.yml @@ -0,0 +1,23 @@ +name: Build and deploy style files +on: + push: + branches: + - "trunk" + +jobs: + style-to-repo: + if: | + github.event.pull_request.merged == true || + github.event_name == 'push' + runs-on: ubuntu-latest + outputs: + all: ${{ steps.changes.outputs.all }} + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: build and deploy + run: CI/Style-To-Repo/build-and-deploy.sh + env: + STYLE_REPO_PUSH_SECRET: ${{ secrets.STYLE_REPO_PUSH_SECRET }} + STYLE_REPO_USER_NAME: ${{ vars.STYLE_REPO_USER_NAME }} diff --git a/.gitignore b/.gitignore index 1723144cdf97..eff459dbc729 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /extern /Services/PHPUnit/config/cfg.phpunit.php /nbproject +/templates/default/delos.css.map # General Patterns *.bak @@ -20,6 +21,10 @@ *.swp *.swo +# Core Components and Components From Other Vendors +/component/* +!/component/ILIAS + # Generated Files /ilias.ini.php /ilias.log diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 000000000000..62d83a8c19e8 --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,8 @@ +{ + "require": [ + "@babel/register" + ], + "spec": [ + "tests" + ] +} diff --git a/CI/Copyright-Checker/copyright-checker.sh b/CI/Copyright-Checker/copyright-checker.sh index e555ae9ede25..c65f131139f4 100755 --- a/CI/Copyright-Checker/copyright-checker.sh +++ b/CI/Copyright-Checker/copyright-checker.sh @@ -147,12 +147,6 @@ function perform_copyright_check() { local exit_status=0 for file in ${files[@]}; do - # remove this theck once JavaScript files are properly - # supported as well (concept for minified scripts). - if [[ ${file} == *".js" ]]; then - continue - fi - # skip files which don't exist to take care of deleted # files when provided by git. if ! [ -f "${file}" ]; then diff --git a/CI/Copyright-Checker/copyright.js b/CI/Copyright-Checker/copyright.js new file mode 100644 index 000000000000..5d80471a15e8 --- /dev/null +++ b/CI/Copyright-Checker/copyright.js @@ -0,0 +1,36 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + * @author Thibeau Fuhrer + */ + +/** + * @type {string} + */ +const copyright = '/**\n' + + ' * This file is part of ILIAS, a powerful learning management system\n' + + ' * published by ILIAS open source e-Learning e.V.\n' + + ' *\n' + + ' * ILIAS is licensed with the GPL-3.0,\n' + + ' * see https://www.gnu.org/licenses/gpl-3.0.en.html\n' + + ' * You should have received a copy of said license along with the\n' + + ' * source code, too.\n' + + ' *\n' + + " * If this is not the case or you just want to try ILIAS, you'll find\n" + + ' * us at:\n' + + ' * https://www.ilias.de\n' + + ' * https://github.com/ILIAS-eLearning\n' + + ' */'; + +export default copyright; diff --git a/CI/Copyright-Checker/preserveCopyright.js b/CI/Copyright-Checker/preserveCopyright.js new file mode 100644 index 000000000000..58783b8e993f --- /dev/null +++ b/CI/Copyright-Checker/preserveCopyright.js @@ -0,0 +1,45 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + * @author Thibeau Fuhrer + */ + +/** + * Function used by '@rollup/plugin-terser' to preserve only comments which + * contain a string indicating a copyright notice. + * + * Additionally, it only keeps ILIAS copyright notices if they are at the beginning + * of a file, so that the license is not duplicated in the bundled file (this works + * due to plugins being ran after the bundle is created). + * + * @param {Object} node + * @param {number} line + * @param {string} value + * @return {boolean} + */ +export default function preserveCopyright(node, { line, value }) { + const copyrightRegex = /(copyright|license|@preserve|@license|@cc_on)/i; + const iliasRegex = /(ilias)/i; + + if (!copyrightRegex.test(value)) { + return false; + } + + // keeps comments which are at the begining of a file. + if (iliasRegex.test(value)) { + return (line === 0 || line === 1); + } + + return true; +} diff --git a/CI/PHP-CS-Fixer/code-format.php_cs b/CI/PHP-CS-Fixer/code-format.php_cs index e41f762231e9..1c9ed4ffdd5e 100644 --- a/CI/PHP-CS-Fixer/code-format.php_cs +++ b/CI/PHP-CS-Fixer/code-format.php_cs @@ -24,6 +24,7 @@ return (new PhpCsFixer\Config()) 'strict_param' => false, 'concat_space' => ['spacing' => 'one'], 'function_typehint_space' => true, + 'function_declaration' => ['closure_fn_spacing' => 'none'], 'binary_operator_spaces' => ['default' => 'single_space'], // 'types_spaces' => ['space' => 'single'], ]) diff --git a/CI/Style-To-Repo/README.md b/CI/Style-To-Repo/README.md new file mode 100644 index 000000000000..60072287a716 --- /dev/null +++ b/CI/Style-To-Repo/README.md @@ -0,0 +1,32 @@ +# Style to Repo + +These scripts ensure that all style-relevant files are copied to a separate repository. +With each push/merge to the original repository, a commit is created when changes are +made to the style files, which is then pushed into the style repository. +This commit contains the original commit message, the commit hash and a URL to the corresponding commit. + +## Steps to do + +Please change the placeholder values of the variables in deploy.sh. + +STYLE_REPO="https://github.com/foo/style_test.git" +STYLE_REPO_NAME_SHORT="foo/style_test.git" + +### Add a token for an user with admin access to style repository + +- open settings for the user on github +- click 'Developer settings/Personal access tokens/Tokens (classic)' +- click 'Generate new token (classic)' +- add a note for the token +- check repo +- click 'Generate token' +- copy the generated token for the next step + +### Add a secret to the original repository on github + +- open 'Settings' for the repo on github +- select 'Secrets/Actions' from left menu +- click on 'New repository secret' +- the name must be 'STYLE_REPO_NAME_SHORT' +- the secret is the token from the step before +- add the username of the user as variable "STYLE_REPO_USER_NAME" diff --git a/CI/Style-To-Repo/build-and-deploy.sh b/CI/Style-To-Repo/build-and-deploy.sh new file mode 100755 index 000000000000..e3d57cccdf13 --- /dev/null +++ b/CI/Style-To-Repo/build-and-deploy.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# This file is part of ILIAS, a powerful learning management system +# published by ILIAS open source e-Learning e.V. +# +# ILIAS is licensed with the GPL-3.0, +# see https://www.gnu.org/licenses/gpl-3.0.en.html +# You should have received a copy of said license along with the +# source code, too. +# +# If this is not the case or you just want to try ILIAS, you'll find +# us at: +# https://www.ilias.de +# https://github.com/ILIAS-eLearning +# +# Build and deploy style specific files. + +if [ -z ${STYLE_REPO_PUSH_SECRET} ] +then + echo "Please ensure you follow the steps in the 'README.md' and you deposit a 'STYLE_REPO_PUSH_SECRET" + exit +fi + +if [ -z ${STYLE_REPO_USER_NAME} ] +then + echo "Please ensure you follow the steps in the 'README.md' and you deposit a 'STYLE_REPO_USER_NAME" + exit +fi + +MSG=$(git show-branch --no-name HEAD) +HASH=$(git rev-parse HEAD) +URL="https://github.com/ILIAS-eLearning/ILIAS/commit/${HASH}" +BRANCH=$(git rev-parse --abbrev-ref HEAD) + +source "./CI/Style-To-Repo/build.sh" +source "./CI/Style-To-Repo/deploy.sh" +source "./CI/Style-To-Repo/cleanup.sh" + +NOW=$(date +'%d.%m.%Y %I:%M:%S') +echo "[${NOW}] Build style folder." +build + +NOW=$(date +'%d.%m.%Y %I:%M:%S') +echo "[${NOW}] Deploy style folder." +deploy "${MSG}" "${HASH}" "${URL}" "${BRANCH}" "${STYLE_REPO_PUSH_SECRET}" "${STYLE_REPO_USER_NAME}" + +NOW=$(date +'%d.%m.%Y %I:%M:%S') +echo "[${NOW}] Cleanup build and deploy artifacts." +removeBuildArtifacts +removeDeployArtifacts + +NOW=$(date +'%d.%m.%Y %I:%M:%S') +echo "[${NOW}] Done" diff --git a/CI/Style-To-Repo/build.sh b/CI/Style-To-Repo/build.sh new file mode 100755 index 000000000000..cd47a863e614 --- /dev/null +++ b/CI/Style-To-Repo/build.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# This file is part of ILIAS, a powerful learning management system +# published by ILIAS open source e-Learning e.V. +# +# ILIAS is licensed with the GPL-3.0, +# see https://www.gnu.org/licenses/gpl-3.0.en.html +# You should have received a copy of said license along with the +# source code, too. +# +# If this is not the case or you just want to try ILIAS, you'll find +# us at: +# https://www.ilias.de +# https://github.com/ILIAS-eLearning +# +# This script gather all style depending files and add them to a folder. + +BUILD_BASE_FOLDER="./CI/Style-To-Repo/style" + +function build() { + if [ -d ${BUILD_BASE_FOLDER} ] + then + rm -rf ${BUILD_BASE_FOLDER} + fi + + mkdir -p ${BUILD_BASE_FOLDER} + + mkdir ${BUILD_BASE_FOLDER}/UI + mkdir ${BUILD_BASE_FOLDER}/Services + mkdir ${BUILD_BASE_FOLDER}/Modules + + cp -r ./templates/default/* ${BUILD_BASE_FOLDER} + cp -r ./src/UI/templates/default/* ${BUILD_BASE_FOLDER}/UI + + + declare -a SERVICES + + SERVICES=($(find **/*/templates/default -type d | grep ^Services)) + + for SERVICE in "${SERVICES[@]}" + do + NAME=$(echo ${SERVICE} | cut -d'/' -f2- | rev | cut -d'/' -f3- | rev) + if [[ "${NAME}" == *\/* ]] + then + continue + fi + mkdir -p ${BUILD_BASE_FOLDER}/Services/${NAME} + cp -r ${SERVICE}/* ${BUILD_BASE_FOLDER}/Services/${NAME} + done + + declare -a MODULES + + MODULES=($(find **/*/templates/default -type d | grep ^Modules)) + + for MODULE in "${MODULES[@]}" + do + NAME=$(echo ${MODULE} | cut -d'/' -f2- | rev | cut -d'/' -f3- | rev) + if [[ "${NAME}" == *\/* ]] + then + continue + fi + mkdir -p ${BUILD_BASE_FOLDER}/Modules/${NAME} + cp -r ${MODULE}/* ${BUILD_BASE_FOLDER}/Modules/${NAME} + done +} \ No newline at end of file diff --git a/CI/Style-To-Repo/cleanup.sh b/CI/Style-To-Repo/cleanup.sh new file mode 100755 index 000000000000..c7ae9ebf0ca2 --- /dev/null +++ b/CI/Style-To-Repo/cleanup.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# This file is part of ILIAS, a powerful learning management system +# published by ILIAS open source e-Learning e.V. +# +# ILIAS is licensed with the GPL-3.0, +# see https://www.gnu.org/licenses/gpl-3.0.en.html +# You should have received a copy of said license along with the +# source code, too. +# +# If this is not the case or you just want to try ILIAS, you'll find +# us at: +# https://www.ilias.de +# https://github.com/ILIAS-eLearning +# +# This script delete all artifacts that are generated by build and deploy scripts. + +BASE_PATH="./CI/Style-To-Repo" + +function removeBuildArtifacts() { + if [ -d "${BASE_PATH}/style" ] + then + rm -rf ${BASE_PATH}/style + fi +} + +function removeDeployArtifacts() { + if [ -d "${BASE_PATH}/repo" ] + then + rm -rf ${BASE_PATH}/repo + fi +} \ No newline at end of file diff --git a/CI/Style-To-Repo/deploy.sh b/CI/Style-To-Repo/deploy.sh new file mode 100755 index 000000000000..36924105edb4 --- /dev/null +++ b/CI/Style-To-Repo/deploy.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# This file is part of ILIAS, a powerful learning management system +# published by ILIAS open source e-Learning e.V. +# +# ILIAS is licensed with the GPL-3.0, +# see https://www.gnu.org/licenses/gpl-3.0.en.html +# You should have received a copy of said license along with the +# source code, too. +# +# If this is not the case or you just want to try ILIAS, you'll find +# us at: +# https://www.ilias.de +# https://github.com/ILIAS-eLearning +# +# This script compares the actual style repo with the built style folder and pushes the possible changes to repo. + +NOW=$(date +'%d.%m.%Y %I:%M:%S') +DEPLOY_BASE_FOLDER="./CI/Style-To-Repo/repo" +STYLE_REPO="https://github.com/ILIAS-eLearning/delos.git" +STYLE_REPO_NAME_SHORT="ILIAS-eLearning/delos.git" + +function deploy() { + MSG=${1} + HASH=${2} + URL=${3} + BRANCH=${4} + REPO_TOKEN="https://${5}@github.com/${STYLE_REPO_NAME_SHORT}" + USER_NAME=${6} + + if [ -d ${DEPLOY_BASE_FOLDER} ] + then + rm -rf ${DEPLOY_BASE_FOLDER} + fi + + mkdir -p ${DEPLOY_BASE_FOLDER} + git clone ${REPO_TOKEN} ${DEPLOY_BASE_FOLDER} >/dev/null 2>&1 + git -C ${DEPLOY_BASE_FOLDER} ls-remote --exit-code --heads origin ${BRANCH} >/dev/null 2>&1 + BRANCH_EXISTS=$? + + if [ ${BRANCH_EXISTS} == "0" ] + then + git -C ${DEPLOY_BASE_FOLDER} checkout ${BRANCH} >/dev/null 2>&1 + else + git -C ${DEPLOY_BASE_FOLDER} checkout -b ${BRANCH} >/dev/null 2>&1 + NEW_BRANCH="1" + fi + + rm -rf ${DEPLOY_BASE_FOLDER}/* + + cp -r CI/Style-To-Repo/style/* ${DEPLOY_BASE_FOLDER} + + git -C ${DEPLOY_BASE_FOLDER} remote set-url origin ${REPO_TOKEN} + git -C ${DEPLOY_BASE_FOLDER} config user.name ${USER_NAME} + + if [ "${NEW_BRANCH}" == "1" ] + then + echo "[${NOW}] Detected new branch '${BRANCH}', which will be committed to ${STYLE_REPO}" + git -C ${DEPLOY_BASE_FOLDER} add . >/dev/null 2>&1 + git -C ${DEPLOY_BASE_FOLDER} commit -m "Style changes from '${HASH}'" -m "Original message: '${MSG}'" -m "${URL}" >/dev/null 2>&1 + git -C ${DEPLOY_BASE_FOLDER} push origin ${BRANCH} >/dev/null 2>&1 + exit + fi + + git -C ${DEPLOY_BASE_FOLDER} update-index --really-refresh >/dev/null 2>&1 + git -C ${DEPLOY_BASE_FOLDER} diff-index --exit-code HEAD + CHECK1=$? + test -z "$(git -C ${DEPLOY_BASE_FOLDER} ls-files --others)" + CHECK2=$? + + if [[ "${CHECK1}" == "0" && "${CHECK2}" == "0" ]] + then + echo "[${NOW}] No changes detected on style files." + else + echo "[${NOW}] Detected changes on style files, which will be committed to ${STYLE_REPO}" + git -C ${DEPLOY_BASE_FOLDER} status + git -C ${DEPLOY_BASE_FOLDER} ls-files --others + git -C ${DEPLOY_BASE_FOLDER} add . + git -C ${DEPLOY_BASE_FOLDER} ls-files --others + git -C ${DEPLOY_BASE_FOLDER} status + git -C ${DEPLOY_BASE_FOLDER} commit -m "Style changes from '${HASH}'" -m "Original message: '${MSG}'" -m "${URL}" + git -C ${DEPLOY_BASE_FOLDER} push origin ${BRANCH} + fi +} diff --git a/Modules/Blog/Export/class.ilBlogImporter.php b/Modules/Blog/Export/class.ilBlogImporter.php index 878764c42fbd..22cd4c8dfe3b 100644 --- a/Modules/Blog/Export/class.ilBlogImporter.php +++ b/Modules/Blog/Export/class.ilBlogImporter.php @@ -63,9 +63,9 @@ public function finalProcessing( ): void { $blp_map = $a_mapping->getMappingsOfEntity("Services/COPage", "pg"); foreach ($blp_map as $blp_id) { - $blp_id = substr($blp_id, 4); + $blp_id = (int) substr($blp_id, 4); $blog_id = ilBlogPosting::lookupBlogId($blp_id); - ilBlogPosting::_writeParentId("blp", $blp_id, $blog_id); + ilBlogPosting::_writeParentId("blp", $blp_id, (int) $blog_id); } $sty_map = $a_mapping->getMappingsOfEntity("Services/Style", "sty"); diff --git a/Modules/Blog/README.md b/Modules/Blog/README.md index 13b2d117057d..129ed4e76d0e 100644 --- a/Modules/Blog/README.md +++ b/Modules/Blog/README.md @@ -5,4 +5,4 @@ 14 Nov 2019 - A withdrawn property has been added for blog postings. This property from type `ilDateTime` is set/updated when a blog posting becomes a draft after being published before. For initial blog posting drafts, the property is `null`. -(Feature Wiki: https://docu.ilias.de/goto_docu_wiki_wpage_5641_1357.html) \ No newline at end of file +(Feature Wiki: https://docu.ilias.de/goto_docu_wiki_wpage_5641_1357.html) diff --git a/Modules/Blog/classes/class.ilObjBlog.php b/Modules/Blog/classes/class.ilObjBlog.php index 4070bfe1dede..f687cd3305e7 100644 --- a/Modules/Blog/classes/class.ilObjBlog.php +++ b/Modules/Blog/classes/class.ilObjBlog.php @@ -1,7 +1,5 @@ @@ -54,6 +56,7 @@ class ilObjBlog extends ilObject2 protected int $overview_postings = 5; protected bool $authors = true; protected array $order = []; + private \ILIAS\Filesystem\Util\Convert\LegacyImages $image_conversion; public function __construct( int $a_id = 0, @@ -64,6 +67,7 @@ public function __construct( $this->notes_service = $DIC->notes(); parent::__construct($a_id, $a_reference); $this->rbac_review = $DIC->rbac()->review(); + $this->image_conversion = $DIC->fileConverters()->legacyImages(); $this->content_style_service = $DIC ->contentStyle() @@ -345,20 +349,24 @@ public function uploadImage(array $a_upload): bool chmod($path . $original, 0770); $blga_set = new ilSetting("blga"); - /* as banner height should overflow, we only handle width - $dimensions = $blga_set->get("banner_width")."x". - $blga_set->get("banner_height"); - */ - $dimensions = $blga_set->get("banner_width"); - - // take quality 100 to avoid jpeg artefacts when uploading jpeg files - // taking only frame [0] to avoid problems with animated gifs - $original_file = ilShellUtil::escapeShellArg($path . $original); - $thumb_file = ilShellUtil::escapeShellArg($path . $thumb); - $processed_file = ilShellUtil::escapeShellArg($path . $processed); - ilShellUtil::execConvert($original_file . "[0] -geometry 100x100 -quality 100 JPEG:" . $thumb_file); - ilShellUtil::execConvert( - $original_file . "[0] -geometry " . $dimensions . " -quality 100 JPEG:" . $processed_file + + // as banner height should overflow, we only handle width (otherwise resizeToFixedSize could be used) + $banner_width = (int)$blga_set->get("banner_width"); + // $banner_height = (int)$blga_set->get("banner_height"); + + $this->image_conversion->croppedSquare( + $path . $original, + $path . $thumb, + 100, + ImageOutputOptions::FORMAT_KEEP + ); + + $this->image_conversion->resizeByWidth( + $path . $original, + $path . $processed, + $banner_width, + ImageOutputOptions::FORMAT_KEEP, + 100 ); $this->setImage($processed); diff --git a/Modules/BookingManager/README-Service.md b/Modules/BookingManager/README-Service.md deleted file mode 100644 index c88af850965e..000000000000 --- a/Modules/BookingManager/README-Service.md +++ /dev/null @@ -1,92 +0,0 @@ -# Public Service -## Using Booking Manager in Repository Objects - -It is possible to integrate the booking manager as a service into other repository objects, see corresponding [feature wiki entry](https://docu.ilias.de/goto_docu_wiki_wpage_5722_1357.html). - -Currently additional features are organised by **ilObjectServiceSettingsGUI**. You need to integrate this into your settings form initialisation and update procedure: - -``` -ilObjectServiceSettingsGUI::initServiceSettingsForm( - $this->object->getId(), - $form, - array( - [...], - ilObjectServiceSettingsGUI::BOOKING - ) -); -``` - -``` -// after $form initialisation -... -ilObjectServiceSettingsGUI::updateServiceSettingsForm( - $this->object->getId(), - $form, - array( - [...], - ilObjectServiceSettingsGUI::BOOKING - ) -); -``` - - -Furthermore you need to add a **tab** to your UI which points to the class ilBookingGatewayGUI: - -``` -$tabs->addTab("booking", $lng->txt("..."), - $ctrl->getLinkTargetByClass(array("ilbookinggatewaygui"), "")); -``` - -The same class needs to be integrated in your **executeCommand** control flow: - -``` -* @ilCtrl_Calls ilYourClassGUI: ilBookingGatewayGUI -``` - -``` -function executeCommand() -{ - ... - $next_class = $this->ctrl->getNextClass($this); - switch($next_class) - { - case "ilbookinggatewaygui": - ... - $gui = new ilBookingGatewayGUI($this); - $this->ctrl->forwardCommand($gui); - break; - ... -``` - -It is possible to **use the booking manager in a sub-context**, e.g. in a session of a course. The pool selection should only be offered in the course and the session derives these settings from the course. In this case you have to provide the master host ref id (e.g. the course ref id), when creating the instance of ilBookingGatewayGUI within the sub-context (session), e.g.: - -``` -function executeCommand() -{ - ... - $next_class = $this->ctrl->getNextClass($this); - switch($next_class) - { - case "ilbookinggatewaygui": - ... - // example: in ilObjSessionGUI we provide the course ref id - // to define the course as the master host, which also defines the booking - // pools being used - $gui = new ilBookingGatewayGUI($this, $course_ref_id); - $this->ctrl->forwardCommand($gui); - break; - ... -``` - -If your repository objects should present the booking information on the **info screen**, add: - -``` -$info = new ilInfoScreenGUI($this); -$info->enableBookingInfo(true); -``` - -## JF Decisions - -20 May 2019 - -- [Integrating Booking Manager into Courses](https://docu.ilias.de/goto_docu_wiki_wpage_5722_1357.html) diff --git a/Modules/BookingManager/README-technical.md b/Modules/BookingManager/README-technical.md new file mode 100644 index 000000000000..319f1b74dc75 --- /dev/null +++ b/Modules/BookingManager/README-technical.md @@ -0,0 +1,169 @@ +# Booking Pool - Technical Documentation + +## Service + +### Using Booking Manager in Repository Objects + +It is possible to integrate the booking manager as a service into other repository objects, see corresponding [feature wiki entry](https://docu.ilias.de/goto_docu_wiki_wpage_5722_1357.html). + +Currently additional features are organised by **ilObjectServiceSettingsGUI**. You need to integrate this into your settings form initialisation and update procedure: + +``` +ilObjectServiceSettingsGUI::initServiceSettingsForm( + $this->object->getId(), + $form, + array( + [...], + ilObjectServiceSettingsGUI::BOOKING + ) +); +``` + +``` +// after $form initialisation +... +ilObjectServiceSettingsGUI::updateServiceSettingsForm( + $this->object->getId(), + $form, + array( + [...], + ilObjectServiceSettingsGUI::BOOKING + ) +); +``` + + +Furthermore you need to add a **tab** to your UI which points to the class ilBookingGatewayGUI: + +``` +$tabs->addTab("booking", $lng->txt("..."), + $ctrl->getLinkTargetByClass(array("ilbookinggatewaygui"), "")); +``` + +The same class needs to be integrated in your **executeCommand** control flow: + +``` +* @ilCtrl_Calls ilYourClassGUI: ilBookingGatewayGUI +``` + +``` +function executeCommand() +{ + ... + $next_class = $this->ctrl->getNextClass($this); + switch($next_class) + { + case "ilbookinggatewaygui": + ... + $gui = new ilBookingGatewayGUI($this); + $this->ctrl->forwardCommand($gui); + break; + ... +``` + +It is possible to **use the booking manager in a sub-context**, e.g. in a session of a course. The pool selection should only be offered in the course and the session derives these settings from the course. In this case you have to provide the master host ref id (e.g. the course ref id), when creating the instance of ilBookingGatewayGUI within the sub-context (session), e.g.: + +``` +function executeCommand() +{ + ... + $next_class = $this->ctrl->getNextClass($this); + switch($next_class) + { + case "ilbookinggatewaygui": + ... + // example: in ilObjSessionGUI we provide the course ref id + // to define the course as the master host, which also defines the booking + // pools being used + $gui = new ilBookingGatewayGUI($this, $course_ref_id); + $this->ctrl->forwardCommand($gui); + break; + ... +``` + +If your repository objects should present the booking information on the **info screen**, add: + +``` +$info = new ilInfoScreenGUI($this); +$info->enableBookingInfo(true); +``` + +*JF Decisions* + +20 May 2019 + +- [Integrating Booking Manager into Courses](https://docu.ilias.de/goto_docu_wiki_wpage_5722_1357.html) + + +## Entities and Properties + +### Booking Pool + +A booking pool is the main entity for managing booking objects (resources) and their usage (reservations). + +* **Code**: `Modules/BookingManager` +* **DB Tables**: `booking_settings` + +#### Properties + +* **Fixed Schedule** or **No Schedule, Direct Booking** or **No Schedule, Using Prefences**: There are two main types of booking pools, those which are using schedules (e.g. for booking rooms) and those who don't (e.g. for selection of term paper topics). Booking pools without schedule either allow direct booking, or assign objects by preferences. (`booking_settings.schedule_type`) +* **Public Reservations**: The list of reservations can be made publicly available for all users with read permission. (`booking_settings.public_log`) +* **Overall Limit of Bookings** (No schedule only): Limits the maximum number of bookings a single user can do in this pool. (`booking_settings.ovlimit`) +* **Default Period for Reservation List** (Fixed schedule only): Sets the default period of the filter in the reservation list view. (`booking_settings.rsv_filter_period`) +* **Reminder**: A reminder can be activated (`booking_settings.reminder_status`) to remind users of their upcoming bookings. The period before users are reminded can be set (`booking_settings.reminder_day`). A cronjob stores the timestamp for last execution (`booking_settings.last_remind_ts`). + +*Deprecated* + +* `booking_settings.slots_no` ? + +### Schedules + +* **Code**: `Modules/BookingManager/Schedule` +* **DB Tables**: `booking_schedule`, `booking_schedule_slot` + +#### Properties + +... + +### Booking Objects + +* **Code**: `Modules/BookingManager/Objects` +* **DB Tables**: `booking_objects` + +#### Properties + +... + +#### File Storage + +*Additional Description File* +- `ilBookingManager/book*BOOK_OBJ_ID*/file/*FILENAME*` (web data directory) +- Additional description file as uploaded in the booking object settings + +*Post Booking Information File* +- `ilBookingManager/book*BOOK_OBJ_ID*/post/*FILENAME*` (web data directory) +- Information file being presented post booking as uploaded in the booking object settings + +### Reservations + +* **Code**: `Modules/BookingManager/Reservations` +* **DB Tables**: `booking_reservation` + +#### Properties + +* **User**: User who 'owns' the reservation. (`booking_reservation.user`) +* **Assigner**: User who created the reservation. A tutor (assigner) may assign a reservation to a student (user who owns the reservation). (`booking_reservation.assigner_id`) +* **Object**: Object that is reserved. (`booking_reservation.object_id`) +* **Reservation Period**: Timestamps that correspond to a concrete instance of a slot of the object schedule. (`booking_reservation.date_from`, `booking_reservation.date_to`) +* **Reservation Status**: Currently `NULL` (reserved) or `ilBookingReservation::STATUS_CANCELLED` (reservation cancelled). (`booking_reservation.status`) +* **Reservation Grouping**: If multiple instances of an object are reserved, each of them will get an entry in the reservation table. They will all share the same internal group ID. (`booking_reservation.group_id`) +* **Context Object**: If a reservation is done within another repository object (e.g. course), this is stored with the reservation. (`booking_reservation.context_obj_id`) + +### Participants + +* **Code**: `Modules/BookingManager/Participants` +* **DB Tables**: `booking_member` + +#### Properties + +... diff --git a/Modules/BookingManager/README.md b/Modules/BookingManager/README.md index e9cfb9b8a04e..986b4728a85f 100644 --- a/Modules/BookingManager/README.md +++ b/Modules/BookingManager/README.md @@ -1,102 +1,22 @@ # Booking Manager -Public service documentation can be found in the separate [README-Service](./README-Service.md). +This documentation is about the main concepts and business rules. Technical documentation can be found in the separate [README-technical](./README-technical.md). This section documents the general concepts and structures of the Booking Manager. -* [Overview](#overview) -* [Booking Pool](#booking-pool) -* [Schedules](#schedules) -* [Booking Objects](#booking-objects) -* [Reservations](#reservations) -* [Participants](#participants) -* [Assignments by Preference](#assignment-by-preferences) -* [Notifications](#notifications) - ## Overview -* A **booking pool** is a repository object that manages resources (booking objects) and their usage (reservations). There are two main types: Pools that are using schedules (e.g. for booking rooms) and pools without schedules (e.g. for booking term paper topics). +* A **booking pool** is a repository object that manages resources (booking objects) and their usage (reservations). There are two main types: Pools that are using schedules (e.g. for booking rooms) and pools without schedules (e.g. for booking term paper topics). Booking pools without schedule either allow direct booking, or assign objects by preferences. * A pool can hold multiple **schedules**. Schedules contain a set of weekly time **slots** where bookings for objects can be made, e.g. "Monday 10:00-11:00". * A pool manages multiple **booking objects** (resources), e.g. a room or a set of beamers. A booking object uses either no schedule (depending on the pool type) or exactly one schedule. * Users can make **reservations** for booking objects on specific dates that correspond to a time slot of the schedule attached to the booking object. * Users that make reservations in a pool are called **participants**. It is also possible to manually add participants to the pool, that did not make any reservations yet. -## Booking Pool - -A booking pool is the main entity for managing booking objects (resources) and their usage (reservations). - -* **Code**: `Modules/BookingManager` -* **DB Tables**: `booking_settings` - -### Properties - -* **Fixed Schedule** or **No Schedule**: There are two main types of booking pools, those which are using schedules (e.g. for booking rooms) and those who don't (e.g. for selection of term paper topics). (`booking_settings.schedule_type`) -* **Public Reservations**: The list of reservations can be made publicly available for all users with read permission. (`booking_settings.public_log`) -* **Overall Limit of Bookings** (No schedule only): Limits the maximum number of bookings a single user can do in this pool. (`booking_settings.ovlimit`) -* **Default Period for Reservation List** (Fixed schedule only): Sets the default period of the filter in the reservation list view. (`booking_settings.rsv_filter_period`) -* **Reminder**: A reminder can be activated (`booking_settings.reminder_status`) to remind users of their upcoming bookings. The period before users are reminded can be set (`booking_settings.reminder_day`). A cronjob stores the timestamp for last execution (`booking_settings.last_remind_ts`). - -*Deprecated* - -* `booking_settings.slots_no` ? - -## Schedules - -* **Code**: `Modules/BookingManager/Schedule` -* **DB Tables**: `booking_schedule`, `booking_schedule_slot` - -### Properties - -... - -## Booking Objects - -* **Code**: `Modules/BookingManager/Objects` -* **DB Tables**: `booking_objects` - -### Properties - -... - -### File Storage - -*Additional Description File* -- `ilBookingManager/book*BOOK_OBJ_ID*/file/*FILENAME*` (web data directory) -- Additional description file as uploaded in the booking object settings - -*Post Booking Information File* -- `ilBookingManager/book*BOOK_OBJ_ID*/post/*FILENAME*` (web data directory) -- Information file being presented post booking as uploaded in the booking object settings - -## Reservations - -* **Code**: `Modules/BookingManager/Reservations` -* **DB Tables**: `booking_reservation` - -### Properties - -* **User**: User who 'owns' the reservation. (`booking_reservation.user`) -* **Assigner**: User who created the reservation. A tutor (assigner) may assign a reservation to a student (user who owns the reservation). (`booking_reservation.assigner_id`) -* **Object**: Object that is reserved. (`booking_reservation.object_id`) -* **Reservation Period**: Timestamps that correspond to a concrete instance of a slot of the object schedule. (`booking_reservation.date_from`, `booking_reservation.date_to`) -* **Reservation Status**: Currently `NULL` (reserved) or `ilBookingReservation::STATUS_CANCELLED` (reservation cancelled). (`booking_reservation.status`) -* **Reservation Grouping**: If multiple instances of an object are reserved, each of them will get an entry in the reservation table. They will all share the same internal group ID. (`booking_reservation.group_id`) -* **Context Object**: If a reservation is done within another repository object (e.g. course), this is stored with the reservation. (`booking_reservation.context_obj_id`) - -## Participants - -* **Code**: `Modules/BookingManager/Participants` -* **DB Tables**: `booking_member` - -### Properties - -... - ## Assignment by Preferences -### Business Rules +- All participants have to select a fixed number (no more, no less) of preferences. This ensures equal probability of their choice for being selected. -**Procedure** +**Assignment Procedure** See [Feature Wiki](https://docu.ilias.de/goto_docu_wiki_wpage_5688_1357.html) for the general feature spec. @@ -120,8 +40,6 @@ The assignments via preferences is done in two phases: Notifications are currently only sent as part of the reminder feature, if schedules are being used. The [feature wiki entry](https://docu.ilias.de/goto_docu_wiki_wpage_3240_1357.html) includes notifications for bookings/canceling bookings as well, however they have never been implemented. -### Business Rules - - Users with "read" and without "write" permission will only be informed about their own upcoming bookings. - Users with "write" permission be informed about all upcoming bookings. - For reminders reservations are included for the whole time frame (current running time to of the cron job up to end of day x after current time). This will inform on some reservations multiple times (daily), see [Bug #26216](https://mantis.ilias.de/view.php?id=26216). diff --git a/Modules/BookingManager/Reservations/class.ilBookingReservation.php b/Modules/BookingManager/Reservations/class.ilBookingReservation.php index a1bd4f6ba7a6..ce8c00606249 100644 --- a/Modules/BookingManager/Reservations/class.ilBookingReservation.php +++ b/Modules/BookingManager/Reservations/class.ilBookingReservation.php @@ -277,7 +277,7 @@ public static function getAvailableObject( ? $schedule->getAvailabilityFrom()->get(IL_CAL_UNIX) : null; $av_to = ($schedule->getAvailabilityTo() && !$schedule->getAvailabilityTo()->isNull()) - ? strtotime($schedule->getAvailabilityTo()->get(IL_CAL_DATE) . " 23:59:59") + ? $schedule->getAvailabilityTo()->get(IL_CAL_UNIX) : null; if (($av_from && $a_from < $av_from) || diff --git a/Modules/BookingManager/classes/class.ilBookCronNotification.php b/Modules/BookingManager/classes/class.ilBookCronNotification.php index b5182e40189d..147e087f91b6 100644 --- a/Modules/BookingManager/classes/class.ilBookCronNotification.php +++ b/Modules/BookingManager/classes/class.ilBookCronNotification.php @@ -155,7 +155,6 @@ protected function sendNotifications(): int // get subscriber of pool id $user_ids = ilNotification::getNotificationsForObject(ilNotification::TYPE_BOOK, $p["booking_pool_id"]); - $log->debug("users: " . count($user_ids)); // group by user, type, pool @@ -182,8 +181,6 @@ protected function sendNotifications(): int ilObjBookingPool::writeLastReminderTimestamp($p["booking_pool_id"], $to_ts); } - $log->debug("notifications to users: " . count($notifications)); - // send mails $this->sendMails($notifications); @@ -199,7 +196,7 @@ protected function sendMails( $lng->loadLanguageModule("book"); $txt = ""; - if (is_array($n["personal"])) { + if (is_array($n["personal"] ?? null)) { $txt .= "\n" . $lng->txt("book_your_reservations") . "\n"; $txt .= "-----------------------------------------\n"; foreach ($n["personal"] as $obj_id => $reservs) { @@ -212,7 +209,7 @@ protected function sendMails( } } - if (is_array($n["admin"])) { + if (is_array($n["admin"] ?? null)) { $txt .= "\n" . $lng->txt("book_reservation_overview") . "\n"; $txt .= "-----------------------------------------\n"; foreach ($n["admin"] as $obj_id => $reservs) { @@ -233,7 +230,8 @@ protected function sendMails( $ntf->setIntroductionLangId("book_rem_intro"); $ntf->addAdditionalInfo("", $txt); $ntf->setReasonLangId("book_rem_reason"); - $ntf->sendMail(array($uid)); + $this->book_log->debug("send Mail: " . $uid); + $ntf->sendMailAndReturnRecipients([$uid]); } } diff --git a/Modules/CategoryReference/classes/class.ilObjCategoryReferenceListGUI.php b/Modules/CategoryReference/classes/class.ilObjCategoryReferenceListGUI.php index 760b84c50afb..e8b4ba39bde1 100644 --- a/Modules/CategoryReference/classes/class.ilObjCategoryReferenceListGUI.php +++ b/Modules/CategoryReference/classes/class.ilObjCategoryReferenceListGUI.php @@ -81,7 +81,7 @@ public function init(): void $this->subscribe_enabled = true; $this->link_enabled = false; $this->info_screen_enabled = true; - $this->type = "cat"; + $this->type = 'catr'; $this->gui_class_name = "ilobjcategorygui"; $this->substitutions = ilAdvancedMDSubstitution::_getInstanceByObjectType($this->type); diff --git a/Modules/Chatroom/README.md b/Modules/Chatroom/README.md index 73bcdf13f932..064f1520a2ad 100644 --- a/Modules/Chatroom/README.md +++ b/Modules/Chatroom/README.md @@ -302,7 +302,6 @@ client.cfg: "conversation_idle_state_in_minutes": 1, "osd_intervall": 60, "chat_enabled": true, - "enable_smilies": true, "play_invitation_sound": false, "auth": { "key": "0cdc8989-d5f0-1111-4444-244320d9dabc", @@ -480,4 +479,4 @@ Dependencies can be installed by the following command: ```bash npm install --ignore-scripts -``` \ No newline at end of file +``` diff --git a/Modules/Chatroom/classes/Setup/UpdateSteps.php b/Modules/Chatroom/classes/Setup/UpdateSteps.php index 67d1bc3e095e..9fbe0d3a6fd8 100644 --- a/Modules/Chatroom/classes/Setup/UpdateSteps.php +++ b/Modules/Chatroom/classes/Setup/UpdateSteps.php @@ -27,7 +27,7 @@ class UpdateSteps implements ilDatabaseUpdateSteps { protected ilDBInterface $db; - public function prepare(\ilDBInterface $db): void + public function prepare(ilDBInterface $db): void { $this->db = $db; } @@ -43,10 +43,22 @@ public function step_1(): void $this->dropColumnWhenExists('chatroom_history', 'private_rooms_enabled'); } + public function step_2(): void + { + $this->dropTableWhenExists('chatroom_smilies'); + } + private function dropColumnWhenExists(string $table, string $column): void { if ($this->db->tableColumnExists($table, $column)) { $this->db->dropTableColumn($table, $column); } } + + private function dropTableWhenExists(string $table): void + { + if ($this->db->tableExists($table)) { + $this->db->dropTable($table); + } + } } diff --git a/Modules/Chatroom/classes/admingui/class.ilChatroomAdminSmileyGUI.php b/Modules/Chatroom/classes/admingui/class.ilChatroomAdminSmileyGUI.php deleted file mode 100644 index f55bfbd13b9d..000000000000 --- a/Modules/Chatroom/classes/admingui/class.ilChatroomAdminSmileyGUI.php +++ /dev/null @@ -1,579 +0,0 @@ - - * @version $Id$ - * @ingroup ModulesChatroom - */ -class ilChatroomAdminSmileyGUI extends ilChatroomGUIHandler -{ - protected ?ilPropertyFormGUI $form_gui = null; - - public function executeDefault(string $requestedMethod): void - { - $this->view(); - } - - /** - * Switches GUI to visible mode and calls editSmiliesObject method - * which prepares and displays the table of existing smilies. - */ - public function view(): void - { - ilChatroom::checkUserPermissions('read', $this->gui->getRefId()); - - $this->gui->switchToVisibleMode(); - - self::_checkSetup(); - - $this->editSmiliesObject(); - } - - public static function _checkSetup(): bool - { - global $DIC; - $main_tpl = $DIC->ui()->mainTemplate(); - - $path = self::_getSmileyDir(); - - if (!is_dir($path)) { - $main_tpl->setOnScreenMessage('info', $DIC->language()->txt('chat_smilies_dir_not_exists')); - ilFileUtils::makeDirParents($path); - - if (!is_dir($path)) { - $main_tpl->setOnScreenMessage('failure', $DIC->language()->txt('chat_smilies_dir_not_available')); - return false; - } - - $smilies = [ - 'icon_smile.gif', - 'icon_wink.gif', - 'icon_laugh.gif', - 'icon_sad.gif', - 'icon_shocked.gif', - 'icon_tongue.gif', - 'icon_cool.gif', - 'icon_eek.gif', - 'icon_angry.gif', - 'icon_flush.gif', - 'icon_idea.gif', - 'icon_thumbup.gif', - 'icon_thumbdown.gif', - ]; - - foreach ($smilies as $smiley) { - copy("templates/default/images/emoticons/$smiley", $path . "/$smiley"); - } - - self::_insertDefaultValues(); - - $main_tpl->setOnScreenMessage('success', $DIC->language()->txt('chat_smilies_initialized')); - } - - if (!is_writable($path)) { - $main_tpl->setOnScreenMessage('info', $DIC->language()->txt('chat_smilies_dir_not_writable')); - } - - return true; - } - - public static function _getSmileyDir(bool $withBaseDir = true): string - { - $path = 'chatroom/smilies'; - - if ($withBaseDir) { - $path = ilFileUtils::getWebspaceDir() . '/' . $path; - } - - return $path; - } - - private static function _insertDefaultValues(): void - { - $values = [ - ["icon_smile.gif", ":)\n:-)\n:smile:"], - ["icon_wink.gif", ";)\n;-)\n:wink:"], - ["icon_laugh.gif", ":D\n:-D\n:laugh:\n:grin:\n:biggrin:"], - ["icon_sad.gif", ":(\n:-(\n:sad:"], - ["icon_shocked.gif", ":o\n:-o\n:shocked:"], - ["icon_tongue.gif", ":p\n:-p\n:tongue:"], - ["icon_cool.gif", ":cool:"], - ["icon_eek.gif", ":eek:"], - ["icon_angry.gif", ":||\n:-||\n:angry:"], - ["icon_flush.gif", ":flush:"], - ["icon_idea.gif", ":idea:"], - ["icon_thumbup.gif", ":thumbup:"], - ["icon_thumbdown.gif", ":thumbdown:"], - ]; - - foreach ($values as $val) { - ilChatroomSmilies::_storeSmiley($val[1], $val[0]); - } - } - - /** - * Shows existing smilies table - * Prepares existing smilies table and displays it. - */ - public function editSmiliesObject(): void - { - if (!$this->rbacsystem->checkAccess('read', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_read'), - $this->ilias->error_obj->MESSAGE - ); - } - - ilChatroomSmilies::_checkSetup(); - - if (null === $this->form_gui) { - $this->form_gui = $this->initSmiliesForm(); - } - - $tpl_smilies = new ilTemplate( - 'tpl.chatroom_edit_smilies.html', - true, - true, - 'Modules/Chatroom' - ); - $tpl_smilies->setVariable('SMILEY_TABLE', ilChatroomSmiliesGUI::_getExistingSmiliesTable( - $this->gui, - $this->uiFactory, - $this->uiRenderer, - $this->rbacsystem - )); - $tpl_smilies->setVariable('SMILEY_FORM', $this->form_gui->getHTML()); - - $this->mainTpl->setContent($tpl_smilies->get()); - } - - public function initSmiliesForm(): ilPropertyFormGUI - { - global $DIC; - - $this->form_gui = new ilPropertyFormGUI(); - - if ($this->http->wrapper()->query()->has('_table_nav')) { - $this->ilCtrl->setParameter( - $this->gui, - '_table_nav', - $this->http->wrapper()->query()->retrieve('_table_nav', $this->refinery->kindlyTo()->string()) - ); - } - $this->form_gui->setFormAction($this->ilCtrl->getFormAction($this->gui, 'smiley-uploadSmileyObject')); - - $sec_l = new ilFormSectionHeaderGUI(); - - $sec_l->setTitle($this->ilLng->txt('chatroom_add_smiley')); - $this->form_gui->addItem($sec_l); - - $inp = new ilImageFileInputGUI( - $this->ilLng->txt('chatroom_image_path'), - 'chatroom_image_path' - ); - $inp->setSuffixes(['jpg', 'jpeg', 'png', 'gif', 'svg']); - - $inp->setRequired(true); - $this->form_gui->addItem($inp); - - $inp = new ilTextAreaInputGUI( - $this->ilLng->txt('chatroom_smiley_keywords'), - 'chatroom_smiley_keywords' - ); - - $inp->setRequired(true); - $inp->setUseRte(false); - $inp->setInfo($this->ilLng->txt('chatroom_smiley_keywords_one_per_line_note')); - $this->form_gui->addItem($inp); - - - if ($this->rbacsystem->checkAccess('write', $this->gui->getRefId())) { - $this->form_gui->addCommandButton( - 'smiley-uploadSmileyObject', - $DIC->language()->txt('chatroom_upload_smiley') - ); - } - - return $this->form_gui; - } - - /** - * Shows EditSmileyEntryForm - * Prepares EditSmileyEntryForm and displays it. - */ - public function showEditSmileyEntryFormObject(): void - { - $this->gui->switchToVisibleMode(); - - if (!$this->rbacsystem->checkAccess('read', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_read'), - $this->ilias->error_obj->MESSAGE - ); - } - - $smileyId = $this->getRequestValue('smiley_id', $this->refinery->kindlyTo()->int()); - - if (null === $this->form_gui) { - $this->form_gui = $this->initSmiliesEditForm($this->getSmileyFormDataById($smileyId)); - } - - $tpl_form = new ilTemplate( - 'tpl.chatroom_edit_smilies.html', - true, - true, - 'Modules/Chatroom' - ); - - $tpl_form->setVariable('SMILEY_FORM', $this->form_gui->getHTML()); - - $this->mainTpl->setContent($tpl_form->get()); - } - - /** - * @return array{chatroom_smiley_id: int, chatroom_smiley_keywords: string, chatroom_current_smiley_image_path: string} - */ - protected function getSmileyFormDataById(int $smileyId): array - { - $smiley = ilChatroomSmilies::_getSmiley($smileyId); - - return [ - 'chatroom_smiley_id' => $smiley['smiley_id'], - 'chatroom_smiley_keywords' => $smiley['smiley_keywords'], - 'chatroom_current_smiley_image_path' => $smiley['smiley_fullpath'], - ]; - } - - /** - * @param array $form_data - */ - public function initSmiliesEditForm(array $form_data): ilPropertyFormGUI - { - $this->form_gui = new ilPropertyFormGUI(); - $this->form_gui->setValuesByArray($form_data); - - if ($this->http->wrapper()->query()->has('_table_nav')) { - $this->ilCtrl->setParameter( - $this->gui, - '_table_nav', - $this->http->wrapper()->query()->retrieve('_table_nav', $this->refinery->kindlyTo()->string()) - ); - } - - $this->ilCtrl->saveParameter($this->gui, 'smiley_id'); - $this->form_gui->setFormAction($this->ilCtrl->getFormAction($this->gui, 'smiley-updateSmiliesObject')); - - $sec_l = new ilFormSectionHeaderGUI(); - - $sec_l->setTitle($this->ilLng->txt('chatroom_edit_smiley')); - $this->form_gui->addItem($sec_l); - - $inp = new ilChatroomSmiliesCurrentSmileyFormElement( - $this->ilLng->txt('chatroom_current_smiley_image_path'), - 'chatroom_current_smiley_image_path' - ); - - $inp->setValue($form_data['chatroom_current_smiley_image_path']); - $this->form_gui->addItem($inp); - - $inp = new ilImageFileInputGUI( - $this->ilLng->txt('chatroom_image_path'), - 'chatroom_image_path' - ); - $inp->setSuffixes(['jpg', 'jpeg', 'png', 'gif', 'svg']); - - $inp->setRequired(false); - $inp->setInfo($this->ilLng->txt('chatroom_smiley_image_only_if_changed')); - $this->form_gui->addItem($inp); - - $inp = new ilTextAreaInputGUI( - $this->ilLng->txt('chatroom_smiley_keywords'), - 'chatroom_smiley_keywords' - ); - - $inp->setValue($form_data['chatroom_smiley_keywords']); - $inp->setUseRte(false); - $inp->setRequired(true); - $inp->setInfo($this->ilLng->txt('chatroom_smiley_keywords_one_per_line_note')); - $this->form_gui->addItem($inp); - - $inp = new ilHiddenInputGUI('chatroom_smiley_id'); - - $this->form_gui->addItem($inp); - $this->form_gui->addCommandButton( - 'smiley-updateSmiliesObject', - $this->ilLng->txt('submit') - ); - $this->form_gui->addCommandButton('smiley', $this->ilLng->txt('cancel')); - - return $this->form_gui; - } - - /** - * Shows DeleteSmileyForm - * Prepares DeleteSmileyForm and displays it. - */ - public function showDeleteSmileyFormObject(): void - { - $this->gui->switchToVisibleMode(); - - if (!$this->rbacsystem->checkAccess('write', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_write'), - $this->ilias->error_obj->MESSAGE - ); - } - - $smileyId = $this->getRequestValue('smiley_id', $this->refinery->kindlyTo()->int()); - - $smiley = ilChatroomSmilies::_getSmiley($smileyId); - - $confirmation = new ilConfirmationGUI(); - $confirmation->setFormAction($this->ilCtrl->getFormAction($this->gui, 'smiley')); - $confirmation->setHeaderText($this->ilLng->txt('chatroom_confirm_delete_smiley')); - $confirmation->setConfirm($this->ilLng->txt('confirm'), 'smiley-deleteSmileyObject'); - $confirmation->setCancel($this->ilLng->txt('cancel'), 'smiley'); - $confirmation->addItem( - 'chatroom_smiley_id', - (string) $smiley['smiley_id'], - ilUtil::img($smiley['smiley_fullpath'], $smiley['smiley_keywords']) . ' ' . $smiley['smiley_keywords'] - ); - - $this->mainTpl->setContent($confirmation->getHTML()); - } - - public function deleteSmileyObject(): void - { - if (!$this->rbacsystem->checkAccess('write', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_write'), - $this->ilias->error_obj->MESSAGE - ); - } - - $smileyId = $this->getRequestValue( - 'chatroom_smiley_id', - $this->refinery->kindlyTo()->int() - ); - - ilChatroomSmilies::_deleteSmiley($smileyId); - - $this->ilCtrl->redirect($this->gui, 'smiley'); - } - - public function updateSmiliesObject(): void - { - if (!$this->rbacsystem->checkAccess('write', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_write'), - $this->ilias->error_obj->MESSAGE - ); - } - - $smileyId = $this->getRequestValue('smiley_id', $this->refinery->kindlyTo()->int()); - - $this->initSmiliesEditForm($this->getSmileyFormDataById($smileyId)); - - $keywords = ilChatroomSmilies::_prepareKeywords(ilUtil::stripSlashes( - $this->getRequestValue('chatroom_smiley_keywords', $this->refinery->kindlyTo()->string(), '') - )); - - $atLeastOneKeywordGiven = count($keywords) > 0; - - $isFormValid = $this->form_gui->checkInput(); - if (!$atLeastOneKeywordGiven || !$isFormValid) { - $errorShown = !$isFormValid; - if (!$atLeastOneKeywordGiven && !$errorShown) { - $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('form_input_not_valid')); - } - - $this->form_gui->setValuesByPost(); - - $this->showEditSmileyEntryFormObject(); - return; - } - - $data = []; - $data['smiley_keywords'] = implode("\n", $keywords); - $data['smiley_id'] = $smileyId; - - if ($this->upload->hasUploads() && !$this->upload->hasBeenProcessed()) { - $this->upload->process(); - - /** @var \ILIAS\FileUpload\DTO\UploadResult|null $result */ - $result = array_values($this->upload->getResults())[0]; - if ($result && $result->isOK()) { - $this->upload->moveOneFileTo( - $result, - ilChatroomSmilies::getSmiliesBasePath(), - \ILIAS\FileUpload\Location::WEB, - $result->getName(), - true - ); - - $data['smiley_path'] = $result->getName(); - } - } - - ilChatroomSmilies::_updateSmiley($data); - - $this->mainTpl->setOnScreenMessage('success', $this->ilLng->txt('saved_successfully'), true); - $this->ilCtrl->redirect($this->gui, 'smiley'); - } - - /** - * Shows confirmation view for deleting multiple smilies - * Prepares confirmation view for deleting multiple smilies and displays it. - */ - public function deleteMultipleObject(): void - { - $this->gui->switchToVisibleMode(); - - if (!$this->rbacsystem->checkAccess('write', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_write'), - $this->ilias->error_obj->MESSAGE - ); - } - - $ids = $this->getRequestValue( - 'smiley_id', - $this->refinery->kindlyTo()->listOf( - $this->refinery->kindlyTo()->int() - ), - [] - ); - if ($ids === []) { - $this->mainTpl->setOnScreenMessage('info', $this->ilLng->txt('select_one'), true); - $this->ilCtrl->redirect($this->gui, 'smiley'); - } - - $smilies = ilChatroomSmilies::_getSmiliesById($ids); - if ($smilies === []) { - $this->mainTpl->setOnScreenMessage('info', $this->ilLng->txt('select_one'), true); - $this->ilCtrl->redirect($this->gui, 'smiley'); - } - - $confirmation = new ilConfirmationGUI(); - $confirmation->setFormAction($this->ilCtrl->getFormAction($this->gui, 'smiley')); - $confirmation->setHeaderText($this->ilLng->txt('chatroom_confirm_delete_smiley')); - $confirmation->setConfirm($this->ilLng->txt('confirm'), 'smiley-confirmedDeleteMultipleObject'); - $confirmation->setCancel($this->ilLng->txt('cancel'), 'smiley'); - - foreach ($smilies as $s) { - $confirmation->addItem( - 'sel_ids[]', - (string) $s['smiley_id'], - ilUtil::img($s['smiley_fullpath'], $s['smiley_keywords']) . ' ' . $s['smiley_keywords'] - ); - } - - $this->mainTpl->setContent($confirmation->getHTML()); - } - - public function confirmedDeleteMultipleObject(): void - { - if (!$this->rbacsystem->checkAccess('write', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_write'), - $this->ilias->error_obj->MESSAGE - ); - } - - $ids = $this->getRequestValue( - 'sel_ids', - $this->refinery->kindlyTo()->listOf( - $this->refinery->kindlyTo()->int() - ), - [] - ); - - if ($ids === []) { - $this->ilCtrl->redirect($this->gui, 'smiley'); - } - - ilChatroomSmilies::_deleteMultipleSmilies($ids); - - $this->ilCtrl->redirect($this->gui, 'smiley'); - } - - public function uploadSmileyObject(): void - { - if (!$this->rbacsystem->checkAccess('write', $this->gui->getRefId())) { - $this->ilias->raiseError( - $this->ilLng->txt('msg_no_perm_write'), - $this->ilias->error_obj->MESSAGE - ); - } - - $this->initSmiliesForm(); - - $keywords = ilChatroomSmilies::_prepareKeywords(ilUtil::stripSlashes( - $this->getRequestValue( - 'chatroom_smiley_keywords', - $this->refinery->kindlyTo()->string(), - '' - ) - )); - - $atLeastOneKeywordGiven = count($keywords) > 0; - - $isFormValid = $this->form_gui->checkInput(); - if (!$atLeastOneKeywordGiven || !$isFormValid) { - $errorShown = !$isFormValid; - if (!$atLeastOneKeywordGiven && !$errorShown) { - $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('form_input_not_valid')); - } - - $this->form_gui->setValuesByPost(); - - $this->view(); - return; - } - - $pathinfo = pathinfo($_FILES['chatroom_image_path']['name']); - $target_file = md5(time() . $pathinfo['basename']) . '.' . $pathinfo['extension']; - - if ($this->upload->hasUploads() && !$this->upload->hasBeenProcessed()) { - $this->upload->process(); - - /** @var \ILIAS\FileUpload\DTO\UploadResult|null $result */ - $result = array_values($this->upload->getResults())[0]; - if ($result && $result->isOK()) { - $this->upload->moveOneFileTo( - $result, - ilChatroomSmilies::getSmiliesBasePath(), - \ILIAS\FileUpload\Location::WEB, - $target_file, - true - ); - - ilChatroomSmilies::_storeSmiley(implode("\n", $keywords), $target_file); - } - } - - $this->mainTpl->setOnScreenMessage('success', $this->ilLng->txt('saved_successfully'), true); - $this->ilCtrl->redirect($this->gui, 'smiley'); - } -} diff --git a/Modules/Chatroom/classes/admingui/class.ilChatroomAdminViewGUI.php b/Modules/Chatroom/classes/admingui/class.ilChatroomAdminViewGUI.php index 2a45affda7b6..c49b02ce54d0 100644 --- a/Modules/Chatroom/classes/admingui/class.ilChatroomAdminViewGUI.php +++ b/Modules/Chatroom/classes/admingui/class.ilChatroomAdminViewGUI.php @@ -132,7 +132,6 @@ public function saveClientSettings(): void 'enable_browser_notifications' => (bool) $form->getInput('enable_browser_notifications'), 'conversation_idle_state_in_minutes' => $convIdleStateTime, 'chat_enabled' => (bool) $form->getInput('chat_enabled'), - 'enable_smilies' => (bool) $form->getInput('enable_smilies'), 'auth' => $form->getInput('auth') ]; diff --git a/Modules/Chatroom/classes/class.ilChatroomAuthInputGUI.php b/Modules/Chatroom/classes/class.ilChatroomAuthInputGUI.php index 8011358ae389..355b9c1f4004 100644 --- a/Modules/Chatroom/classes/class.ilChatroomAuthInputGUI.php +++ b/Modules/Chatroom/classes/class.ilChatroomAuthInputGUI.php @@ -103,7 +103,7 @@ public function setValueByArray(array $a_values): void { $this->values = [ self::NAME_AUTH_PROP_1 => $a_values[$this->getPostVar()][self::NAME_AUTH_PROP_1] ?? '', - self::NAME_AUTH_PROP_2 => $a_values[$this->getPostVar()][self::NAME_AUTH_PROP_2]?? '' + self::NAME_AUTH_PROP_2 => $a_values[$this->getPostVar()][self::NAME_AUTH_PROP_2] ?? '' ]; foreach ($this->getSubItems() as $item) { diff --git a/Modules/Chatroom/classes/class.ilChatroomFormFactory.php b/Modules/Chatroom/classes/class.ilChatroomFormFactory.php index e8fb4d2d003f..80b176ea65e6 100644 --- a/Modules/Chatroom/classes/class.ilChatroomFormFactory.php +++ b/Modules/Chatroom/classes/class.ilChatroomFormFactory.php @@ -276,10 +276,6 @@ public function getClientSettingsForm(): ilPropertyFormGUI $oscBrowserNotificationIdleTime->setInfo($this->lng->txt('osc_adm_conv_idle_state_threshold_info')); $enable_osc->addSubItem($oscBrowserNotificationIdleTime); - $enable_smilies = new ilCheckboxInputGUI($this->lng->txt('enable_smilies'), 'enable_smilies'); - $enable_smilies->setInfo($this->lng->txt('hint_enable_smilies')); - $enable_chat->addSubItem($enable_smilies); - $name = new ilTextInputGUI($this->lng->txt('chatroom_client_name'), 'client_name'); $name->setInfo($this->lng->txt('chatroom_client_name_info')); $name->setRequired(true); diff --git a/Modules/Chatroom/classes/class.ilChatroomInstaller.php b/Modules/Chatroom/classes/class.ilChatroomInstaller.php index 7f507a4ee1d4..a5287358b6cf 100644 --- a/Modules/Chatroom/classes/class.ilChatroomInstaller.php +++ b/Modules/Chatroom/classes/class.ilChatroomInstaller.php @@ -182,27 +182,6 @@ public static function install(): void ); } - if (!$ilDB->tableExists('chatroom_smilies')) { - $fields = [ - 'smiley_id' => [ - 'type' => 'integer', - 'length' => 4, - ], - 'smiley_keywords' => [ - 'type' => 'text', - 'length' => 100, - ], - 'smiley_path' => [ - 'type' => 'text', - 'length' => 200, - ] - ]; - - $ilDB->createTable('chatroom_smilies', $fields); - $ilDB->addPrimaryKey('chatroom_smilies', ['smiley_id']); - $ilDB->createSequence('chatroom_smilies'); - } - self::registerObject(); self::registerAdminObject(); self::removeOldChatEntries(); diff --git a/Modules/Chatroom/classes/class.ilChatroomServerSettings.php b/Modules/Chatroom/classes/class.ilChatroomServerSettings.php index 860aa163ef4a..0a74e78ce7b4 100644 --- a/Modules/Chatroom/classes/class.ilChatroomServerSettings.php +++ b/Modules/Chatroom/classes/class.ilChatroomServerSettings.php @@ -35,7 +35,6 @@ class ilChatroomServerSettings private string $protocol = self::DEFAULT_PROCOTOL; private string $domain = self::DEFAULT_HOST; private string $instance = '123456'; - private bool $smilies_enabled = false; private string $authKey = ''; private string $authSecret = ''; private bool $clientUrlEnabled = false; @@ -60,7 +59,6 @@ public static function loadDefault(): self $settings->setPort((int) ($server_settings->port ?? self::DEFAULT_PORT)); $settings->setProtocol((string) ($server_settings->protocol ?? self::DEFAULT_PROCOTOL)); $settings->setDomain((string) ($server_settings->address ?? self::DEFAULT_HOST)); - $settings->setSmiliesEnabled((bool) ($client_settings->enable_smilies ?? false)); $settings->setClientUrlEnabled((bool) ($server_settings->client_proxy ?? false)); $settings->setIliasUrlEnabled((bool) ($server_settings->ilias_proxy ?? false)); $settings->setClientUrl((string) ($server_settings->client_url ?? '')); @@ -213,16 +211,6 @@ public function setClientUrl(string $clientUrl): void $this->clientUrl = $clientUrl; } - public function getSmiliesEnabled(): bool - { - return $this->smilies_enabled; - } - - public function setSmiliesEnabled(bool $a_bool): void - { - $this->smilies_enabled = $a_bool; - } - public function getAuthKey(): string { return $this->authKey; diff --git a/Modules/Chatroom/classes/class.ilChatroomSmilies.php b/Modules/Chatroom/classes/class.ilChatroomSmilies.php deleted file mode 100644 index 9323763750f8..000000000000 --- a/Modules/Chatroom/classes/class.ilChatroomSmilies.php +++ /dev/null @@ -1,334 +0,0 @@ - - * @version $Id$ - * @ingroup ModulesChatroom - */ -class ilChatroomSmilies -{ - /** - * Inserts default smiley set - */ - private static function _insertDefaultValues(): void - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - $values = [ - ["icon_smile.gif", ":)\n:-)\n:smile:"], - ["icon_wink.gif", ";)\n;-)\n:wink:"], - ["icon_laugh.gif", ":D\n:-D\n:laugh:\n:grin:\n:biggrin:"], - ["icon_sad.gif", ":(\n:-(\n:sad:"], - ["icon_shocked.gif", ":o\n:-o\n:shocked:"], - ["icon_tongue.gif", ":p\n:-p\n:tongue:"], - ["icon_cool.gif", ":cool:"], - ["icon_eek.gif", ":eek:"], - ["icon_angry.gif", ":||\n:-||\n:angry:"], - ["icon_flush.gif", ":flush:"], - ["icon_idea.gif", ":idea:"], - ["icon_thumbup.gif", ":thumbup:"], - ["icon_thumbdown.gif", ":thumbdown:"], - ]; - - $stmt = $ilDB->prepareManip( - 'INSERT INTO chatroom_smilies (smiley_id, smiley_keywords, smiley_path) VALUES (?, ?, ?)', - ['integer', 'text', 'text'] - ); - - foreach ($values as $val) { - $row = [ - $ilDB->nextId('chatroom_smilies'), - $val[1], - $val[0] - ]; - $stmt->execute($row); - } - } - - /** - * Checks if smiley folder is available; if not - * it will try to create folder and performs - * actions for an initial smiley set - */ - public static function _checkSetup(): bool - { - global $DIC; - $main_tpl = $DIC->ui()->mainTemplate(); - - /** @var ilLanguage $lng */ - $lng = $DIC->language(); - - $path = self::_getSmileyDir(); - - if (!is_dir($path)) { - $main_tpl->setOnScreenMessage('info', $lng->txt('chatroom_smilies_dir_not_exists')); - ilFileUtils::makeDirParents($path); - - if (!is_dir($path)) { - $main_tpl->setOnScreenMessage('failure', $lng->txt('chatroom_smilies_dir_not_available')); - return false; - } - - $smilies = [ - "icon_smile.gif", - "icon_wink.gif", - "icon_laugh.gif", - "icon_sad.gif", - "icon_shocked.gif", - "icon_tongue.gif", - "icon_cool.gif", - "icon_eek.gif", - "icon_angry.gif", - "icon_flush.gif", - "icon_idea.gif", - "icon_thumbup.gif", - "icon_thumbdown.gif", - ]; - - foreach ($smilies as $smiley) { - copy("templates/default/images/emoticons/$smiley", $path . "/$smiley"); - } - - self::_insertDefaultValues(); - $main_tpl->setOnScreenMessage('success', $lng->txt('chatroom_smilies_initialized')); - } - - if (!is_writable($path)) { - $main_tpl->setOnScreenMessage('info', $lng->txt('chatroom_smilies_dir_not_writable')); - } - - return true; - } - - public static function _getSmileyDir(): string - { - return ilFileUtils::getWebspaceDir() . '/chatroom/smilies'; - } - - /** - * @return array{smiley_id: int, smiley_keywords: string, smiley_path: string, smiley_fullpath: string}[] - */ - public static function _getSmilies(): array - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - $res = $ilDB->query("SELECT smiley_id, smiley_keywords, smiley_path FROM chatroom_smilies"); - $result = []; - - while ($row = $ilDB->fetchAssoc($res)) { - $result[] = [ - 'smiley_id' => (int) $row['smiley_id'], - 'smiley_keywords' => $row['smiley_keywords'], - 'smiley_path' => $row['smiley_path'], - 'smiley_fullpath' => ilFileUtils::getWebspaceDir() . '/chatroom/smilies/' . $row['smiley_path'] - ]; - } - - return $result; - } - - /** - * @param int[] $ids - */ - public static function _deleteMultipleSmilies(array $ids = []): void - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - $smilies = self::_getSmiliesById($ids); - - if ($smilies === []) { - return; - } - - $sql_parts = []; - - foreach ($smilies as $s) { - unlink($s['smiley_fullpath']); - $sql_parts[] = 'smiley_id = ' . $ilDB->quote($s['smiley_id'], 'integer'); - } - - $ilDB->manipulate('DELETE FROM chatroom_smilies WHERE ' . implode(' OR ', $sql_parts)); - } - - /** - * @param int[] $ids - * @return array{smiley_id: int, smiley_keywords: string, smiley_path: string, smiley_fullpath: string}[] - */ - public static function _getSmiliesById(array $ids = []): array - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - if ($ids === []) { - return []; - } - - $sql = 'SELECT smiley_id, smiley_keywords, smiley_path FROM chatroom_smilies WHERE '; - - $sql_parts = []; - foreach ($ids as $id) { - $sql_parts[] = "smiley_id = " . $ilDB->quote($id, "integer"); - } - - $sql .= implode(" OR ", $sql_parts); - $res = $ilDB->query($sql); - $result = []; - - while ($row = $ilDB->fetchAssoc($res)) { - $result[] = [ - 'smiley_id' => (int) $row['smiley_id'], - 'smiley_keywords' => $row['smiley_keywords'], - 'smiley_path' => $row['smiley_path'], - 'smiley_fullpath' => ilFileUtils::getWebspaceDir() . '/chatroom/smilies/' . $row['smiley_path'] - ]; - } - - return $result; - } - - /** - * Updates smiley in DB by keyword and id from given array - * ($data["smiley_keywords"], $data["smiley_id"]) - * @param array{smiley_id: int, smiley_keywords: string, smiley_path?: string, smiley_fullpath?: string} $data - */ - public static function _updateSmiley(array $data): void - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - $ilDB->manipulateF( - 'UPDATE chatroom_smilies SET smiley_keywords = %s WHERE smiley_id = %s', - ['text', 'integer'], - [$data['smiley_keywords'], $data['smiley_id']] - ); - - if (isset($data["smiley_path"])) { - $sm = self::_getSmiley($data["smiley_id"]); - unlink($sm["smiley_fullpath"]); - $ilDB->manipulateF( - 'UPDATE chatroom_smilies SET smiley_path = %s WHERE smiley_id = %s', - ['text', 'integer'], - [$data['smiley_path'], $data['smiley_id']] - ); - } - } - - /** - * @return array{smiley_id: int, smiley_keywords: string, smiley_path: string, smiley_fullpath: string} - */ - public static function _getSmiley(int $a_id): array - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - $res = $ilDB->queryF( - 'SELECT smiley_id, smiley_keywords, smiley_path FROM chatroom_smilies WHERE smiley_id = %s ', - ['integer'], - [$a_id] - ); - - if ($row = $ilDB->fetchAssoc($res)) { - return [ - 'smiley_id' => (int) $row['smiley_id'], - 'smiley_keywords' => $row['smiley_keywords'], - 'smiley_path' => $row['smiley_path'], - 'smiley_fullpath' => ilFileUtils::getWebspaceDir() . '/chatroom/smilies/' . $row['smiley_path'] - ]; - } - - throw new OutOfBoundsException("Smiley with id $a_id not found"); - } - - public static function getSmiliesBasePath(): string - { - return 'chatroom/smilies'; - } - - public static function _deleteSmiley(int $a_id): void - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - try { - $smiley = self::_getSmiley($a_id); - $path = ilFileUtils::getWebspaceDir() . '/chatroom/smilies/' . $smiley['smiley_path']; - - if (is_file($path)) { - unlink($path); - } - - $ilDB->manipulateF( - 'DELETE FROM chatroom_smilies WHERE smiley_id = %s', - ['integer'], - [$a_id] - ); - } catch (Exception) { - } - } - - /** - * Stores smiley with given keywords and path in database. - */ - public static function _storeSmiley(string $keywords, string $path): void - { - global $DIC; - - /** @var ilDBInterface $ilDB */ - $ilDB = $DIC->database(); - - $stmt = $ilDB->prepareManip( - 'INSERT INTO chatroom_smilies (smiley_id, smiley_keywords, smiley_path) VALUES (?, ?, ?)', - ['integer', 'text', 'text'] - ); - $ilDB->execute($stmt, [ - $ilDB->nextId('chatroom_smilies'), - $keywords, - $path - ]); - } - - /** - * Trims given keywords and returns them in one array. - * @return string[] - */ - public static function _prepareKeywords(string $words): array - { - return array_filter(array_map('trim', explode("\n", $words))); - } -} diff --git a/Modules/Chatroom/classes/class.ilChatroomSmiliesCurrentSmileyFormElement.php b/Modules/Chatroom/classes/class.ilChatroomSmiliesCurrentSmileyFormElement.php deleted file mode 100644 index 2da58f2b926c..000000000000 --- a/Modules/Chatroom/classes/class.ilChatroomSmiliesCurrentSmileyFormElement.php +++ /dev/null @@ -1,58 +0,0 @@ - - * @version $Id$ - * @ingroup ModulesChatroom - */ -class ilChatroomSmiliesCurrentSmileyFormElement extends ilCustomInputGUI -{ - private string $value = ''; - - public function getHtml(): string - { - global $DIC; - - $tpl = new ilTemplate("tpl.chatroom_current_smiley_image.html", true, true, "Modules/Chatroom"); - $tpl->setVariable("IMAGE_ALT", $DIC->language()->txt("chatroom_current_smiley_image")); - $tpl->setVariable("IMAGE_PATH", $this->value); - - return $tpl->get(); - } - - public function getValue(): string - { - return $this->value; - } - - public function setValue(string $a_value): void - { - $this->value = $a_value; - } - - public function checkInput(): bool - { - return true; - } -} diff --git a/Modules/Chatroom/classes/class.ilChatroomSmiliesGUI.php b/Modules/Chatroom/classes/class.ilChatroomSmiliesGUI.php deleted file mode 100644 index b0928ae74df2..000000000000 --- a/Modules/Chatroom/classes/class.ilChatroomSmiliesGUI.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @version $Id$ - * @ingroup ModulesChatroom - */ -class ilChatroomSmiliesGUI -{ - public static function _getExistingSmiliesTable( - ilChatroomObjectGUI $a_ref, - \ILIAS\UI\Factory $ui_factory, - \ILIAS\UI\Renderer $ui_renderer, - ilRbacSystem $rbac_system - ): string { - $table = new ilChatroomSmiliesTableGUI( - $a_ref, - $ui_factory, - $ui_renderer, - $rbac_system, - 'smiley' - ); - $values = ilChatroomSmilies::_getSmilies(); - $table->setData($values); - - return $table->getHTML(); - } -} diff --git a/Modules/Chatroom/classes/class.ilChatroomSmiliesTableGUI.php b/Modules/Chatroom/classes/class.ilChatroomSmiliesTableGUI.php deleted file mode 100644 index 2f9ca61d73ca..000000000000 --- a/Modules/Chatroom/classes/class.ilChatroomSmiliesTableGUI.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @version $Id$ - * @ingroup ModulesChatroom - */ -class ilChatroomSmiliesTableGUI extends ilTable2GUI -{ - public function __construct( - private readonly ilChatroomObjectGUI $gui, - private readonly \ILIAS\UI\Factory $ui_factory, - private readonly \ILIAS\UI\Renderer $ui_renderer, - private readonly ilRbacSystem $rbac_system, - string $cmd - ) { - $this->setId('chatroom_smilies_tbl'); - parent::__construct($gui, $cmd); - - $this->setTitle($this->lng->txt('chatroom_available_smilies')); - - $this->addColumn('', 'checkbox', '2%', true); - $this->addColumn($this->lng->txt('chatroom_smiley_image'), '', '28%'); - $this->addColumn($this->lng->txt('chatroom_smiley_keyword'), 'keyword', '55%'); - $this->addColumn($this->lng->txt('actions'), '', '15%'); - - $this->setFormAction($this->ctrl->getFormAction($this->gui)); - $this->setRowTemplate('tpl.chatroom_smiley_list_row.html', 'Modules/Chatroom'); - $this->setSelectAllCheckbox('smiley_id'); - - if ($this->rbac_system->checkAccess('write', $this->gui->getRefId())) { - $this->addMultiCommand( - 'smiley-deleteMultipleObject', - $this->lng->txt('chatroom_delete_selected') - ); - } - } - - protected function fillRow(array $a_set): void - { - $this->tpl->setVariable('VAL_SMILEY_ID', $a_set['smiley_id']); - $this->tpl->setVariable('VAL_SMILEY_PATH', $a_set['smiley_fullpath']); - $this->tpl->setVariable('VAL_SMILEY_KEYWORDS', $a_set['smiley_keywords']); - $this->tpl->setVariable( - 'VAL_SMILEY_KEYWORDS_NONL', - str_replace("\n", "", $a_set['smiley_keywords']) - ); - - if ($this->rbac_system->checkAccess('write', $this->gui->getRefId())) { - $buttons = []; - - $this->ctrl->setParameter($this->gui, 'smiley_id', $a_set['smiley_id']); - $buttons[] = $this->ui_factory - ->button() - ->shy( - $this->lng->txt('edit'), - $this->ctrl->getLinkTarget($this->gui, 'smiley-showEditSmileyEntryFormObject') - ); - $buttons[] = $this->ui_factory - ->button() - ->shy( - $this->lng->txt('delete'), - $this->ctrl->getLinkTarget($this->gui, 'smiley-showDeleteSmileyFormObject') - ); - $this->ctrl->setParameter($this->gui, 'smiley_id', null); - - $drop_down = $this->ui_factory - ->dropdown() - ->standard($buttons) - ->withLabel($this->lng->txt('actions')); - - $this->tpl->setVariable('VAL_ACTIONS', $this->ui_renderer->render($drop_down)); - } - } -} diff --git a/Modules/Chatroom/classes/class.ilChatroomTabGUIFactory.php b/Modules/Chatroom/classes/class.ilChatroomTabGUIFactory.php index 1c34978c46ca..1f78d83a6dac 100644 --- a/Modules/Chatroom/classes/class.ilChatroomTabGUIFactory.php +++ b/Modules/Chatroom/classes/class.ilChatroomTabGUIFactory.php @@ -86,11 +86,6 @@ public function getAdminTabsForCommand(string $command): void ] ] ], - 'smiley' => [ - 'lng' => 'smiley', - 'link' => $DIC->ctrl()->getLinkTargetByClass(ilObjChatroomAdminGUI::class, 'smiley'), - 'permission' => 'read' - ] ]; $DIC->ctrl()->setParameterByClass(ilObjChatroomGUI::class, 'ref_id', $public_room_ref); diff --git a/Modules/Chatroom/classes/class.ilObjChatroomAccess.php b/Modules/Chatroom/classes/class.ilObjChatroomAccess.php index 5ff99e4c45e7..35c58c8b3256 100644 --- a/Modules/Chatroom/classes/class.ilObjChatroomAccess.php +++ b/Modules/Chatroom/classes/class.ilObjChatroomAccess.php @@ -147,10 +147,6 @@ public static function lookupOnline(int $a_obj_id): bool public function canBeDelivered(ilWACPath $ilWACPath): bool { - if (preg_match("/chatroom\\/smilies\\//ui", $ilWACPath->getPath())) { - return true; - } - return false; } } diff --git a/Modules/Chatroom/classes/gui/class.ilChatroomViewGUI.php b/Modules/Chatroom/classes/gui/class.ilChatroomViewGUI.php index b08ded48bb13..36ebf8faa196 100644 --- a/Modules/Chatroom/classes/gui/class.ilChatroomViewGUI.php +++ b/Modules/Chatroom/classes/gui/class.ilChatroomViewGUI.php @@ -143,37 +143,6 @@ private function showRoom(ilChatroom $room, ilChatroomUser $chat_user): void 'broadcast_typing' => $chat_user->enabledBroadcastTyping(), ]; - $smileys = []; - - if ($settings->getSmiliesEnabled()) { - $smileys_array = ilChatroomSmilies::_getSmilies(); - foreach ($smileys_array as $smiley_array) { - $new_keys = []; - $new_val = ''; - foreach ($smiley_array as $key => $value) { - if ($key === 'smiley_keywords') { - $new_keys = explode("\n", $value); - } - - if ($key === 'smiley_fullpath') { - $new_val = $value; - } - } - - if (!$new_keys || !$new_val) { - continue; - } - - foreach ($new_keys as $new_key) { - $smileys[$new_key] = $new_val; - } - } - - $initial->smileys = $smileys; - } else { - $initial->smileys = '{}'; - } - $initial->messages = []; $roomTpl = new ilTemplate('tpl.chatroom.html', true, true, 'Modules/Chatroom'); diff --git a/Modules/Chatroom/js/chat.js b/Modules/Chatroom/js/chat.js index fb862082406d..ac4746270ece 100644 --- a/Modules/Chatroom/js/chat.js +++ b/Modules/Chatroom/js/chat.js @@ -627,8 +627,7 @@ } var messageSpan = $(''); - messageSpan.text(messageSpan.text(content).text()) - .html(il.Chatroom.getSmileys().replace(messageSpan.text())); + messageSpan.text(messageSpan.text(content).text()); line.append($(':')) .append(messageSpan); diff --git a/Modules/Chatroom/js/iliaschat.jquery.js b/Modules/Chatroom/js/iliaschat.jquery.js index 8f3c013df440..fa8771948701 100644 --- a/Modules/Chatroom/js/iliaschat.jquery.js +++ b/Modules/Chatroom/js/iliaschat.jquery.js @@ -13,7 +13,6 @@ serverConnector, logger, messageOptions, - smileys, iliasConnector, chatActions; @@ -190,106 +189,6 @@ }; ProfileImageLoader._imagesByUserId = {}; - /** - * This class renders the smiley selection for ChatActions. - * It also replaces all smileys in a chat messages. - * - * @params {array} _smileys - * @constructor - */ - const Smileys = function Smileys(_smileys) { - /** - * Sets smileys into text - * - * @param {string} message - * @returns {string} - */ - this.replace = function (message) { - if (typeof _smileys == "string") { - return message; - } - - for (let i in _smileys) { - while (message.indexOf(i) != -1) { - message = message.replace(i, ''); - } - } - - return message; - }; - - this.render = function () { - if (typeof _smileys == "object") { - if (_smileys.length == 0) { - return; - } - // Emoticons - const $emoticons_flyout_trigger = $(''), - $emoticons_flyout = $('
'), - $emoticons_panel = $('
') - .append($emoticons_flyout_trigger) - .append($emoticons_flyout); - - $("#submit_message_text").css("paddingLeft", "25px").after($emoticons_panel); - - $emoticons_panel.css("top", "3px"); - - const $emoticons_table = $("
"), - emoticonMap = new Object(); - - let $emoticons_row = null, - cnt = 0; - - for (let i in _smileys) { - let $emoticon; - - if (emoticonMap[_smileys[i]]) { - $emoticon = emoticonMap[_smileys[i]]; - } else { - if (cnt % 6 == 0) { - $emoticons_row = $(""); - $emoticons_table.append($emoticons_row); - } - - $emoticon = $(''); - $emoticon.data("emoticon", i); - $emoticons_row.append($('').append($('').append($emoticon))); - - emoticonMap[_smileys[i]] = $emoticon; - ++cnt; - } - - $emoticon.attr({ - alt: [$emoticon.attr('alt').toString(), i].join(' '), - title: [$emoticon.attr('title').toString(), i].join(' ') - }); - } - $emoticons_flyout.append($emoticons_table); - - $emoticons_flyout_trigger.on('click', function (e) { - $emoticons_flyout.toggle(); - - if ($(this).hasClass("active")) { - $(this).removeClass("active"); - } else { - $(this).addClass("active"); - } - }); - - $emoticons_panel.on('clickoutside', function (event) { - if ($emoticons_flyout_trigger.hasClass("active")) { - $emoticons_flyout_trigger.click(); - } - }); - - $("#iosChatEmoticonsPanelFlyout a").click(function () { - $emoticons_flyout_trigger.click(); - $("#submit_message_text").insertAtCaret($(this).find('img').data("emoticon")); - }); - } - }; - }; - /** * This class renders the chat gui and manages all gui actions. * @@ -1483,8 +1382,6 @@ var ILIASResponseHandler = function ILIASResponseHandler() { }); - smileys.render(); - // Insert Chatheader into HTML next to AKTION-Button gui.renderHeaderAndActionButton(); // When private rooms are disabled, dont show chat header @@ -1606,16 +1503,12 @@ var ILIASResponseHandler = function ILIASResponseHandler() { logger = new Logger(); translation = new Translation(lang); - smileys = new Smileys(initial.smileys); $("#" + appDomElementId).chat(baseurl, instance); }, leavePrivateRoom: function () { iliasConnector.leavePrivateRoom(); }, - getSmileys: function () { - return smileys; - }, getUserInfo: function() { return personalUserInfo; }, diff --git a/Modules/Chatroom/templates/default/style.css b/Modules/Chatroom/templates/default/style.css index 865fb5b29465..92b82162e32d 100644 --- a/Modules/Chatroom/templates/default/style.css +++ b/Modules/Chatroom/templates/default/style.css @@ -173,63 +173,10 @@ h2.current_room_title { position: relative; } -#iosChatEmoticonsPanel { - position: absolute; - left: 16px; - top: 1px; - display: block; - height: 19px; - width: 19px; -} - -#iosChatEmoticonsPanel > a { - display: block; - height: 19px; - width: 19px; - background: url("./images/emoticons_trigger.png") no-repeat 1px 2px; - position: relative; - z-index: 1; - border-left: 1px solid #FFFFFF; -} - -#iosChatEmoticonsPanel > a:hover, #iosChatEmoticonsPanel > a.active { - background-color: #6D84B4; - border-bottom: 1px solid #6D84B6; - border-left: 1px solid #3B5998; - border-right: 1px solid #3B5998; - border-top: none; -} - -#iosChatEmoticonsPanelFlyout { - position: absolute; - background-color: white; - border: 1px solid gray; - padding: 5px; - border-bottom: 2px solid #293E6A; - bottom: 19px; - display: none; -} - -#iosChatEmoticonsPanelFlyout a { - border: 1px solid white; - display: block; - padding: 1px 0 1px 2px; -} - -#iosChatEmoticonsPanelFlyout a:hover { - border: 1px solid silver; -} - - .ilNoDisplayChat { display: none; } -#iosChatEmoticonsPanel img, .messageLine img { - max-width: 24px; - max-height: 24px; -} - #message_recipient_info { word-wrap: normal; } diff --git a/Modules/Chatroom/templates/default/tpl.chatroom_edit_smilies.html b/Modules/Chatroom/templates/default/tpl.chatroom_edit_smilies.html deleted file mode 100644 index 742a728372f9..000000000000 --- a/Modules/Chatroom/templates/default/tpl.chatroom_edit_smilies.html +++ /dev/null @@ -1,7 +0,0 @@ - -
{SMILEY_TABLE}
-
- - -
{SMILEY_FORM}
- \ No newline at end of file diff --git a/Modules/Chatroom/templates/default/tpl.chatroom_smiley_line.html b/Modules/Chatroom/templates/default/tpl.chatroom_smiley_line.html deleted file mode 100644 index 9243dc22bfc9..000000000000 --- a/Modules/Chatroom/templates/default/tpl.chatroom_smiley_line.html +++ /dev/null @@ -1 +0,0 @@ -{SMILEY_ALT} \ No newline at end of file diff --git a/Modules/Chatroom/templates/default/tpl.chatroom_smiley_list_row.html b/Modules/Chatroom/templates/default/tpl.chatroom_smiley_list_row.html deleted file mode 100644 index 24f9128e75f2..000000000000 --- a/Modules/Chatroom/templates/default/tpl.chatroom_smiley_list_row.html +++ /dev/null @@ -1,6 +0,0 @@ - - - Smiley: {VAL_SMILEY_KEYWORDS_NONL} - {VAL_SMILEY_KEYWORDS} - {VAL_ACTIONS} - diff --git a/Modules/Chatroom/test/class.ilChatroomServerSettingsTest.php b/Modules/Chatroom/test/class.ilChatroomServerSettingsTest.php index 67617936c8b6..3d6dfd5269c6 100644 --- a/Modules/Chatroom/test/class.ilChatroomServerSettingsTest.php +++ b/Modules/Chatroom/test/class.ilChatroomServerSettingsTest.php @@ -53,8 +53,6 @@ public function setterAndGettersProvider(): array ['clientUrl', $assertIsString, 'http://proxy.localhost'], ['iliasUrlEnabled', $assertIsBool, true], ['iliasUrl', $assertIsString, 'http://proxy.localhost'], - ['smiliesEnabled', $assertIsBool, false], - //@TODO Remove this properties ['instance', $assertIsString, '123456'], ]; diff --git a/Modules/ContentPage/classes/class.ilObjContentPageGUI.php b/Modules/ContentPage/classes/class.ilObjContentPageGUI.php index 0225e9d3a8a0..09869067669f 100644 --- a/Modules/ContentPage/classes/class.ilObjContentPageGUI.php +++ b/Modules/ContentPage/classes/class.ilObjContentPageGUI.php @@ -36,7 +36,6 @@ * @ilCtrl_Calls ilObjContentPageGUI: ilLearningProgressGUI * @ilCtrl_Calls ilObjContentPageGUI: ilCommonActionDispatcherGUI * @ilCtrl_Calls ilObjContentPageGUI: ilContentPagePageGUI - * @ilCtrl_Calls ilObjContentPageGUI: ilObjectCustomIconConfigurationGUI * @ilCtrl_Calls ilObjContentPageGUI: ilObjectContentStyleSettingsGUI * @ilCtrl_Calls ilObjContentPageGUI: ilObjectTranslationGUI * @ilCtrl_Calls ilObjContentPageGUI: ilPageMultiLangGUI @@ -365,19 +364,6 @@ public function executeCommand(): void $this->ctrl->forwardCommand($gui); break; - case strtolower(ilObjectCustomIconConfigurationGUI::class): - if (!$this->checkPermissionBool('write') || !$this->settings->get('custom_icons', '0')) { - $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE); - } - - $this->prepareOutput(); - $this->tabs_gui->activateTab(self::UI_TAB_ID_SETTINGS); - $this->setSettingsSubTabs(self::UI_TAB_ID_ICON); - - $gui = new ilObjectCustomIconConfigurationGUI($this->dic, $this, $this->object); - $this->ctrl->forwardCommand($gui); - break; - case strtolower(ilObjectCopyGUI::class): $this->tpl->loadStandardTemplate(); @@ -450,14 +436,6 @@ protected function setSettingsSubTabs(string $activeTab): void $this->ctrl->getLinkTarget($this, self::UI_CMD_EDIT) ); - if ($this->settings->get('custom_icons', '0')) { - $this->tabs_gui->addSubTab( - self::UI_TAB_ID_ICON, - $this->lng->txt('icon_settings'), - $this->ctrl->getLinkTargetByClass(ilObjectCustomIconConfigurationGUI::class) - ); - } - $this->tabs_gui->addSubTab( self::UI_TAB_ID_STYLE, $this->lng->txt('cont_style'), @@ -588,6 +566,7 @@ protected function initEditCustomForm(ilPropertyFormGUI $a_form): void $presentationHeader->setTitle($this->lng->txt('settings_presentation_header')); $a_form->addItem($presentationHeader); + $this->object_service->commonSettings()->legacyForm($a_form, $this->object)->addIcon(); $this->object_service->commonSettings()->legacyForm($a_form, $this->object)->addTileImage(); $sh = new ilFormSectionHeaderGUI(); @@ -632,6 +611,7 @@ protected function updateCustom(ilPropertyFormGUI $form): void ilObjectServiceSettingsGUI::INFO_TAB_VISIBILITY ] ); + $this->object_service->commonSettings()->legacyForm($form, $this->object)->saveIcon(); $this->object_service->commonSettings()->legacyForm($form, $this->object)->saveTileImage(); } diff --git a/Modules/ContentPage/interfaces/interface.ilContentPageObjectConstants.php b/Modules/ContentPage/interfaces/interface.ilContentPageObjectConstants.php index aab408c54ab5..424150389a47 100644 --- a/Modules/ContentPage/interfaces/interface.ilContentPageObjectConstants.php +++ b/Modules/ContentPage/interfaces/interface.ilContentPageObjectConstants.php @@ -42,7 +42,6 @@ interface ilContentPageObjectConstants public const UI_TAB_ID_CONTENT = 'content'; public const UI_TAB_ID_INFO = 'info_short'; public const UI_TAB_ID_SETTINGS = 'settings'; - public const UI_TAB_ID_ICON = 'icon'; public const UI_TAB_ID_STYLE = 'style'; public const UI_TAB_ID_I18N = 'i18n'; public const UI_TAB_ID_LP = 'learning_progress'; diff --git a/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterialAssignmentTableGUI.php b/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterialAssignmentTableGUI.php index 50bd54d9b64f..dac711fcd14a 100644 --- a/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterialAssignmentTableGUI.php +++ b/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterialAssignmentTableGUI.php @@ -1,6 +1,5 @@ @@ -36,6 +37,7 @@ public function __construct(object $a_parent_obj, ilObject $a_course_obj, int $a $this->objectDefinition = $DIC['objDefinition']; $this->objective_id = $a_objective_id; + $this->setId('tbl_crs_obj_mat_assignment'); parent::__construct($a_parent_obj, 'materialAssignment'); $this->lng->loadLanguageModule('crs'); @@ -46,7 +48,7 @@ public function __construct(object $a_parent_obj, ilObject $a_course_obj, int $a $this->setFormAction($this->ctrl->getFormAction($a_parent_obj)); $this->setRowTemplate("tpl.crs_objective_list_materials_row.html", "Modules/Course"); $this->setDefaultOrderField('title'); - $this->setLimit(200); + $this->setShowRowsSelector(true); $this->setNoEntriesText($this->lng->txt('crs_no_objective_lms_found')); $this->addCommandButton('updateMaterialAssignment', $this->lng->txt('crs_wiz_next')); $this->initObjectiveAssignments(); diff --git a/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterials.php b/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterials.php index fbea60a3480f..b4ceb26ac6cd 100644 --- a/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterials.php +++ b/Modules/Course/classes/Objectives/class.ilCourseObjectiveMaterials.php @@ -1,7 +1,5 @@ @@ -293,6 +293,26 @@ public function add(): int return $next_id; } + public function deleteMaterial(int $ref_id, int $obj_id): bool + { + $query = "DELETE FROM crs_objective_lm " . + "WHERE objective_id = " . $this->db->quote($this->getObjectiveId(), 'integer') . " " . + "AND ref_id = " . $this->db->quote($ref_id, 'integer') . " " . + "AND obj_id = " . $this->db->quote($obj_id, 'integer'); + $this->db->manipulate($query); + return true; + } + + public function isMaterialAssigned(int $ref_id, int $obj_id): bool + { + $query = "SELECT * FROM crs_objective_lm " . + "WHERE ref_id = " . $this->db->quote($ref_id, 'integer') . " " . + "AND obj_id = " . $this->db->quote($obj_id, 'integer') . " " . + "AND objective_id = " . $this->db->quote($this->getObjectiveId(), 'integer') . " "; + $res = $this->db->query($query); + return (bool) $res->numRows(); + } + public function delete(int $lm_id): bool { if (!$lm_id) { diff --git a/Modules/Course/classes/Objectives/class.ilCourseObjectivesGUI.php b/Modules/Course/classes/Objectives/class.ilCourseObjectivesGUI.php index ee1573530b03..53afb77b5599 100644 --- a/Modules/Course/classes/Objectives/class.ilCourseObjectivesGUI.php +++ b/Modules/Course/classes/Objectives/class.ilCourseObjectivesGUI.php @@ -1,7 +1,5 @@ tpl->setContent($table->getHTML()); } + /** + * @return int[] + */ + private function getIntArrayFromPost(string $key): array + { + if ($this->http->wrapper()->post()->has($key)) { + return $this->http->wrapper()->post()->retrieve( + $key, + $this->refinery->kindlyTo()->listOf( + $this->refinery->kindlyTo()->int() + ) + ); + } + return []; + } + + /** + * @return string[] + */ + private function getStringArrayFromPost(string $key): array + { + if ($this->http->wrapper()->post()->has($key)) { + return $this->http->wrapper()->post()->retrieve( + $key, + $this->refinery->kindlyTo()->listOf( + $this->refinery->kindlyTo()->string() + ) + ); + } + return []; + } + protected function updateMaterialAssignment(): void { if (!$this->access->checkAccess('write', '', $this->course_obj->getRefId())) { @@ -410,38 +442,36 @@ protected function updateMaterialAssignment(): void } $this->__initLMObject($this->initObjectiveIdFromQuery()); - $this->objectives_lm_obj->deleteAll(); - $materials = []; - if ($this->http->wrapper()->post()->has('materials')) { - $materials = $this->http->wrapper()->post()->retrieve( - 'materials', - $this->refinery->kindlyTo()->listOf( - $this->refinery->kindlyTo()->int() - ) - ); - } - foreach ($materials as $node_id) { - $obj_id = $this->objectDataCache->lookupObjId((int) $node_id); - $type = $this->objectDataCache->lookupType($obj_id); + $visibleMaterials = $this->getIntArrayFromPost('visible_materials'); + $visibleChapters = $this->getStringArrayFromPost('visible_chapters'); + $materials = $this->getIntArrayFromPost('materials'); + $chapters = $this->getStringArrayFromPost('chapters'); + foreach ($visibleMaterials as $node_id) { + $obj_id = $this->objectDataCache->lookupObjId((int) $node_id); + if (!in_array($node_id, $materials)) { + $this->objectives_lm_obj->deleteMaterial($node_id, $obj_id); + continue; + } + if ($this->objectives_lm_obj->isMaterialAssigned($node_id, $obj_id)) { + continue; + } $this->objectives_lm_obj->setLMRefId($node_id); $this->objectives_lm_obj->setLMObjId($obj_id); - $this->objectives_lm_obj->setType($type); + $this->objectives_lm_obj->setType($this->objectDataCache->lookupType($obj_id)); $this->objectives_lm_obj->add(); } - $chapters = []; - if ($this->http->wrapper()->post()->has('chapters')) { - $chapters = $this->http->wrapper()->post()->retrieve( - 'chapters', - $this->refinery->kindlyTo()->listOf( - $this->refinery->kindlyTo()->string() - ) - ); - } - foreach ($chapters as $chapter) { - list($ref_id, $chapter_id) = explode('_', $chapter); + foreach ($visibleChapters as $chapter) { + list($ref_id, $chapter_id) = explode('_', $chapter); + if (!in_array($chapter, $chapters)) { + $this->objectives_lm_obj->deleteMaterial($ref_id, $chapter_id); + continue; + } + if ($this->objectives_lm_obj->isMaterialAssigned($ref_id, $chapter_id)) { + continue; + } $this->objectives_lm_obj->setLMRefId($ref_id); $this->objectives_lm_obj->setLMObjId($chapter_id); $this->objectives_lm_obj->setType(ilLMObject::_lookupType($chapter_id)); diff --git a/Modules/Course/classes/class.ilCourseParticipantsGroupsGUI.php b/Modules/Course/classes/class.ilCourseParticipantsGroupsGUI.php index ffd52ad453bd..6ef4eada4a1f 100644 --- a/Modules/Course/classes/class.ilCourseParticipantsGroupsGUI.php +++ b/Modules/Course/classes/class.ilCourseParticipantsGroupsGUI.php @@ -166,11 +166,11 @@ protected function add(): void $this->refinery->kindlyTo()->int() ); } - $usr_ids = 0; + $usr_ids = []; if ($this->http->wrapper()->post()->has('usrs')) { $usr_ids = $this->http->wrapper()->post()->retrieve( 'usrs', - $this->refinery->kindlyTo()->int() + $this->refinery->kindlyTo()->dictOf($this->refinery->kindlyTo()->int()) ); } diff --git a/Modules/Course/classes/class.ilObjCourse.php b/Modules/Course/classes/class.ilObjCourse.php index a8bdaeba132c..ada533d9335a 100755 --- a/Modules/Course/classes/class.ilObjCourse.php +++ b/Modules/Course/classes/class.ilObjCourse.php @@ -1,4 +1,5 @@ increment(IL_CAL_DAY, -1); $now = $before->get(IL_CAL_UNIX); $now_dt = $before->get(IL_CAL_DATETIME, '', ilTimeZone::UTC); diff --git a/Modules/Course/classes/class.ilObjCourseAdministrationGUI.php b/Modules/Course/classes/class.ilObjCourseAdministrationGUI.php index be4dc91b9542..232aaba111fc 100644 --- a/Modules/Course/classes/class.ilObjCourseAdministrationGUI.php +++ b/Modules/Course/classes/class.ilObjCourseAdministrationGUI.php @@ -1,6 +1,5 @@ @@ -25,6 +26,8 @@ */ class ilObjCourseAdministrationGUI extends ilMembershipAdministrationGUI { + private const SETTING_COURSES_AND_GROUPS_ENABLED = 'mmbr_my_crs_grp'; + protected function getType(): string { return "crss"; @@ -39,4 +42,31 @@ protected function getAdministrationFormId(): int { return ilAdministrationSettingsFormHandler::FORM_COURSE; } + + protected function addChildContentsTo(ilPropertyFormGUI $form): ilPropertyFormGUI + { + $checkBox = new ilCheckboxInputGUI($this->lng->txt('crs_my_courses_groups_enabled'), self::SETTING_COURSES_AND_GROUPS_ENABLED); + $checkBox->setInfo($this->lng->txt('crs_my_courses_groups_enabled_info')); + $checkBox->setChecked((bool) $this->settings->get(self::SETTING_COURSES_AND_GROUPS_ENABLED, 1)); + $form->addItem($checkBox); + return $form; + } + + protected function saveChildSettings(ilPropertyFormGUI $form): void + { + $this->settings->set(self::SETTING_COURSES_AND_GROUPS_ENABLED, (int) $form->getInput(self::SETTING_COURSES_AND_GROUPS_ENABLED)); + } + + protected function getChildSettingsInfo(int $a_form_id): array + { + switch ($a_form_id) { + case ilAdministrationSettingsFormHandler::FORM_GROUP: + $this->lng->loadLanguageModule("crs"); + $fields = [ + 'crs_my_courses_groups_enabled' => [ (bool) $this->settings->get(self::SETTING_COURSES_AND_GROUPS_ENABLED, 1), ilAdministrationSettingsFormHandler::VALUE_BOOL ] + ]; + return [ [ "editSettings", $fields ] ]; + } + return []; + } } diff --git a/Modules/Course/classes/class.ilObjCourseGUI.php b/Modules/Course/classes/class.ilObjCourseGUI.php index f9f755dc19ee..40f79415c05e 100755 --- a/Modules/Course/classes/class.ilObjCourseGUI.php +++ b/Modules/Course/classes/class.ilObjCourseGUI.php @@ -1,7 +1,5 @@ http = $DIC->http(); $this->refinery = $DIC->refinery(); + $this->news = $DIC->news(); } /** @@ -112,6 +115,7 @@ public function viewObject(): void $this->checkPermission('read', 'view'); if ($this->view_manager->isAdminView()) { parent::renderObject(); + $this->addAdoptContentLinkToToolbar(); return; } @@ -652,6 +656,7 @@ public function updateInfoObject(): void $file_info = $form->getInput('file'); $file_name = $form->getItemByPostVar('file')->getFilename(); + $file_name = ilFileUtils::getValidFilename($file_name); $file_obj = new ilCourseFile(); $file_obj->setCourseId($this->object->getId()); @@ -882,18 +887,7 @@ public function updateObject(): void ilObjectServiceSettingsGUI::updateServiceSettingsForm( $this->object->getId(), $form, - array( - ilObjectServiceSettingsGUI::CALENDAR_CONFIGURATION, - ilObjectServiceSettingsGUI::USE_NEWS, - ilObjectServiceSettingsGUI::AUTO_RATING_NEW_OBJECTS, - ilObjectServiceSettingsGUI::TAG_CLOUD, - ilObjectServiceSettingsGUI::CUSTOM_METADATA, - ilObjectServiceSettingsGUI::BADGES, - ilObjectServiceSettingsGUI::ORGU_POSITION_ACCESS, - ilObjectServiceSettingsGUI::SKILLS, - ilObjectServiceSettingsGUI::BOOKING, - ilObjectServiceSettingsGUI::EXTERNAL_MAIL_PREFIX - ) + $this->getSubServices() ); ilChangeEvent::_recordWriteEvent($this->object->getId(), $this->user->getId(), 'update'); @@ -916,6 +910,26 @@ public function updateObject(): void $this->afterUpdate(); } + protected function getSubServices(): array + { + $subs = array( + ilObjectServiceSettingsGUI::CALENDAR_CONFIGURATION, + ilObjectServiceSettingsGUI::AUTO_RATING_NEW_OBJECTS, + ilObjectServiceSettingsGUI::TAG_CLOUD, + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + ilObjectServiceSettingsGUI::BADGES, + ilObjectServiceSettingsGUI::ORGU_POSITION_ACCESS, + ilObjectServiceSettingsGUI::SKILLS, + ilObjectServiceSettingsGUI::BOOKING, + ilObjectServiceSettingsGUI::EXTERNAL_MAIL_PREFIX + ); + if ($this->news->isGloballyActivated()) { + $subs[] = ilObjectServiceSettingsGUI::USE_NEWS; + } + + return $subs; + } + protected function confirmLPSync(): void { $cgui = new ilConfirmationGUI(); @@ -1330,18 +1344,7 @@ protected function initEditForm(): ilPropertyFormGUI ilObjectServiceSettingsGUI::initServiceSettingsForm( $this->object->getId(), $form, - array( - ilObjectServiceSettingsGUI::CALENDAR_CONFIGURATION, - ilObjectServiceSettingsGUI::USE_NEWS, - ilObjectServiceSettingsGUI::AUTO_RATING_NEW_OBJECTS, - ilObjectServiceSettingsGUI::TAG_CLOUD, - ilObjectServiceSettingsGUI::CUSTOM_METADATA, - ilObjectServiceSettingsGUI::BADGES, - ilObjectServiceSettingsGUI::ORGU_POSITION_ACCESS, - ilObjectServiceSettingsGUI::SKILLS, - ilObjectServiceSettingsGUI::BOOKING, - ilObjectServiceSettingsGUI::EXTERNAL_MAIL_PREFIX - ) + $this->getSubServices() ); $mem = new ilCheckboxInputGUI($this->lng->txt('crs_show_members'), 'show_members'); @@ -2575,7 +2578,7 @@ public function saveMapSettingsObject(): void $location = []; if ($this->http->wrapper()->post()->has('location')) { $custom_transformer = $this->refinery->custom()->transformation( - fn ($array) => $array + fn($array) => $array ); $location = $this->http->wrapper()->post()->retrieve( 'location', diff --git a/Modules/Course/module.xml b/Modules/Course/module.xml index de59ea3e5b9f..dde5c87857d5 100644 --- a/Modules/Course/module.xml +++ b/Modules/Course/module.xml @@ -39,6 +39,7 @@ + diff --git a/Modules/Course/templates/default/tpl.crs_objective_list_materials_row.html b/Modules/Course/templates/default/tpl.crs_objective_list_materials_row.html index 135ca7d2c6ec..433676ac2288 100644 --- a/Modules/Course/templates/default/tpl.crs_objective_list_materials_row.html +++ b/Modules/Course/templates/default/tpl.crs_objective_list_materials_row.html @@ -1,7 +1,8 @@ - + +