Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3719785
Add weblinks.xml for task plugin configuration
alikon Jun 5, 2026
07f900f
Add files via upload
alikon Jun 5, 2026
92842b1
cs
alikon Jun 6, 2026
502b953
include on package
alikon Jun 6, 2026
aebb234
Fix copyright tag format in weblinks.xml
alikon Jun 6, 2026
ac1cbf8
Refactor Weblinks plugin for better error handling
alikon Jun 8, 2026
3f424cb
cs
alikon Jun 8, 2026
77fe291
Update email body placeholders in weblinks plugin
alikon Jun 8, 2026
6fc91c3
Add installer script for weblinks plugin
alikon Jun 8, 2026
ad7b7e0
Fix indentation in script.php
alikon Jun 8, 2026
f313790
Add Cypress tests for weblinks task plugin
alikon Jun 8, 2026
1438065
Fix syntax error in afterEach cleanup task
alikon Jun 8, 2026
0fb4871
Add db_createSchedulerTask command
alikon Jun 8, 2026
a40d448
Add 'url' field to weblinks query selection
alikon Jun 8, 2026
24eadb8
Change dialog header text from 'Run Task' to 'Test Task'
alikon Jun 9, 2026
41c0e25
Fix case sensitivity in dialog header assertion
alikon Jun 9, 2026
5b2f9f3
Configure Mailpit for email testing in CI
alikon Jun 10, 2026
d6a2c7a
Refactor Mailpit mail handling with fetch API
alikon Jun 10, 2026
814e866
Improve mail validation in Weblinks test
alikon Jun 10, 2026
e0da485
Change latestMail reference from index 0 to 1
alikon Jun 10, 2026
be0ec5a
Correct index for latest mail in Weblinks test
alikon Jun 10, 2026
9142634
Change template ID for dropTable function
alikon Jun 11, 2026
d229ba9
Change success_mail notification from 1 to 0
alikon Jun 11, 2026
2c1fdd9
Add cleanup for scheduler tasks in Weblinks tests
alikon Jun 11, 2026
6a2d495
Enable email notifications for broken link checks
alikon Jun 11, 2026
ffd3ef1
Refactor email assertions in Weblinks.cy.js
alikon Jun 11, 2026
c04e466
Fix SQL query syntax in email notification test
alikon Jun 11, 2026
e00875f
Refactor email notification query for database compatibility
alikon Jun 11, 2026
cff86d3
Refactor task string handling based on Joomla version
alikon Jun 11, 2026
24cc5ab
Add weblinks_params.xml for task parameters
alikon Jun 19, 2026
e7d7d9e
Add HTTP timeout and batch size labels to weblinks plugin
alikon Jun 19, 2026
4aa284b
Enhance weblinks plugin with batch processing support
alikon Jun 19, 2026
2b9efd1
Refactor code for improved readability and consistency
alikon Jun 19, 2026
22b81a2
cs
alikon Jun 19, 2026
b60dc61
Refactor beforeEach and update task parameters
alikon Jun 21, 2026
952973a
demo x errore
alikon Jun 22, 2026
9f80501
Rename ADatabaseAwareTrait to DatabaseAwareTrait
alikon Jun 22, 2026
befc194
end-jug-demo
alikon Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ jobs:
POSTGRES_USER: ${{ matrix.db == 'pgsql' && 'root' || 'unused' }}
POSTGRES_PASSWORD: ${{ matrix.db == 'pgsql' && 'root' || 'unused' }}
POSTGRES_DB: ${{ matrix.db == 'pgsql' && 'test_joomla' || 'unused' }}
mailpit:
image: axllent/mailpit:latest
ports:
- 1025:1025
- 8025:8025

steps:
- uses: actions/checkout@v6
Expand All @@ -219,6 +224,11 @@ jobs:
cd /tests/www/${{ matrix.db }}/
apache2ctl -D FOREGROUND &
php installation/joomla.php install --verbose --site-name="Joomla test" --admin-email=admin@example.org --admin-username=ci-admin --admin-user="jane doe" --admin-password=joomla-17082005 --db-type=${{ matrix.db-type }} --db-host=${{ matrix.db-host }} --db-name=test_joomla --db-pass=$DB_PASS --db-user=$DB_USER --db-encryption=0 --db-prefix=${{ matrix.db-prefix }}
# CONFIGURAZIONE EMAIL PER MAILPIT
php cli/joomla.php config:set mailer=smtp
php cli/joomla.php config:set smtphost=mailpit
php cli/joomla.php config:set smtpport=1025
php cli/joomla.php config:set smtpauth=0
php cli/joomla.php extension:install --path=/tests/www/${{ matrix.db }}/pkg-weblinks-current.zip
mkdir -p tmp/api_rate_limit tmp/plg_system_ratelimit
chown -R www-data:www-data /tests/www/${{ matrix.db }}/
Expand All @@ -229,7 +239,7 @@ jobs:
[ "${{ matrix.db }}" = "pgsql" ] && psql -h ${{ matrix.db-host }} -U $DB_USER -d test_joomla -t -c 'SELECT version();' | head -1 | xargs || mysql -h ${{ matrix.db-host }} -u $DB_USER -p$DB_PASS --skip-ssl -e 'SELECT VERSION();' -s -N
echo "========================"
cd $GITHUB_WORKSPACE
npx cypress run --browser=chrome --e2e --config video=false --expose cmsPath=/tests/www/${{ matrix.db }},db_type=${{ matrix.db-type }},db_host=${{ matrix.db-host }},db_name=test_joomla,db_user=$DB_USER,db_password=$DB_PASS,db_prefix=${{ matrix.db-prefix }},logFile=/var/log/apache2/error.log --config baseUrl=http://localhost/${{ matrix.db }}
npx cypress run --browser=chrome --e2e --config video=false --expose mailpitUrl=http://mailpit:8025,cmsPath=/tests/www/${{ matrix.db }},db_type=${{ matrix.db-type }},db_host=${{ matrix.db-host }},db_name=test_joomla,db_user=$DB_USER,db_password=$DB_PASS,db_prefix=${{ matrix.db-prefix }},logFile=/var/log/apache2/error.log --config baseUrl=http://localhost/${{ matrix.db }}

- name: Upload Screenshots on Failure
if: failure()
Expand Down
1 change: 1 addition & 0 deletions src/administrator/manifests/packages/pkg_weblinks.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<file type="plugin" id="weblinks" group="search">plg_search_weblinks.zip</file>
<file type="plugin" id="weblinks" group="system">plg_system_weblinks.zip</file>
<file type="plugin" id="weblink" group="editors-xtd">plg_editors-xtd_weblink.zip</file>
<file type="plugin" id="weblinks" group="task">plg_task_weblinks.zip</file>
<file type="plugin" id="weblinks" group="webservices">plg_webservices_weblinks.zip</file>
<file type="plugin" id="weblinks" group="quickicon">plg_quickicon_weblinks.zip</file>
</files>
Expand Down
2 changes: 1 addition & 1 deletion src/components/com_weblinks/src/Model/WeblinksModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ protected function getListQuery()
$this->getState(
'list.select',
'a.id, a.title, a.alias, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, ' .
'a.hits, a.state, a.access, a.ordering, a.language, a.publish_up, a.publish_down'
'a.hits, a.state, a.access, a.ordering, a.language, a.publish_up, a.publish_down, a.url'
)
);
$query->from($db->quoteName('#__weblinks', 'a'));
Expand Down
29 changes: 29 additions & 0 deletions src/plugins/task/weblinks/forms/weblinks_params.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<form>
<fields name="params">
<fieldset name="task_params">
<field
name="http_timeout"
type="number"
label="PLG_TASK_WEBLINKS_HTTP_TIMEOUT_LABEL"
default="8"
required="true"
min="5"
step="1"
validate="number"
filter="int"
/>
<field
name="batch_size"
type="number"
label="PLG_TASK_WEBLINKS_BATCH_SIZE_LABEL"
default="3"
required="true"
min="1"
step="1"
validate="number"
filter="int"
/>
</fieldset>
</fields>
</form>
10 changes: 10 additions & 0 deletions src/plugins/task/weblinks/language/en-GB/plg_task_weblinks.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
PLG_TASK_WEBLINKS="Weblinks Task"
PLG_TASK_WEBLINKS_XML_DESCRIPTION="Task plugin for checking weblinks"
PLG_TASK_WEBLINKS_TITLE="Weblinks check"
PLG_TASK_WEBLINKS_DESC="This task checks the weblinks for broken links and sends an email with the results. It checks only published weblinks."
PLG_TASK_WEBLINKS_EMAIL_SUBJECT="Weblinks check results"
PLG_TASK_WEBLINKS_EMAIL_BODY="Hello,\n\nThe weblinks check task has completed. Here are the results:\n\n{DETAILS}\n\nBest regards,\n{SITENAME}"
PLG_TASK_WEBLINKS_HTTP_TIMEOUT_LABEL="HTTP Timeout (seconds)"
PLG_TASK_WEBLINKS_BATCH_SIZE_LABEL="Batch Size"
PLG_TASK_WEBLINKS_MAIL_BROKEN_LINKS_TITLE="Broken Links Report"
PLG_TASK_WEBLINKS_MAIL_BROKEN_LINKS_DESC="Email template used to report broken links."
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PLG_TASK_WEBLINKS="Weblinks Task"
PLG_TASK_WEBLINKS_XML_DESCRIPTION="Task plugin for checking weblinks"
262 changes: 262 additions & 0 deletions src/plugins/task/weblinks/script.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
<?php

/**
* @package Joomla.Plugin
* @subpackage Weblinks.weblinks
*
* @copyright (C) 2026 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

\defined('_JEXEC') or die();

use Joomla\CMS\Application\AdministratorApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\CMS\Installer\InstallerScriptInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\Database\DatabaseDriver;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;

/**
* Installer service provider of plg_contact_customreply plugin.
*
* @since 1.0.0
*/
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 1.0.0
*/
public function register(Container $container)
{
$container->set(
InstallerScriptInterface::class,
new class (
$container->get(AdministratorApplication::class)
) implements InstallerScriptInterface {
/**
* Minimum Joomla version to check
*
* @var string
* @since 1.0.0
*/
protected $minimumJoomla = '5.0.0';

/**
* Minimum PHP version to check
*
* @var string
* @since 1.0.0
*/
protected $minimumPhp = '8.1.0';

/**
* The application object
*
* @var AdministratorApplication
* @since 1.0.0
*/
private AdministratorApplication $app;

/**
* True when we have to update the searchable fields
*
* @var boolean
* @since 1.0.0
*/
private $updateSearchable = false;

/**
* Constructor
*
* @param AdministratorApplication $app The application object
*
* @since 1.0.0
*/
public function __construct(AdministratorApplication $app)
{
$this->app = $app;
}

/**
* Function called after the extension is installed.
*
* @param InstallerAdapter $adapter The adapter calling this method
*
* @return boolean True on success
*
* @since 1.0.0
*/
public function install(InstallerAdapter $adapter): bool
{

$this->createTable();
return true;
}

/**
* Function called after the extension is updated.
*
* @param InstallerAdapter $adapter The adapter calling this method
*
* @return boolean True on success
*
* @since 1.0.0
*/
public function update(InstallerAdapter $adapter): bool
{
return true;
}

/**
* Function called after the extension is uninstalled.
*
* @param InstallerAdapter $adapter The adapter calling this method
*
* @return boolean True on success
*
* @since 1.0.0
*/
public function uninstall(InstallerAdapter $adapter): bool
{

$this->dropTable();
return true;
}

/**
* Function called before extension installation/update/removal procedure commences.
*
* @param string $type The type of change (install or discover_install, update, uninstall)
* @param InstallerAdapter $adapter The adapter calling this method
*
* @return boolean True on success
*
* @since 1.0.0
*/
public function preflight(string $type, InstallerAdapter $adapter): bool
{
if ($type !== 'uninstall') {
// Check for the minimum PHP version before continuing
if (!empty($this->minimumPhp) && version_compare(PHP_VERSION, $this->minimumPhp, '<')) {
Log::add(
Text::sprintf('JLIB_INSTALLER_MINIMUM_PHP', $this->minimumPhp),
Log::WARNING,
'jerror'
);

return false;
}

// Check for the minimum Joomla version before continuing
if (!empty($this->minimumJoomla) && version_compare(JVERSION, $this->minimumJoomla, '<')) {
Log::add(
Text::sprintf('JLIB_INSTALLER_MINIMUM_JOOMLA', $this->minimumJoomla),
Log::WARNING,
'jerror'
);

return false;
}
}

return true;
}

/**
* Function called after extension installation/update/removal procedure commences.
*
* @param string $type The type of change (install or discover_install, update, uninstall)
* @param InstallerAdapter $adapter The adapter calling this method
*
* @return boolean True on success
*
* @since 1.0.0
*/
public function postflight(string $type, InstallerAdapter $adapter): bool
{
if (!\in_array($type, ['install', 'discover_install'])) {
return true;
}
// Auto-publish plugin
$adapter->extension->enabled = 1;
$adapter->extension->store();

echo Text::_('PLG_CONTACT_CUSTOMREPLY_INSTALLERSCRIPT_POSTFLIGHT_INSTALL');

return true;
}
/**
* Insert the template into the #__mail_templates table.
*
* @return void
*/
private function createTable(): void
{
try {
$db = Factory::getContainer()->get(DatabaseDriver::class);

$templateId = 'plg_task_weblinks.broken_links';
$extension = 'plg_task_weblinks';
$language = '';
$subject = 'PLG_TASK_WEBLINKS_EMAIL_SUBJECT';
$body = 'PLG_TASK_WEBLINKS_EMAIL_BODY';
$htmlbody = 'PLG_TASK_WEBLINKS_EMAIL_HTMLBODY';
$attachments = '';
$params = '{"tags":["broken_count","checked_count","details","sitename"]}';

$query = $db->getQuery(true);
$query->clear()
->insert($db->quoteName('#__mail_templates'))
->columns($db->quoteName(['template_id', 'extension', 'language', 'subject', 'body', 'htmlbody', 'attachments', 'params']))
->values(':templateid, :extension, :language, :subject, :body, :htmlbody, :attachments, :params')
->bind(':templateid', $templateId)
->bind(':extension', $extension)
->bind(':language', $language)
->bind(':subject', $subject)
->bind(':body', $body)
->bind(':htmlbody', $htmlbody)
->bind(':attachments', $attachments)
->bind(':params', $params);

$db->setQuery($query);
$db->execute();
} catch (\Exception $e) {
Factory::getApplication()->enqueueMessage('Error creating template_id ' . $templateId . ': ' . $e->getMessage(), 'error');
}
}

/**
* Delete the template_id in the #__mail_templates table.
*
* @return void
*/
private function dropTable(): void
{
try {
$db = Factory::getContainer()->get(DatabaseDriver::class);
$templateId = 'plg_task_weblinks.broken_links';
// Delete the template_id from the #__mail_templates table
$query = $db->getQuery(true);
$query->clear()
->delete($db->quoteName('#__mail_templates'))
->where($db->quoteName('template_id') . ' = :templateid')
->bind(':templateid', $templateId);
$db->setQuery($query);
$db->execute();
} catch (\Exception $e) {
Factory::getApplication()->enqueueMessage('Error dropping template_id ' . $templateId . ': ' . $e->getMessage(), 'error');
}
}
}
);
}
};
39 changes: 39 additions & 0 deletions src/plugins/task/weblinks/services/provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/**
* @package Joomla.Plugin
* @subpackage Task.weblinks
*
* @copyright (C) 2026 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects

use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Plugin\Task\Weblinks\Extension\Weblinks;

return new class () implements ServiceProviderInterface {
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Weblinks(
(array) PluginHelper::getPlugin('task', 'weblinks')
);

$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get('DatabaseDriver'));

return $plugin;
}
);
}
};
Loading
Loading