diff --git a/.github/workflows/test-acceptance.yml b/.github/workflows/test-acceptance.yml index 2c75f5738..3cecf345e 100644 --- a/.github/workflows/test-acceptance.yml +++ b/.github/workflows/test-acceptance.yml @@ -1,7 +1,9 @@ name: Acceptance Tests + on: push: pull_request: + jobs: test-acceptance: strategy: @@ -11,30 +13,27 @@ jobs: - image: docker.io/jrei/systemd-ubuntu:20.04 - image: docker.io/jrei/systemd-ubuntu:22.04 runs-on: ubuntu-latest + steps: - - name: Replace Docker with Podman Rootless - run: | - sudo apt-get -o Dpkg::Options::="--force-overwrite" install -y podman - echo -e "export XDG_RUNTIME_DIR=/tmp/${RUNNER_TEMP}" >> $GITHUB_ENV - echo -e "export XDG_DATA_HOME=/tmp/${RUNNER_TEMP}" >> $GITHUB_ENV - echo -e "export CONTAINERS_STORAGE_CONF=/tmp/${RUNNER_TEMP}/storage.conf" >> $GITHUB_ENV + - name: Replace Docker with Podman + run: sudo apt-get -o Dpkg::Options::="--force-overwrite" install -y podman-docker + - uses: actions/setup-go@v3 with: go-version: "^1.19" + - uses: actions/checkout@v3 + - name: Compile SaltStack bootstrap wrapper run: CGO_ENABLED=0 go build -ldflags "-s -w" -o ./salt-bootstrap salt-bootstrap.go working-directory: ./e107_tests/lib/ci/salt/ + - name: Launch test container - run: | - docker run -d --rm --name target -v .:/app/ ${{ matrix.operating_system.image }} tail -f /dev/null - sleep 5 - if ! docker ps | grep -q target; then - docker logs target - exit 1 - fi + run: docker run -d -it --rm --name target -v .:/app/ ${{ matrix.operating_system.image }} + - name: Install SaltStack run: docker exec target /app/e107_tests/lib/ci/salt/salt-bootstrap onedir + - name: Apply Salt state run: | ln -v -s master minion @@ -48,14 +47,18 @@ jobs: salt-call -c ./ --id=e107-dev --local state.apply e107-dev " working-directory: ./e107_tests/lib/ci/salt/ + - name: Install test dependencies run: | docker exec -w /app/e107_tests/ -e COMPOSER_ALLOW_SUPERUSER=1 target \ composer update --prefer-dist --no-progress + - name: Download Git submodule dependencies run: git submodule update --init --recursive --remote + - name: Install the CI test configuration file run: | ln -v -s -f ./lib/ci/config.acceptance.ci.yml ./e107_tests/config.yml + - name: Run acceptance tests run: docker exec -w /app/e107_tests/ target php ./vendor/bin/codecept run acceptance --steps \ No newline at end of file diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index c6e394dfa..878202633 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -163,8 +163,17 @@ jobs: --input ./e107_tests/tests/_output/coverage/codeclimate.json continue-on-error: true + - name: Set artifact name + id: set_artifact_name + run: | + TIMESTAMP=$(date +%Y%m%d%H%M%S) + INTERPRETER_IMAGE=$(echo "${{ matrix.interpreter.image }}" | sed 's/[:/]/_/g') + DB_IMAGE=$(echo "${{ matrix.db.image }}" | sed 's/[:/]/_/g') + ARTIFACT_NAME="tests_output_${{ github.run_id }}_${INTERPRETER_IMAGE}_${DB_IMAGE}_${TIMESTAMP}" + echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV + - name: Upload test output - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: - name: tests_output + name: ${{ env.ARTIFACT_NAME }} path: ./e107_tests/tests/_output/ diff --git a/README.md b/README.md index 9857ef5cf..155069e5f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![e107 Content Management System](https://e107.org/e107_images/logoHD.png)](https://e107.org) ================= -[![Supported PHP Versions](https://img.shields.io/badge/PHP-7.4,%208.0,%208.1,%208.2-blue)](https://github.com/e107inc/e107/) +[![Supported PHP Versions](https://img.shields.io/badge/PHP-7.4,%208.0,%208.1,%208.2,%208.3-blue)](https://github.com/e107inc/e107/) [![GitHub release](https://img.shields.io/github/v/release/e107inc/e107?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAQAAAD9CzEMAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfjDBwRCAhY3Q3XAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAA8hJREFUWMOtlltMVFcUhhcDGC+YalXSpI1Kqtg0jMVLTS9p0tcahkTb+GRi65MvfRWN+tL60kuqsU+mxtLYpIQOIBYhNJZYQY2RFrVoNWICioYWOpFhBqQw8/kwnH32Ppe5Mftp5uy1/3+t/19n7SOS5eIFDtNHhAh3OUaFFHaxkX709Q/bCwlfxRDONcXOwmXvhgeYZEch4IM+8ADP5l0FVTwyIPvoIVmwKlziHKJEhI+IG17sKJQ4dWqn1kGxM7/sH3rDi4gQYnJeQhFk0B9+ropY3lVQlS57H6Gyr8JlbZ1vZCgPu/2tzaKKzEIRdIhzIGNCtTnY7cp+f1aShhLxrN7u7Kz1rmI4s92ZreV9vqaDVo6w0V3F9Xgsnd2ugewQh5do0XanOU6JGTESOh8b87M7k7WUc801Sc9QbEb11jZORbyEcmXvEIe1XPcc1s2UmZGXa8PxUd3u7SJCGX+mhV/HPbV3m085wBP1v91N0RT/V79YVwufZIC/q/Z6KBcRoVq7IzpYYp64GDIovhQaNfjPHfCvavDdrPTsuPMsNU9d2hWeVh11Q7isQqO8nCb7FcZepfaV0e6s4vf+H629/4QuzZQtBvzfXtmr/QqDQvPi5tKuR03WzrBwQpPoakplR/Ye8CIi3Wu4rQk1R0HgwpkGG/FX4W3D5KuUu+BfVFm/wYfs4k2KUv9b12pVdLBEJFn6W/1POt5uEeG4QXGRzdxxZ882OpkGIMEl3k09barQqmhjVeP37TpWE6UiQjGn1KNZOrnvtpYaJow0YtR4VNGZaBu2Y1pYbJUe4DuAqUTvOS28W4Of9Piu86LoSDYr+IV6TxRxkjB1mjg9Spwadb2P8RVfMKKq2K0o7HOdyYP0adkbjXnTM3tr1j9OtTEbVAPP8rGi+EudbWU5pd4XzojL2pAGX6294RZFUqPo9xsfzrH9iwZviTPMZscQsShmLIoLq+kBznqIox3cwj7127b2CZtckTZFwqIYWMRe52RKc5Wr7B8S9Iyw3+QEe3L9dNym+n6IrSzwiapUbTHNe7kRtCn4Kk7Sa80oLaLk5waaWc+NuchjuRFsZRAYIhj/FoArJgWB0R/CAA1UcgtoYVmuIlXTxWvs08agfeGUUG91NEd5hW/Sdk4akhVE3cOcAPXa01nWSL6LMk4b8+cPPuAdwsazc/Y4z4eiSJu0XsscaXlRzE1aH/jFMv/lS3F23tnbQj07NU6UKBEiTDDOU6ZaWCSFWwT+PzoQf8Ad7jHA4Ez0dEHhU2vm9dhBGmgc+4y3sj/1HPOcQpNXqqPqAAAAAElFTkSuQmCC)](https://github.com/e107inc/e107/releases) [![GitHub Workflow "Unit Tests" Status](https://img.shields.io/github/actions/workflow/status/e107inc/e107/test-unit.yml?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAOCAQAAABnEe8CAAAAAnNCSVQICFXsRgQAAAAJcEhZcwAAA3cAAAN3Aa+SYCgAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAABG0lEQVQoFW3By0pUARgA4H8O05AQZWjkImjprr0LL7guJ3VcidAmkFZBi0AHDyNCtu4FeoF6hbQLw5CiKIX2BLWa0+jshj6P13Tq++KUfjWbDrTtWnUvrnAzjpmU2Vc14aGXdhwaizP6VNyKCFM6qirWNR2qe2ROT+Qk5qWKEeGO36peaxiWKBnx3u3IGVL3NE5Ztqei4breuOCut34ajnO2LfpoJMIDqWKEoucy2+7HX1rKMknkvPHZjF28cyMu01KWSSKn1y/8UVOIq2ypWjcaJzzRNhP/UrNn2lc9kVMwqKQU3fTLLHnlu3GJgiGfPFOIbh7rSE1b09T0xawXPrgW3ZQ1/ZAqm7Dgm5bZ+B99UhtaDmxZMRBdjgBnPOGTaoNcdgAAAABJRU5ErkJggg==)](https://github.com/e107inc/e107/actions) [![Code coverage](https://img.shields.io/codeclimate/coverage/e107inc/e107?logo=code-climate)](https://codeclimate.com/github/e107inc/e107/test_coverage) @@ -122,7 +122,6 @@ Having trouble getting e107 up and running? Something not working the way you th ## License -e107 is released under the terms and conditions of the GNU General Public License (http://www.gnu.org/licenses/gpl.txt) -This changed. +e107 is released under the terms and conditions of the GNU [General Public License](http://www.gnu.org/licenses/gpl.txt) [1]: https://e107.org diff --git a/class2.php b/class2.php index 7163f6a02..7b0dddb66 100755 --- a/class2.php +++ b/class2.php @@ -470,54 +470,24 @@ if(!empty($pref['redirectsiteurl']) && !empty($pref['siteurl'])) { } elseif(deftrue('e_DOMAIN')) { - // Find domain and port from user and from pref - list($urlbase,$urlport) = explode(':',$_SERVER['HTTP_HOST'].':'); - if(!$urlport) - { - $urlport = (int) $_SERVER['SERVER_PORT']; - } - if(!$urlport) - { - $urlport = 80; - } - $aPrefURL = explode('/',$pref['siteurl'],4); - if (count($aPrefURL) > 2) // we can do this -- there's at least http[s]://dom.ain/whatever - { - $PrefRoot = $aPrefURL[2]; - list($PrefSiteBase,$PrefSitePort) = explode(':',$PrefRoot.':'); - if (!$PrefSitePort) - { - $PrefSitePort = ( $aPrefURL[0] === 'https:' ) ? 443 : 80; // no port so set port based on 'scheme' - } + $location = e107::getRedirect()->host($_SERVER, $pref['siteurl'], ADMINDIR); - // Redirect only if - // -- ports do not match (http <==> https) - // -- base domain does not match (case-insensitive) - // -- NOT admin area - if (($urlport !== $PrefSitePort || stripos($PrefSiteBase, $urlbase) === false) && strpos(e_REQUEST_SELF, ADMINDIR) === false) - { - $aeSELF = explode('/', e_REQUEST_SELF, 4); - $aeSELF[0] = $aPrefURL[0]; // Swap in correct type of query (http, https) - $aeSELF[1] = ''; // Defensive code: ensure http:// not http:// - $aeSELF[2] = $aPrefURL[2]; // Swap in correct domain and possibly port - $location = implode('/',$aeSELF).($_SERVER['QUERY_STRING'] ? '?'.$_SERVER['QUERY_STRING'] : ''); - $location = filter_var($location, FILTER_SANITIZE_URL); - // - // header("Location: {$location}", true, 301); // send 301 header, not 302 + if($location) + { if(defined('e_DEBUG') && e_DEBUG === true) { - echo "DEBUG INFO: site-redirect preference enabled.
Redirecting to: ".$location. ''; - echo '
e_DOMAIN: ' .e_DOMAIN; - echo '
e_SUBDOMAIN: ' .e_SUBDOMAIN; + echo "DEBUG INFO: site-redirect preference enabled.
Redirecting to: " . $location . ""; + echo '
e_DOMAIN: ' . e_DOMAIN; + echo '
e_SUBDOMAIN: ' . e_SUBDOMAIN; } else { - e107::getRedirect()->go($location,true,301); + e107::getRedirect()->go($location, true, 301); // Issue 301 redirect } - exit(); - } + exit(); } + } } diff --git a/composer.lock b/composer.lock index 88f02596e..c4fdc8d65 100644 --- a/composer.lock +++ b/composer.lock @@ -262,16 +262,16 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "2.4-dev" - }, "laravel": { - "providers": [ - "Intervention\\Image\\ImageServiceProvider" - ], "aliases": { "Image": "Intervention\\Image\\Facades\\Image" - } + }, + "providers": [ + "Intervention\\Image\\ImageServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "2.4-dev" } }, "autoload": { @@ -318,16 +318,16 @@ }, { "name": "matthiasmullie/minify", - "version": "1.3.71", + "version": "1.3.73", "source": { "type": "git", "url": "https://github.com/matthiasmullie/minify.git", - "reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1" + "reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1", - "reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1", + "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/cb7a9297b4ab070909cefade30ee95054d4ae87a", + "reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a", "shasum": "" }, "require": { @@ -377,7 +377,7 @@ ], "support": { "issues": "https://github.com/matthiasmullie/minify/issues", - "source": "https://github.com/matthiasmullie/minify/tree/1.3.71" + "source": "https://github.com/matthiasmullie/minify/tree/1.3.73" }, "funding": [ { @@ -385,7 +385,7 @@ "type": "github" } ], - "time": "2023-04-25T20:33:03+00:00" + "time": "2024-03-15T10:27:10+00:00" }, { "name": "matthiasmullie/path-converter", @@ -442,16 +442,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.1", + "version": "v6.9.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18" + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", "shasum": "" }, "require": { @@ -511,7 +511,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" }, "funding": [ { @@ -519,7 +519,7 @@ "type": "github" } ], - "time": "2023-11-25T22:23:28+00:00" + "time": "2024-11-24T18:04:13+00:00" }, { "name": "psr/http-message", diff --git a/e107_admin/image.php b/e107_admin/image.php index ae28a9e25..15dd43bb3 100644 --- a/e107_admin/image.php +++ b/e107_admin/image.php @@ -873,39 +873,47 @@ class media_admin_ui extends e_admin_ui public $deleteConfirmScreen = true; public $deleteConfirmMessage = IMALAN_129; - protected $grid = array('id'=>'media_id', 'title'=>'media_name', 'image'=>'media_preview', 'body'=>'', 'class'=>'col-sm-6 col-md-4 col-lg-2', 'perPage'=>24, 'carousel'=>false); - + protected $grid = array('id'=>'media_id', 'title'=>'media_name', 'image'=>'media_preview', 'dimensions'=>'media_dimensions', 'body'=>'', 'class'=>'col-sm-6 col-md-4 col-lg-2', 'perPage'=>24, 'carousel'=>false); protected $preftabs = array(IMALAN_78,IMALAN_89, 'Youtube'); - - protected $fields = array( - 'checkboxes' => array('title'=> '', 'type' => null, 'data'=> null, 'width' =>'5%', 'forced'=> TRUE, 'thclass'=>'center', 'class'=>'center'), - 'media_id' => array('title'=> LAN_ID, 'type' => 'number', 'data'=> 'int', 'width' =>'5%', 'forced'=> TRUE, 'nolist'=>TRUE), - 'media_preview' => array('title'=> LAN_PREVIEW, 'type' => 'method', 'data'=>false, 'forced'=>true, 'width' => '110px', 'thclass' => 'center', 'class'=>'center'), - 'media_url' => array('title'=> IMALAN_110, 'type' => 'text', 'data'=> 'str', 'inline'=>false, 'thclass' => 'left', 'class'=>'left', 'width' => 'auto', 'writeParms'=>'size=xxlarge'), - 'media_category' => array('title'=> LAN_CATEGORY, 'type' => 'comma', 'inline'=>false, 'data'=> 'str', 'width' => '10%', 'filter' => true, 'batch' => true, 'class'=>'left'), - // Upload should be managed completely separately via upload-handler. - // 'media_upload' => array('title'=> "Upload File", 'type' => 'upload', 'data'=> false, 'readParms' => 'hidden', 'writeParms' => 'disable_button=1', 'width' => '10%', 'nolist' => true), - 'media_name' => array('title'=> LAN_TITLE, 'type' => 'text', 'data'=> 'str', 'inline'=>true, 'width' => 'auto', 'writeParms'=>array('size'=>'xxlarge')), - 'media_caption' => array('title'=> LAN_CAPTION, 'type' => 'text', 'data'=> 'str', 'inline'=>true, 'width' => 'auto', 'writeParms'=>array('size'=>'xxlarge')), - // media_description is type = textarea until bbarea can be reduced to not include youtube etc - 'media_sef' => array('title'=> LAN_URL, 'readonly'=>1, 'type'=>'method', 'data'=>false), - 'media_description' => array('title'=> LAN_DESCRIPTION, 'type' => 'textarea', 'data'=> 'str', 'width' => 'auto', 'thclass' => 'left first', 'readParms' => 'truncate=100', 'writeParms' => 'size=xxlarge&counter=0'), - 'media_type' => array('title'=> IMALAN_118, 'type' => 'dropdown', 'data'=> 'str', 'filter'=>true, 'width' => 'auto', 'noedit'=>TRUE), - 'media_author' => array('title'=> LAN_USER, 'type' => 'user', 'data'=> 'int', 'width' => 'auto', 'thclass' => 'center', 'class'=>'center','readParms' => 'link=1', 'filter' => true, 'batch' => true, 'noedit'=>TRUE ), - 'media_datestamp' => array('title'=> LAN_DATESTAMP, 'type' => 'datestamp', 'data'=> 'int', 'width' => '10%', 'noedit'=>TRUE), // User date - 'media_size' => array('title'=> LAN_SIZE, 'type' => 'number', 'data'=> 'int', 'width' => 'auto', 'readonly'=>2), - 'media_dimensions' => array('title'=> IMALAN_120, 'type' => 'text', 'data'=> 'str', 'width' => '5%', 'readonly'=>TRUE, 'class'=>'nowrap','noedit'=>TRUE), - 'media_userclass' => array('title'=> LAN_USERCLASS, 'type' => 'userclass', 'data'=> 'str', 'inline'=>true, 'width' => '10%', 'thclass' => 'center','filter'=>TRUE,'batch'=>TRUE ), - 'media_tags' => array('title'=> IMALAN_132, 'type' => 'tags', 'inline'=>true, 'data'=> 'str', 'width' => '10%', 'filter'=>TRUE,'batch'=>TRUE ), - 'media_usedby' => array('title'=> IMALAN_21, 'type' => 'hidden', 'data'=> 'text', 'width' => 'auto', 'thclass' => 'center', 'class'=>'center', 'nolist'=>true, 'readonly'=>TRUE ), + protected $tabs = ['general'=>LAN_GENERAL, 'advanced'=>LAN_ADVANCED]; - 'options' => array('title'=> LAN_OPTIONS, 'type' => 'method', 'data'=> null, 'forced'=>TRUE, 'width' => '10%', 'thclass' => 'center last', 'class' => 'center', 'batch'=>true, 'noedit'=>true) - ); + protected $fields = [ + 'checkboxes' => array('title'=> '', 'type' => null, 'data'=> null, 'tab'=>'general', 'width' =>'5%', 'forced'=> TRUE, 'thclass'=>'center', 'class'=>'center'), + 'media_id' => array('title'=> LAN_ID, 'type' => 'number', 'data'=> 'int', 'tab'=>'general', 'width' =>'5%', 'forced'=> TRUE, 'nolist'=>TRUE), + 'media_preview' => array('title'=> LAN_PREVIEW, 'type' => 'method', 'data'=>false, 'tab'=>'general', 'forced'=>true, 'width' => '110px', 'thclass' => 'center', 'class'=>'center'), + 'media_url' => array('title'=> IMALAN_110, 'type' => 'text', 'data'=> 'str', 'tab'=>'general', 'inline'=>false, 'thclass' => 'left', 'class'=>'left', 'width' => 'auto', 'writeParms'=>'size=xxlarge'), + 'media_category' => array('title'=> LAN_CATEGORY, 'type' => 'comma', 'inline'=>false, 'data'=> 'str', 'tab'=>'advanced', 'width' => '10%', 'filter' => true, 'batch' => true, 'class'=>'left'), + // Upload should be managed completely separately via upload-handler. + // 'media_upload' => array('title'=> "Upload File", 'type' => 'upload', 'data'=> false, 'tab'=>'general', 'readParms' => 'hidden', 'writeParms' => 'disable_button=1', 'width' => '10%', 'nolist' => true), + 'media_name' => array('title'=> LAN_TITLE, 'type' => 'text', 'data'=> 'str', 'tab'=>'general', 'inline'=>true, 'width' => 'auto', 'writeParms'=>array('size'=>'xxlarge')), + 'media_caption' => array('title'=> LAN_CAPTION, 'type' => 'text', 'data'=> 'str', 'tab'=>'general', 'inline'=>true, 'width' => 'auto', 'writeParms'=>array('size'=>'xxlarge')), + // media_description is type = textarea until bbarea can be reduced to not include youtube etc + 'media_alt' => array('title' => IMALAN_191, 'type' => 'text', 'data' => 'str', 'tab'=>'general', 'width' => '20%', 'inline' => true, 'writeParms' => array('size' => 'xxlarge'), 'thclass' => 'left', 'class' => 'left', 'filter' => true), + 'media_sef' => array('title'=> LAN_URL, 'readonly'=>1, 'type'=>'method', 'data'=>false, 'tab'=>'general'), + 'media_description' => array('title'=> LAN_DESCRIPTION, 'type' => 'textarea', 'data'=> 'str', 'tab'=>'general', 'width' => 'auto', 'thclass' => 'left first', 'readParms' => 'truncate=100', 'writeParms' => 'size=xxlarge&counter=0'), + 'media_type' => array('title'=> IMALAN_118, 'type' => 'dropdown', 'data'=> 'str', 'tab'=>'general', 'filter'=>true, 'width' => 'auto', 'noedit'=>TRUE), + 'media_author' => array('title'=> LAN_USER, 'type' => 'user', 'data'=> 'int', 'tab'=>'general', 'width' => 'auto', 'thclass' => 'center', 'class'=>'center','readParms' => 'link=1', 'filter' => true, 'batch' => true, 'noedit'=>TRUE), + 'media_datestamp' => array('title'=> LAN_DATESTAMP, 'type' => 'datestamp', 'data'=> 'int', 'tab'=>'general', 'width' => '10%', 'noedit'=>TRUE), // User date + 'media_size' => array('title'=> LAN_SIZE, 'type' => 'number', 'data'=> 'int', 'tab'=>'general', 'width' => 'auto', 'readonly'=>2, 'readParms'=>['format'=>'bytes']), + 'media_dimensions' => array('title'=> IMALAN_120, 'type' => 'text', 'data'=> 'str', 'tab'=>'general', 'width' => '5%', 'readonly'=>TRUE, 'class'=>'nowrap','noedit'=>TRUE), + 'media_userclass' => array('title'=> LAN_USERCLASS, 'type' => 'userclass', 'data'=> 'str', 'tab'=>'advanced', 'inline'=>true, 'width' => '10%', 'thclass' => 'center','filter'=>TRUE,'batch'=>TRUE ), + 'media_tags' => array('title'=> IMALAN_132, 'type' => 'tags', 'inline'=>true, 'data'=> 'str', 'tab'=>'advanced', 'width' => '10%', 'filter'=>TRUE,'batch'=>TRUE ), - protected $mimePaths = array( + 'media_credits' => array('title' => IMALAN_192, 'type' => 'text', 'data' => 'str', 'tab'=>'advanced', 'width' => '20%', 'inline' => true, 'writeParms' => array('size' => 'xxlarge'), 'thclass' => 'left', 'class' => 'left', 'filter' => false), + 'media_expires' => array('title' => IMALAN_193, 'type' => 'datestamp', 'data' => 'int', 'tab'=>'advanced', 'width' => '15%', 'inline' => true, 'writeParms' => '', 'thclass' => 'center', 'class' => 'center', 'filter' => true, 'batch' => true), + 'media_usedby' => array('title'=> IMALAN_21, 'type' => 'hidden', 'data'=> 'text', 'tab'=>'advanced', 'width' => 'auto', 'thclass' => 'center', 'class'=>'center', 'nolist'=>true, 'readonly'=>TRUE ), + + 'options' => array('title'=> LAN_OPTIONS, 'type' => 'method', 'data'=> null, 'forced'=>TRUE, 'width' => '10%', 'thclass' => 'center last', 'class' => 'center', 'batch'=>true, 'noedit'=>true) + ]; + + // protected $filterSort = ['media_author']; // Display these fields first + + // protected $batchSort = ['media_author']; // Display these fields first + + protected $mimePaths = [ 'text' => e_MEDIA_FILE, 'multipart' => e_MEDIA_FILE, 'application' => e_MEDIA_FILE, @@ -913,15 +921,12 @@ class media_admin_ui extends e_admin_ui 'image' => e_MEDIA_IMAGE, 'video' => e_MEDIA_VIDEO, 'other' => e_MEDIA_FILE - ); + ]; - protected $fieldpref = array( 'media_id', 'media_name', 'media_caption', 'media_category', 'media_datestamp','media_userclass', 'options'); + protected $fieldpref = ['media_id', 'media_name', 'media_caption', 'media_category', 'media_datestamp','media_alt', 'options']; - - - - protected $prefs = array( + protected $prefs = array( 'image_post' => array('title'=> IMALAN_1, 'tab'=>0, 'type'=>'boolean', 'data'=>'int', 'writeParms'=>'help=IMALAN_2'), 'image_post_class' => array('title'=> IMALAN_10, 'type' => 'userclass', 'data'=>'int', 'writeParms'=>'help=IMALAN_11&classlist=public,guest,nobody,member,admin,main,classes' ), 'image_post_disabled_method' => array('title'=> IMALAN_12, 'type' => 'boolean','writeParms'=>'enabled=IMALAN_15&disabled=IMALAN_14'), @@ -1353,6 +1358,7 @@ class media_admin_ui extends e_admin_ui $this->grid['template'] = '
{IMAGE}
+ {DIMENSIONS}

{TITLE}

{OPTIONS}

{CHECKBOX}

@@ -3127,6 +3133,19 @@ class media_admin_ui extends e_admin_ui // return $this->observeUploaded($new_data); } + public function afterUpdate($new_data, $old_data, $id) + { + if(isset($new_data['media_alt']) && !empty($new_data['media_url'])) + { + if($cacheFile = e107::getParser()->setImageAltCacheFile($new_data['media_url'], $new_data['media_alt'])) + { + e107::getMessage()->addDebug("Created Alt Tag cache file: $cacheFile"); + } + } + + + } + public function mediaData($sc_path) { if(!$sc_path) diff --git a/e107_core/shortcodes/batch/news_shortcodes.php b/e107_core/shortcodes/batch/news_shortcodes.php index 7797dbe52..e4686a1c4 100644 --- a/e107_core/shortcodes/batch/news_shortcodes.php +++ b/e107_core/shortcodes/batch/news_shortcodes.php @@ -493,7 +493,7 @@ class news_shortcodes extends e_shortcode } $style = !empty($this->param['thumbnail']) ? $this->param['thumbnail'] : ''; - $alt = !empty($parm['alt']) ? $parm['alt'] : basename($srcPath); + $alt = !empty($parm['alt']) ? $parm['alt'] : ''; $imgParms = array( 'class' => $class, diff --git a/e107_core/sql/core_sql.php b/e107_core/sql/core_sql.php index 51cf29dff..7c8cfe223 100755 --- a/e107_core/sql/core_sql.php +++ b/e107_core/sql/core_sql.php @@ -103,7 +103,9 @@ CREATE TABLE comments ( comment_share tinyint(1) unsigned NOT NULL default '0', PRIMARY KEY (comment_id), KEY comment_blocked (comment_blocked), - KEY comment_author_id (comment_author_id) + KEY comment_author_id (comment_author_id), + FULLTEXT (comment_comment), + FULLTEXT (comment_author_name) ) ENGINE=InnoDB; # -------------------------------------------------------- @@ -136,6 +138,9 @@ CREATE TABLE core_media ( media_userclass varchar(255) NOT NULL default '', media_usedby text NOT NULL, media_tags text NOT NULL, + media_alt varchar(255) NOT NULL default '', + media_credits varchar(255) NOT NULL default '', + media_expires int(10) unsigned NOT NULL default '0', PRIMARY KEY (media_id), UNIQUE KEY media_url (media_url) ) ENGINE=InnoDB; @@ -328,7 +333,13 @@ CREATE TABLE news ( KEY news_datestamp (news_datestamp), KEY news_sticky (news_sticky), KEY news_render_type (news_render_type), - KEY news_class (news_class) + KEY news_class (news_class), + FULLTEXT (news_title), + FULLTEXT (news_body), + FULLTEXT (news_extended), + FULLTEXT (news_summary), + FULLTEXT (news_meta_keywords), + FULLTEXT (news_meta_description) ) ENGINE=InnoDB; @@ -407,9 +418,12 @@ CREATE TABLE page ( menu_template varchar(50) NOT NULL default '', menu_class varchar(250) NOT NULL default '0', menu_button_url varchar(250) NOT NULL default '', - menu_button_text varchar(250) NOT NULL default '', - - PRIMARY KEY (page_id) + menu_button_text varchar(250) NOT NULL default '', + PRIMARY KEY (page_id), + FULLTEXT (page_title), + FULLTEXT (page_text), + FULLTEXT (page_metakeys), + FULLTEXT (page_fields) ) ENGINE=InnoDB; # -------------------------------------------------------- @@ -586,7 +600,8 @@ CREATE TABLE user ( PRIMARY KEY (user_id), UNIQUE KEY user_name (user_name), UNIQUE KEY user_loginname (user_loginname), - KEY join_ban_index (user_join,user_ban) + KEY join_ban_index (user_join,user_ban), + FULLTEXT (user_signature) ) ENGINE=InnoDB; # -------------------------------------------------------- diff --git a/e107_core/templates/bootstrap5/fpw_template.php b/e107_core/templates/bootstrap5/fpw_template.php new file mode 100644 index 000000000..26716c2d5 --- /dev/null +++ b/e107_core/templates/bootstrap5/fpw_template.php @@ -0,0 +1,24 @@ + +
+

{FPW_TEXT}

+
{FPW_USEREMAIL}
+
{FPW_CAPTCHA_IMG}{FPW_CAPTCHA_INPUT}
+
+
+ {FPW_SUBMIT} +
+
+
+
+ '; + +$FPW_TEMPLATE['header'] = '
'; +$FPW_TEMPLATE['footer'] = '
'; diff --git a/e107_handlers/admin_ui.php b/e107_handlers/admin_ui.php index be673edc1..e3b09a2d5 100755 --- a/e107_handlers/admin_ui.php +++ b/e107_handlers/admin_ui.php @@ -2786,6 +2786,19 @@ class e_admin_controller_ui extends e_admin_controller */ protected $filterQry; + /** + * Custom sorting of the filter list. + * @var array + */ + protected $filterSort = array(); + + + /** + * Custom sorting of the batch list. + * @var array + */ + protected $batchSort = array(); + /** * @var boolean */ @@ -2939,6 +2952,21 @@ class e_admin_controller_ui extends e_admin_controller return $this->eventName; } + /** + * @return array + */ + public function getFilterSort() + { + return $this->filterSort; + } + + /** + * @return array + */ + public function getBatchSort() + { + return $this->batchSort; + } /** * @return string @@ -6152,6 +6180,16 @@ class e_admin_ui extends e_admin_controller_ui $this->getTreeModel()->setMessages(); } + protected function handleGridSearchfieldFilter($selected) + { + return $this->handleListSearchfieldFilter($selected); + } + + protected function handleGridDeleteBatch($selected) + { + return $this->handleListDeleteBatch($selected); + } + /** * Method to generate "Search in Field" query. @@ -8182,6 +8220,25 @@ class e_admin_form_ui extends e_form return $text; } + private function sortFieldsByPriority(array $fields, array $priorityKeys) + { + // Separate fields into priority and non-priority arrays + $priorityFields = []; + $remainingFields = $fields; + + foreach ($priorityKeys as $key) + { + // If the key exists in the fields array, move it to the priorityFields array + if (isset($fields[$key])) + { + $priorityFields[$key] = $fields[$key]; + unset($remainingFields[$key]); // Remove from remaining fields + } + } + + // Merge priorityFields at the top with remainingFields retaining their original order + return $priorityFields + $remainingFields; + } /** * Render Batch and Filter Dropdown options. @@ -8192,16 +8249,22 @@ class e_admin_form_ui extends e_form public function renderBatchFilter($type='batch', $selected = '') // Common function used for both batches and filters. { $optdiz = array('batch' => LAN_BATCH_LABEL_PREFIX.' ', 'filter'=> LAN_FILTER_LABEL_PREFIX.' '); - $table = $this->getController()->getTableName(); + $obj = $this->getController(); + $table = $obj->getTableName(); $text = ''; $textsingle = ''; $searchFieldOpts = array(); - $fieldList = $this->getController()->getFields(); - + $fieldList = $obj->getFields(); + $fieldSort = ($type ==='batch') ? $obj->getBatchSort() : $obj->getFilterSort(); + if(!empty($fieldSort)) + { + e107::getMessage()->addDebug("Filtering by custom sort field: ".print_r($fieldSort,true)); + $fieldList = $this->sortFieldsByPriority($fieldList, $fieldSort); + } foreach($fieldList as $key=>$val) { @@ -8603,6 +8666,7 @@ class e_admin_form_ui extends e_form if(!empty($option)) { $text .= "\t".$this->optgroup_open($optdiz[$type].defset($val['title'], $val['title']), varset($disabled))."\n"; + foreach($option as $okey=>$oval) { $text .= $this->option($oval, $okey, $selected == $okey)."\n"; @@ -8611,22 +8675,23 @@ class e_admin_form_ui extends e_form } } + $text2 = ''; if(!empty($searchFieldOpts) && $type !== 'batch') { - $text .= "\t".$this->optgroup_open(defset('LAN_UI_FILTER_SEARCH_IN_FIELD', 'Search in Field'))."\n"; + $text2 .= "\t".$this->optgroup_open(defset('LAN_UI_FILTER_SEARCH_IN_FIELD', 'Search in Field'))."\n"; foreach($searchFieldOpts as $key=>$val) { - $text .= $this->option($val, $key, $selected == $key)."\n"; + $text2 .= $this->option($val, $key, $selected == $key)."\n"; } - $text .= "\t".$this->optgroup_close()."\n"; + $text2 .= "\t".$this->optgroup_close()."\n"; } - return $textsingle.$text; + return $textsingle.$text2.$text; } diff --git a/e107_handlers/db_verify_class.php b/e107_handlers/db_verify_class.php index 9d4d702ef..8cdf3b1ed 100755 --- a/e107_handlers/db_verify_class.php +++ b/e107_handlers/db_verify_class.php @@ -793,7 +793,7 @@ class db_verify // return "
".print_r($data,TRUE)."
"; $v = $data['_valid']; - $i = $data['_invalid']; + $i = !empty($data['_invalid']) ? $data['_invalid'] : array(); $valid = $this->toMysql($v,$mode); $invalid = $this->toMysql($i,$mode); @@ -1163,6 +1163,13 @@ class db_verify foreach($tmp as $line) { $line = trim($line); + + if(strpos($line,"PRIMARY") === 0 || strpos($line,"KEY") === 0 || strpos($line,"INDEX") === 0 || strpos($line,"FULLTEXT") === 0 || strpos($line,"FOREIGN") === 0) + { + $newline[] = ''; // Add a placeholder to preserve the structure + continue; + } + $newline[] = preg_replace('/^([^`\s][0-9a-zA-Z\$_]*)/',"`$1`", $line); } @@ -1172,26 +1179,13 @@ class db_verify $mes = e107::getMessage(); // $regex = "/`?([\w]*)`?\s*?(".implode("|",$this->fieldTypes)."|".implode("|",$this->fieldTypeNum).")\s?(?:\([\s]?([0-9,]*)[\s]?\))?[\s]?(unsigned)?[\s]?.*?(?:(NOT NULL|NULL))?[\s]*(auto_increment|default .*)?[\s]?(?:PRIMARY KEY)?[\s]*?,?\s*?\n/im"; - $regex = "/^\s*?`?([\w]*)`?\s*?(".implode("|",$this->fieldTypes)."|".implode("|",$this->fieldTypeNum).")\s?(?:\([\s]?([0-9,]*)[\s]?\))?[\s]?(unsigned)?[\s]?.*?(?:(NOT NULL|NULL))?[\s]*(auto_increment|default|AUTO_INCREMENT|DEFAULT [\w'\s.\(:\)-]*)?[\s]?(comment [\w\s'.-]*)?[\s]?(?:PRIMARY KEY)?[\s]*?,?\s*?\n/im"; + $regex = "/^\s*?`?([\w]*)`?\s*?(".implode("|",$this->fieldTypes)."|".implode("|",$this->fieldTypeNum).")\s?(?:\([\s]?([0-9,]*)[\s]?\))?[\s]?(unsigned)?[\s]?.*?(?:(NOT NULL|NULL))?[\s]*(auto_increment|default|AUTO_INCREMENT|DEFAULT [\w'\s.\(:\)-]*)?[\s]?(comment [\w\s'.-]*)?[\s]?(?:PRIMARY KEY|FULLTEXT)?[\s]*?,?\s*?\n/im"; - - // echo $regex."

"; - - // $regex = "/`?([\w]*)`?\s*(int|varchar|tinyint|smallint|text|char|tinyint) ?(?:\([\s]?([0-9]*)[\s]?\))?[\s]?(unsigned)?[\s]?.*?(NOT NULL|NULL)?[\s]*(auto_increment|default .*)?[\s]?,/i"; - - // $regex = "/^\s*?`?([\w]*)`?\s*?(".implode("|",$this->fieldTypes)."|".implode("|",$this->fieldTypeNum).")\s?(?:\([\s]?([0-9,]*)[\s]?\))?[\s]?(unsigned)?[\s]?.*?(?:(NOT NULL|NULL))?[\s]*?(auto_increment|default [\w'\".-]*)?[\s]?(?:PRIMARY KEY)?[\s]*?,?\n/im"; - //$regex = "/^\s*?`?([\w]*)`?\s*?(date|time|timestamp|datetime|year|tinyblob|blob|mediumblob|longblob|tinytext|mediumtext|longtext|text|bit|tinyint|smallint|mediumint|integer|int|bigint|real|double|float|decimal|numeric|varchar|char|binary|varbinary|enum|set)\s?(?:\([\s]?([0-9,]*)[\s]?\))?[\s]?(unsigned)?[\s]*?(?:(NOT NULL|NULL))?[\s]*?(auto_increment|default [\w'\".-]*)?[\s]?(?:PRIMARY KEY)?[\s]*?,?\n/im"; - // $mes->addDebug($regex); - - //$regex = "/^\s*?`?([\w]*)`?\s*?(date|time|timestamp|datetime|year|text|bit|tinyint|smallint|mediumint|integer|int|bigint|real|double|float|decimal|numeric|varchar|char|binary|varbinary|enum|set)\s?(?:\([\s]?([0-9,]*)[\s]?\))?[\s]?(unsigned)?[\s]*?(?:(NOT NULL|NULL))?[\s]*?(auto_increment|default [\w'.-]*)?[\s]?(?:PRIMARY KEY)?[\s]*?,?\n/i"; - - // echo "reg=".$regex; - preg_match_all($regex,$data,$m); $ret = array(); - - if($print) var_dump($regex, $m); + + if($print) var_dump($regex, $m); foreach($m[1] as $k=>$val) { @@ -1215,10 +1209,47 @@ class db_verify */ function getIndex($data, $print = false) { - $regex = "/(PRIMARY|UNIQUE|FULLTEXT|FOREIGN)?[\s]*?(INDEX|KEY)[\s]*(?:`?([\w]*)`?)?[\s]*?\(`?([\w]+)`?(?:\s*\(\d+\))?(?:\s*(ASC|DESC))?\)[\s]*,?/i"; + // $regex = "/(PRIMARY|UNIQUE|FULLTEXT|FOREIGN)?[\s]*?(INDEX|KEY)[\s]*(?:`?([\w]*)`?)?[\s]*?\(`?([\w]+)`?(?:\s*\(\d+\))?(?:\s*(ASC|DESC))?\)[\s]*,?/i"; + // $regex = "/(?PPRIMARY|PRIMARY|UNIQUE|FULLTEXT|FOREIGN|KEY)[\s]*?(?PINDEX|KEY)?[\s]*(?:`?(?P[\w]*)`?)?[\s]*?\(`?(?P[\w]+)`?(?:\s*\(\d+\))?(?:\s*(?PASC|DESC))?\)[\s]*,?/i"; + $regex = "/(?PPRIMARY|UNIQUE|FULLTEXT|FOREIGN|KEY|INDEX)[\s]*?(?PINDEX|KEY)?[\s]*(?:`?(?P[\w]*)`?)?[\s]*?\(`?(?P[\w]+)`?(?:\s*\((?P\d+)\))?(?:\s*(?PASC|DESC))?\)[\s]*,?/i"; preg_match_all($regex,$data,$m); + $ret = []; + + foreach($m['type'] as $k=>$val) + { + $i = $m['field'][$k]; + $type = trim(strtoupper($m['type'][$k])); + $keyname = trim($m['keyname'][$k]); + $field = trim($m['field'][$k]); + + if(empty($field) || $field === 'KEY') + { + $field = $keyname; + $i = $keyname; + } + + if($type === 'KEY' || $type === 'INDEX') + { + $type = ''; + } + + if(empty($keyname) || $keyname === 'KEY') + { + $keyname = $field; + } + + $ret[$i] = array( + 'type' => $type, + 'keyname' => $keyname, + 'field' => $field, + + ); + } + + return $ret; +/* if (count($m) > 0) { unset($m[2]); @@ -1273,7 +1304,7 @@ class db_verify } return $ret; - +*/ } diff --git a/e107_handlers/e_parse_class.php b/e107_handlers/e_parse_class.php index 2c7c223b5..2f845a938 100644 --- a/e107_handlers/e_parse_class.php +++ b/e107_handlers/e_parse_class.php @@ -2288,6 +2288,50 @@ class e_parse } + /** + * Sets a cache file for storing alternate text data for an image. + * + * @param string $path The file path of the image whose alternate text is being cached. + * @param string $value The alternate text value to cache. + * @return string or false on failure + */ + public function setImageAltCacheFile($path, $value) + { + $cache_str = sha1($path); + + $pre = 'alt_'; + $post = '.cache.txt'; + + $file = e_CACHE_IMAGE .'alt_' . sha1($path) . '.cache.txt'; + + if (file_put_contents($file, $value) !== false) + { + return $file; + } + + return false; + + } + + /** + * Retrieves the content of the alternative cache file for the specified path if it exists. + * + * @param string $path The file path to generate the cache filename for. + * @return string|null The content of the cache file if it exists, or null if the file does not exist. + */ + public function getImageAltCacheFile($path) + { + $file = e_CACHE_IMAGE .'alt_' . sha1($path) . '.cache.txt'; + + if (file_exists($file)) + { + return file_get_contents($file); + } + + return null; + } + + /** * Generated a Thumb Cache File Name from path and options. * @@ -4545,6 +4589,11 @@ class e_parse $tp = $this; + if(($alt = $this->getImageAltCacheFile($file)) && empty($parm['alt'])) + { + $parm['alt'] = $alt; + } + // e107::getDebug()->log($file); // e107::getDebug()->log($parm); @@ -4621,6 +4670,8 @@ class e_parse $path = $tp->thumbUrl($file, $parm); } + + $id = (!empty($parm['id'])) ? 'id="' . $parm['id'] . '" ' : ''; $class = (!empty($parm['class'])) ? $parm['class'] : 'img-responsive img-fluid'; $alt = (!empty($parm['alt'])) ? $tp->toAttribute($parm['alt']) : basename($file); diff --git a/e107_handlers/e_pluginbuilder_class.php b/e107_handlers/e_pluginbuilder_class.php index 283e650a9..a783931e7 100644 --- a/e107_handlers/e_pluginbuilder_class.php +++ b/e107_handlers/e_pluginbuilder_class.php @@ -669,7 +669,7 @@ $content .= '}'; 'keywords' => array('one','two','three'), 'category' => array('category'), 'copyright' => array('copyright'), - // 'adminLinks' => array('url','description','icon','iconSmall','primary'), + 'adminLinks' => array('url', 'description', 'icon', 'iconSmall', 'icon128'), // 'sitelinks' => array('url','description','icon','iconSmall') ); @@ -729,21 +729,27 @@ $content .= '}'; $existingXml = e_PLUGIN.$this->pluginName."/plugin.xml"; if(file_exists($existingXml)) { - $p = e107::getXml()->loadXMLfile($existingXml,true); + $p = e107::getXml()->loadXMLfile($existingXml, 'advanced'); - // print_a($p); + // print_a($p); $defaults = array( "main-name" => varset($p['@attributes']['name']), "main-lang" => varset($p['@attributes']['lan']), "author-name" => varset($p['author']['@attributes']['name']), "author-url" => varset($p['author']['@attributes']['url']), - "description-description" => varset($p['description']), - "summary-summary" => varset($p['summary'], $p['description']), + "description-description" => varset($p['description']['@value']), + "summary-summary" => varset($p['summary'], $p['summary']['@value']), "category-category" => varset($p['category']), "copyright-copyright" => varset($p['copyright']), "keywords-one" => varset($p['keywords']['word'][0]), "keywords-two" => varset($p['keywords']['word'][1]), "keywords-three" => varset($p['keywords']['word'][2]), + "adminLinks-url" => varset($p['adminLinks']['link'][0]['@attributes']['url']), + "adminLinks-description" => varset($p['adminLinks']['link'][0]['@attributes']['description']), + "adminLinks-icon" => varset($p['adminLinks']['link'][0]['@attributes']['icon']), + "adminLinks-iconSmall" => varset($p['adminLinks']['link'][0]['@attributes']['iconSmall']), + "adminLinks-icon128" => varset($p['adminLinks']['link'][0]['@attributes']['icon128']), + ); unset($p); @@ -1023,7 +1029,7 @@ $template = <<