Skip to content

Commit

Permalink
Merge pull request #204 from creative-commoners/pulls/6/remove-support
Browse files Browse the repository at this point in the history
NEW Migrate code from other modules
  • Loading branch information
GuySartorelli authored Nov 28, 2024
2 parents 683d4ac + d1913b0 commit 579b939
Show file tree
Hide file tree
Showing 73 changed files with 9,210 additions and 4 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@silverstripe/eslint-config/.eslintrc');
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.sass-cache
.DS_Store
.DS_Store
node_modules
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18
1 change: 1 addition & 0 deletions .stylelintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@silverstripe/eslint-config/.stylelintrc');
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ composer require silverstripe/reports
This module contains the API's for building Reports that are displayed in the
Silverstripe backend.

There are also a few CMS reports that comes out of the box:
- A "Users, Groups and Permissions" report allowing administrators to get a quick overview of who has access to the CMS.
- A "Site-wide content report" report allowing CMS users to get a quick overview of content across the site.
- An "External broken links report" allowing users with permissions to track broken external links.

## Troubleshooting

The reports section will not show up in the CMS if:
Expand All @@ -31,6 +36,10 @@ SilverStripe\Reports\Report:
```
Note that some reports may have overridden the `getCount` method, and for those reports this may not apply.

## Included reports

This module comes with a few customisable reports out of the box. Details on how to customise these reports can be found in the [documentation] section(./docs/en/index.md).

## Links ##

* [License](./LICENSE)
9 changes: 9 additions & 0 deletions _config/externallinks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
Name: reports-externallinksdependencies
---
SilverStripe\Core\Injector\Injector:
SilverStripe\Reports\ExternalLinks\Tasks\LinkChecker: SilverStripe\Reports\ExternalLinks\Tasks\CurlLinkChecker
Psr\SimpleCache\CacheInterface.CurlLinkChecker:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: 'curllinkchecker'
6 changes: 6 additions & 0 deletions _config/securityreport.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
Name: reports-securityreportconfig
---
SilverStripe\Security\Member:
extensions:
- SilverStripe\Reports\SecurityReport\Extensions\MemberReportExtension
8 changes: 8 additions & 0 deletions _config/sitewidecontent-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
Name: reports-sitewidecontenttaxonomy
Only:
moduleexists: silverstripe/taxonomy
---
SilverStripe\Reports\SitewideContentReport\Reports\SitewideContentReport:
extensions:
- SilverStripe\Reports\SiteWideContentReport\Extensions\SitewideContentTaxonomy
6 changes: 6 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
29 changes: 29 additions & 0 deletions behat.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
default:
suites:
reports:
paths:
- "%paths.modules.reports%/tests/behat/features"
contexts:
- SilverStripe\Admin\Tests\Behat\Context\AdminContext
- SilverStripe\BehatExtension\Context\BasicContext
- SilverStripe\BehatExtension\Context\EmailContext
- SilverStripe\BehatExtension\Context\LoginContext
- SilverStripe\Framework\Tests\Behaviour\CmsFormsContext
- SilverStripe\Framework\Tests\Behaviour\CmsUiContext
- SilverStripe\Reports\Tests\Behat\Context\FeatureContext
- SilverStripe\Reports\Tests\Behat\Context\FixtureContext
-
SilverStripe\Reports\Tests\Behat\Context\FixtureContext:
- "%paths.modules.reports%/tests/behat/files/"

extensions:
SilverStripe\BehatExtension\MinkExtension:
default_session: facebook_web_driver
javascript_session: facebook_web_driver
facebook_web_driver:
browser: chrome
wd_host: "http://127.0.0.1:9515"

SilverStripe\BehatExtension\Extension:
screenshot_path: "%paths.base%/artifacts/screenshots"
bootstrap_file: vendor/silverstripe/framework/tests/behat/serve-bootstrap.php
1 change: 1 addition & 0 deletions client/dist/js/BrokenExternalLinksReport.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/dist/js/ReportAdmin.Tree.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/dist/js/ReportAdmin.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/dist/styles/BrokenExternalLinksReport.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.external-links-report__create-report,.external-links-report__report-progress{margin-top:20px}
1 change: 1 addition & 0 deletions client/dist/styles/sitewidecontentreport.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.gridfieldbasiccontentreport.field{border-bottom:1px solid #d2d5d8;margin:24px 0}.gridfieldbasiccontentreport.field:last-of-type{border-bottom-style:none}
148 changes: 148 additions & 0 deletions client/src/js/BrokenExternalLinksReport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/* global jQuery */
(function ($) {
// eslint-disable-next-line no-shadow
$.entwine('ss', ($) => {
$('.external-links-report__create-report').entwine({
PollTimeout: null,
ButtonIsLoading: false,
ReloadContent: false,

onclick(e) {
e.preventDefault();

this.buttonLoading();
this.start();
},

onmatch() {
// poll the current job and update the front end status
this.poll();
},

start() {
const self = this;
// initiate a new job
$('.external-links-report__report-progress')
.empty()
.text('Running report 0%');

$.ajax({
url: 'admin/externallinks/start',
async: true,
timeout: 3000,
success() {
self.setReloadContent(true);
self.poll();
},
error() {
self.buttonReset();
}
});
},

/**
* Get the "create report" button selector
*
* @return {Object}
*/
getButton() {
return $('.external-links-report__create-report');
},

/**
* Sets the button into a loading state. See LeftAndMain.js.
*/
buttonLoading() {
if (this.getButtonIsLoading()) {
return;
}
this.setButtonIsLoading(true);

const $button = this.getButton();

// set button to "submitting" state
$button.addClass('btn--loading loading');
$button.attr('disabled', true);

if ($button.is('button')) {
$button.append($(
'<div class="btn__loading-icon">' +
'<span class="btn__circle btn__circle--1" />' +
'<span class="btn__circle btn__circle--2" />' +
'<span class="btn__circle btn__circle--3" />' +
'</div>'));

$button.css(`${$button.outerWidth()}px`);
}
},

/**
* Reset the button back to its original state after loading. See LeftAndMain.js.
*/
buttonReset() {
this.setButtonIsLoading(false);

const $button = this.getButton();

$button.removeClass('btn--loading loading');
$button.attr('disabled', false);
$button.find('.btn__loading-icon').remove();
$button.css('width', 'auto');
},

poll() {
const self = this;
this.buttonLoading();

$.ajax({
url: 'admin/externallinks/getJobStatus',
async: true,
success(data) {
// No report, so let user create one
if (!data || (typeof data === 'object' && data.length < 1)) {
self.buttonReset();
return;
}

// Parse data
const completed = data.Completed ? data.Completed : 0;
const total = data.Total ? data.Total : 0;

// If complete status
if (data.Status === 'Completed') {
if (self.getReloadContent()) {
$('.cms-container').loadPanel(document.location.href, null, {}, true, false);
self.setReloadContent(false);
}
$('.external-links-report__report-progress')
.text(`Report finished ${completed}/${total}`);

self.buttonReset();
return;
}

// If incomplete update status
if (completed < total) {
const percent = (completed / total) * 100;
$('.external-links-report__report-progress')
.text(`Running report ${completed}/${total} (${percent.toFixed(2)}%)`);
}

// Ensure the regular poll method is run
// kill any existing timeout
if (self.getPollTimeout() !== null) {
clearTimeout(self.getPollTimeout());
}

self.setPollTimeout(setTimeout(() => {
$('.external-links-report__create-report').poll();
}, 1000));
},
error() {
self.buttonReset();
}
});
}
});
});
}(jQuery));
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions client/src/styles/BrokenExternalLinksReport.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.external-links-report__create-report,
.external-links-report__report-progress {
margin-top: 20px;
}
8 changes: 8 additions & 0 deletions client/src/styles/sitewidecontentreport.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.gridfieldbasiccontentreport.field {
border-bottom: 1px solid #D2D5D8;
margin: 24px 0;
}

.gridfieldbasiccontentreport.field:last-of-type {
border-bottom-style: none;
}
67 changes: 67 additions & 0 deletions code/ExternalLinks/Controllers/CMSExternalLinksController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace SilverStripe\Reports\ExternalLinks\Controllers;

use SilverStripe\Admin\AdminController;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Reports\ExternalLinks\Model\BrokenExternalPageTrackStatus;
use SilverStripe\Reports\ExternalLinks\Jobs\CheckExternalLinksJob;
use SilverStripe\Reports\ExternalLinks\Tasks\CheckExternalLinksTask;
use Symbiote\QueuedJobs\Services\QueuedJobService;
use SilverStripe\PolyExecution\PolyOutput;

class CMSExternalLinksController extends AdminController
{
private static ?string $url_segment = 'externallinks';

private static string|array $required_permission_codes = [
'CMS_ACCESS_CMSMain',
];

private static $allowed_actions = [
'getJobStatus',
'start'
];

/**
* Respond to Ajax requests for info on a running job
*/
public function getJobStatus(): HTTPResponse
{
$this->getResponse()->addHeader('X-Content-Type-Options', 'nosniff');
$track = BrokenExternalPageTrackStatus::get_latest();
if ($track) {
return $this->jsonSuccess(200, [
'TrackID' => $track->ID,
'Status' => $track->Status,
'Completed' => $track->getCompletedPages(),
'Total' => $track->getTotalPages()
]);
}
return $this->jsonSuccess(200, []);
}

/**
* Starts a broken external link check
*/
public function start(): HTTPResponse
{
// return if the a job is already running
$status = BrokenExternalPageTrackStatus::get_latest();
if ($status && $status->Status == 'Running') {
return $this->jsonSuccess(200, []);
}

// Create a new job
if (class_exists(QueuedJobService::class)) {
// Force the creation of a new run
BrokenExternalPageTrackStatus::create_status();
$checkLinks = new CheckExternalLinksJob();
singleton(QueuedJobService::class)->queueJob($checkLinks);
} else {
$task = CheckExternalLinksTask::create();
$task->runLinksCheck(PolyOutput::create(PolyOutput::FORMAT_HTML));
}
return $this->jsonSuccess(200, []);
}
}
46 changes: 46 additions & 0 deletions code/ExternalLinks/Jobs/CheckExternalLinksJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace SilverStripe\Reports\ExternalLinks\Jobs;

use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJob;
use SilverStripe\Reports\ExternalLinks\Tasks\CheckExternalLinksTask;
use SilverStripe\PolyExecution\PolyOutput;

if (!class_exists(AbstractQueuedJob::class)) {
return;
}

/**
* A Job for running a external link check for published pages
*
*/
class CheckExternalLinksJob extends AbstractQueuedJob implements QueuedJob
{
public function getTitle()
{
return _t(__CLASS__ . '.TITLE', 'Checking for external broken links');
}

public function getJobType()
{
return QueuedJob::QUEUED;
}

public function getSignature()
{
return md5(get_class($this));
}

/**
* Check an individual page
*/
public function process()
{
$task = CheckExternalLinksTask::create();
$track = $task->runLinksCheck(PolyOutput::create(PolyOutput::FORMAT_ANSI), 1);
$this->currentStep = $track->CompletedPages;
$this->totalSteps = $track->TotalPages;
$this->isComplete = $track->Status === 'Completed';
}
}
Loading

0 comments on commit 579b939

Please sign in to comment.