30 |
--------------------------------------------------------------------------------
/Tests/Functional/Domain/Repository/Fixtures/tx_scheduler_task.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 131
5 | 345
6 | Not important for the test
7 | 1507140146
8 |
9 |
10 | 132
11 | 345
12 | Not important for the test
13 | 1507140147
14 |
15 |
16 | 133
17 | 345
18 | Not important for the test
19 | 1507140148
20 |
21 |
22 | 134
23 | 345
24 | Not important for the test
25 | 1507140149
26 |
27 |
28 | 135
29 | 345
30 | Not important for the test
31 | 1507140150
32 |
33 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: DEPLOY
2 |
3 | on:
4 | push:
5 | tags:
6 | - "**"
7 |
8 | jobs:
9 | TER:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 |
14 | - name: "Determine tag"
15 | id: "determine-tag"
16 | run: "echo \"::set-output name=tag::${GITHUB_REF#refs/tags/}\""
17 |
18 | - name: Deploy to TER
19 | run: |
20 | if [ -n "${{ secrets.TYPO3_ORG_USERNAME }}" ] && [ -n "${{ secrets.TYPO3_ORG_PASSWORD }}" ]; then
21 | echo -e "Preparing upload of release ${{ steps.determine-tag.outputs.tag }} to TER\n";
22 |
23 | # Install ter client
24 | composer global require helhum/ter-client
25 |
26 | # Build extension files
27 | composer extension-release
28 |
29 | # Upload
30 | TAG_MESSAGE=`git log -1 --pretty=%B`
31 | echo "Tag-Message: ${TAG_MESSAGE}"
32 | echo "Uploading release ${{ steps.determine-tag.outputs.tag }} to TER"
33 | $HOME/.composer/vendor/helhum/ter-client/ter-client upload scheduler_timeline . -u "${{ secrets.TYPO3_ORG_USERNAME }}" -p "${{ secrets.TYPO3_ORG_PASSWORD }}" -m "$TAG_MESSAGE"
34 | fi;
--------------------------------------------------------------------------------
/Classes/Interfaces/ReturnMessage.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | /**
30 | * Interface ReturnMessage
31 | *
32 | * @package AOE\SchedulerTimeline\Interfaces
33 | */
34 | interface ReturnMessage
35 | {
36 |
37 | /**
38 | * @var string return message
39 | */
40 | public function getReturnMessage();
41 | }
42 |
--------------------------------------------------------------------------------
/Documentation/Pages/Aoe.rst:
--------------------------------------------------------------------------------
1 | .. ==================================================
2 | .. FOR YOUR INFORMATION
3 | .. --------------------------------------------------
4 | .. -*- coding: utf-8 -*- with BOM.
5 |
6 | .. include:: ../Includes.txt
7 |
8 |
9 | .. _aoe:
10 |
11 |
12 | The AOE Way
13 | ====================
14 |
15 | | AOE ( `www.aoe.com `_ ) is a leading provider of Enterprise Open Source web solutions.
16 | | Using current agile development methods, more than 180 developers and consultants in 8 global locations
17 | | develop customized Open Source solutions for global Fortune 500 companies and corporations.
18 | |
19 | | For more than 15 years we have been designing and developing complex Enterprise Web Content Management
20 | | Systems, E-Commerce and Mobile Applications as well as Web Portal solutions based on Open Source
21 | | technology and successfully launched over 1,400 projects worldwide.
22 | |
23 | | The integration of Open Source software is a central element of our
24 | | corporate philosophy and key driver of our growth.
25 | |
26 | | **The sourcecode of this Extension is continuously monitored by a** `Jenkins `_ **job.**
27 | | **Checking for** `checkstyles `_, `mess `_, `duplicate code `_ **and** `code coverage `_
28 |
29 |
--------------------------------------------------------------------------------
/Resources/Private/Partials/Timeline/Detail.html:
--------------------------------------------------------------------------------
1 | {namespace s=AOE\SchedulerTimeline\ViewHelpers}
2 |
3 |
4 |
5 |
6 |
{log.task.title}
7 |
8 |
9 |
10 |
11 |
[{log.task.taskObject.additionalInformation}]
12 |
13 |
14 |
15 |
16 |
Status:
17 |
18 |
19 |
Timespan:
{log.timespan}
20 |
21 |
22 |
Duration [h:m:s]:
23 |
24 |
25 |
Process id:
{log.processid}
26 |
27 |
28 |
29 |
Exception: {log.exception.message}
30 |
31 |
32 |
33 |
34 |
{log.exception.stacktrace}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
Return message:
42 |
43 |
44 |
45 |
46 |
{log.returnmessage}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Classes/Converter/FormValueTimestampConverter.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * This file is part of the TYPO3 Scheduler Timeline Extension.
9 | *
10 | * It is free software; you can redistribute it and/or modify it under
11 | * the terms of the GNU General Public License, either version 2
12 | * of the License, or any later version.
13 | *
14 | * For the full copyright and license information, please read the
15 | * LICENSE.txt file that was distributed with this source code.
16 | *
17 | * The TYPO3 project - inspiring people to share!
18 | */
19 |
20 | class FormValueTimestampConverter
21 | {
22 | /**
23 | * @param string $value
24 | * @return string
25 | */
26 | public static function convertValueToStrToTimeValue(string $value)
27 | {
28 | $timeArray = preg_split('#(?<=\d)(?=[a-z])#i', $value);
29 | $timeArray[0] = $timeArray[0] ?? '1';
30 | $timeArray[1] = $timeArray[1] ?? 'hour';
31 | return $timeArray[0] . ' ' . self::getFullLabel($timeArray[1]);
32 | }
33 |
34 | /**
35 | * @param string $label
36 | * @return string
37 | */
38 | private function getFullLabel(string $label)
39 | {
40 | switch ($label) {
41 | case 'd':
42 | return 'day';
43 | case 'w':
44 | return 'week';
45 | case 'y':
46 | return 'year';
47 | case 'h':
48 | default:
49 | return 'hour';
50 |
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/Resources/Public/StyleSheet/bars.css:
--------------------------------------------------------------------------------
1 | .bar-red,
2 | .bar-red span,
3 | .bar-orange,
4 | .bar-orange span,
5 | .bar-yellow,
6 | .bar-yellow span,
7 | .bar-green,
8 | .bar-green span,
9 | .bar-lightblue,
10 | .bar-lightblue span,
11 | .bar-blue,
12 | .bar-blue span,
13 | .bar-lightgray,
14 | .bar-lightgray span,
15 | .bar-gray,
16 | .bar-gray span { display:block; height:16px; background-image:url(../Images/bg_notifications.png); background-repeat:no-repeat; font:bold 10px/16px Arial, Helvetica, sans-serif; text-transform:uppercase; text-align:center; padding:0 0 0 7px; margin:1px 0; white-space:nowrap; color:#fff; }
17 |
18 | .bar-red { background-position:0 0; }
19 | .bar-red span { background-position:100% 0; padding:0 7px 0 0; }
20 |
21 | .bar-orange { background-position:0 -16px; }
22 | .bar-orange span { background-position:100% -16px; padding:0 7px 0 0; }
23 |
24 | .bar-yellow { background-position:0 -32px; }
25 | .bar-yellow span { background-position:100% -32px; padding:0 7px 0 0; }
26 |
27 | .bar-green { background-position:0 -48px; }
28 | .bar-green span { background-position:100% -48px; padding:0 7px 0 0; }
29 |
30 | .bar-lightblue { background-position:0 -64px; }
31 | .bar-lightblue span { background-position:100% -64px; padding:0 7px 0 0; }
32 |
33 | .bar-blue { background-position:0 -80px; }
34 | .bar-blue span { background-position:100% -80px; padding:0 7px 0 0; }
35 |
36 | .bar-lightgray { background-position:0 -96px; }
37 | .bar-lightgray span { background-position:100% -96px; padding:0 7px 0 0; }
38 |
39 | .bar-gray { background-position:0 -112px; }
40 | .bar-gray span { background-position:100% -112px; padding:0 7px 0 0; }
--------------------------------------------------------------------------------
/Classes/Domain/Repository/TaskRepository.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | /**
30 | * Class TaskRepository
31 | *
32 | * @package AOE\SchedulerTimeline\Domain\Repository
33 | */
34 | class TaskRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
35 | {
36 |
37 | /**
38 | * Initialize object
39 | * Ignore storage pid
40 | *
41 | * @return void
42 | */
43 | public function initializeObject()
44 | {
45 | $querySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
46 | $querySettings->setRespectStoragePage(false);
47 | $this->setDefaultQuerySettings($querySettings);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Tests/Linting/Resources/Xliff.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Resources/Public/Icons/Extension.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/Tests/Functional/Domain/Repository/Fixtures/tx_schedulertimeline_domain_model_log.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1
5 | 345
6 |
7 | 1445191476
8 | 0
9 | 131
10 |
11 |
12 |
13 |
14 | 2
15 | 345
16 |
17 | 1445191514
18 |
19 | 1445192788
20 | 132
21 |
22 |
23 |
24 |
25 | 3
26 | 345
27 |
28 | 1445106499
29 |
30 | 1445110099
31 | 133
32 |
33 |
34 |
35 |
36 | 4
37 | 345
38 |
39 | 1445282899
40 |
41 | 1445286499
42 | 134
43 |
44 |
45 |
46 |
47 | 5
48 | 345
49 |
50 | 1445113699
51 | 0
52 | 134
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Documentation/Index.rst:
--------------------------------------------------------------------------------
1 | .. ==================================================
2 | .. FOR YOUR INFORMATION
3 | .. --------------------------------------------------
4 | .. -*- coding: utf-8 -*- with BOM.
5 |
6 | .. include:: Includes.txt
7 |
8 |
9 | .. _start:
10 |
11 | =============================================================
12 | Scheduler Timeline
13 | =============================================================
14 |
15 | .. only:: html
16 |
17 | :Classification:
18 | scheduler_timeline
19 |
20 | :Version:
21 | |release|
22 |
23 | :Language:
24 | en
25 |
26 | :Description:
27 | Logs information about scheduler task execution and displays them in a graphical timeline
28 |
29 | :Keywords:
30 | Scheduler,Timeline
31 |
32 | :Copyright:
33 | 2016
34 |
35 | :Author:
36 | AOE GmbH
37 |
38 | :Email:
39 | dev@aoe.com
40 |
41 | :License:
42 | Copyright 2016 AOE GmbH
43 |
44 | All rights reserved
45 |
46 | This Extension is part of the TYPO3 project. The TYPO3 project is
47 | free software; you can redistribute it and/or modify
48 | it under the terms of the GNU General Public License as published by
49 | the Free Software Foundation; either version 3 of the License, or
50 | (at your option) any later version.
51 |
52 | The GNU General Public License can be found at
53 | http://www.gnu.org/copyleft/gpl.html.
54 |
55 | This Extension is distributed in the hope that it will be useful,
56 | but WITHOUT ANY WARRANTY; without even the implied warranty of
57 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58 | GNU General Public License for more details.
59 |
60 | :Rendered:
61 | |today|
62 |
63 | The content of this document is related to TYPO3,
64 | a GNU/GPL CMS/Framework available from `www.typo3.org `_.
65 |
66 |
67 | **Table of Contents**
68 |
69 | .. toctree::
70 | :maxdepth: 5
71 | :titlesonly:
72 | :glob:
73 |
74 | Pages/Introduction
75 | Pages/Screenshots
76 | Pages/UserManual
77 | Pages/Links
78 | Pages/Aoe
79 |
--------------------------------------------------------------------------------
/Resources/Public/JavaScript/common.js:
--------------------------------------------------------------------------------
1 | $.noConflict();
2 | jQuery(function () {
3 | jQuery('.timeline-box').scrollLeft(jQuery('.timeline-panel').width());
4 |
5 | jQuery('.task, .task-title').tooltip({
6 | offsetParent: 'body',
7 | predelay: 100,
8 | position: 'bottom center',
9 | onShow: function () {
10 | this.getTrigger().addClass('active');
11 | },
12 | onHide: function () {
13 | this.getTrigger().removeClass('active');
14 | }
15 | }).dynamic();
16 |
17 | // collision detection
18 | function getPositions(box) {
19 | var $box = jQuery(box);
20 | var pos = $box.position();
21 | var width = $box.width();
22 | var height = $box.height();
23 | return [[pos.left, pos.left + width], [pos.top, pos.top + height]];
24 | }
25 |
26 | function comparePositions(p1, p2) {
27 | var x1 = p1[0] < p2[0] ? p1 : p2;
28 | var x2 = p1[0] < p2[0] ? p2 : p1;
29 | return x1[1] > x2[0] || x1[0] === x2[0] ? true : false;
30 | }
31 |
32 | function collision(a, b) {
33 | var posA = getPositions(a);
34 | var posB = getPositions(b);
35 |
36 | return (posA[1][0] == posB[1][0]) && comparePositions(posA[0], posB[0]);
37 | }
38 |
39 | jQuery('.timeline').each(function () {
40 | var $tasks = jQuery('.task', jQuery(this));
41 | var numberOfTasks = $tasks.length;
42 | for (var i = 0; i < numberOfTasks; i++) {
43 | var u = Math.min(i + 10, numberOfTasks);
44 | for (var j = i + 1; j < u; j++) {
45 | if (collision($tasks[i], $tasks[j])) {
46 | var $subject = jQuery($tasks[i]);
47 | var $object = jQuery($tasks[j]);
48 |
49 | var objectTop = parseInt($subject.css('top'));
50 |
51 | $object.css('top', (objectTop + 4) + 'px');
52 |
53 | $subject.css('height', 18);
54 | $object.css('height', 18);
55 | }
56 | }
57 | }
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/Tests/Unit/Converter/FormValueTimestampConverterTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * This file is part of the TYPO3 Scheduler Timeline Extension.
9 | *
10 | * It is free software; you can redistribute it and/or modify it under
11 | * the terms of the GNU General Public License, either version 2
12 | * of the License, or any later version.
13 | *
14 | * For the full copyright and license information, please read the
15 | * LICENSE.txt file that was distributed with this source code.
16 | *
17 | * The TYPO3 project - inspiring people to share!
18 | */
19 |
20 | use AOE\SchedulerTimeline\Converter\FormValueTimestampConverter;
21 | use Nimut\TestingFramework\TestCase\UnitTestCase;
22 |
23 |
24 | class formValueTimestampConverterTest extends UnitTestCase
25 | {
26 | /**
27 | * @test
28 | * @dataProvider convertValueToStrToTimeValueDataProvider
29 | * @return void
30 | */
31 | public function convertValueToStrToTimeValueTest(string $label, string $expected)
32 | {
33 | self::assertSame(
34 | $expected,
35 | FormValueTimestampConverter::convertValueToStrToTimeValue($label)
36 | );
37 |
38 | }
39 |
40 | /**
41 | * @return array
42 | */
43 | public function convertValueToStrToTimeValueDataProvider()
44 | {
45 | return [
46 | '1 Hours' => [
47 | 'label' => '1h',
48 | 'expected' => '1 hour'
49 | ],
50 | '3 Hours' => [
51 | 'label' => '3h',
52 | 'expected' => '3 hour'
53 | ],
54 | '1 Day' => [
55 | 'label' => '1d',
56 | 'expected' => '1 day'
57 | ],
58 | '3 Days' => [
59 | 'label' => '3d',
60 | 'expected' => '3 day'
61 | ],
62 | '1 Week' => [
63 | 'label' => '1w',
64 | 'expected' => '1 week'
65 | ],
66 | '2 Weeks' => [
67 | 'label' => '2w',
68 | 'expected' => '2 week'
69 | ],
70 | '1 Year' => [
71 | 'label' => '1y',
72 | 'expected' => '1 year'
73 | ],
74 | ];
75 | }
76 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aoe/scheduler_timeline",
3 | "description": "Logs information about scheduler task execution and displays them in a graphical timeline",
4 | "type": "typo3-cms-extension",
5 | "keywords": ["TYPO3 CMS", "Scheduler", "Timeline"],
6 | "license": ["GPL-2.0+"],
7 | "homepage": "https://github.com/AOEpeople/scheduler_timeline",
8 | "support": {
9 | "issues": "https://github.com/AOEpeople/scheduler_timeline/issues"
10 | },
11 | "require": {
12 | "php": ">=7.0",
13 | "typo3/cms-core": "^8.7",
14 | "typo3/cms-extbase": "^8.7",
15 | "typo3/cms-scheduler": "^8.7",
16 | "typo3fluid/fluid": "^2.6"
17 | },
18 | "require-dev": {
19 | "nimut/testing-framework": "^4.1"
20 | },
21 | "autoload": {
22 | "psr-4": {
23 | "AOE\\SchedulerTimeline\\": "Classes"
24 | }
25 | },
26 | "autoload-dev": {
27 | "psr-4": {
28 | "AOE\\SchedulerTimeline\\Tests\\": "Tests"
29 | }
30 | },
31 | "config": {
32 | "vendor-dir": ".Build/vendor",
33 | "bin-dir": ".Build/bin"
34 | },
35 | "scripts": {
36 | "post-autoload-dump": [
37 | "mkdir -p .Build/Web/typo3conf/ext/",
38 | "[ -L .Build/Web/typo3conf/ext/scheduler_timeline ] || ln -snvf ../../../../. .Build/Web/typo3conf/ext/scheduler_timeline"
39 | ],
40 | "test:unit": [
41 | "[ -e .Build/bin/phpunit ] || composer update",
42 | "TYPO3_PATH_ROOT=$(pwd)/.Build/Web .Build/bin/phpunit -c .Build/vendor/nimut/testing-framework/res/Configuration/UnitTests.xml Tests/Unit/"
43 | ],
44 | "test:functional": [
45 | "[ -e .Build/bin/phpunit ] || composer update",
46 | "TYPO3_PATH_ROOT=$(pwd)/.Build/Web .Build/bin/phpunit -c .Build/vendor/nimut/testing-framework/res/Configuration/FunctionalTests.xml Tests/Functional",
47 | "[ -L .Build/Web/typo3conf/ext/scheduler_timeline ] || ln -snvf ../../../../. .Build/Web/typo3conf/ext/scheduler_timeline"
48 | ],
49 | "extension-release": [
50 | "rm -rf Tests/",
51 | "rm .gitignore",
52 | "rm .scrutinizer.yml",
53 | "rm disabled.travis.yml"
54 | ]
55 | },
56 | "extra": {
57 | "branch-alias": {
58 | "dev-master": "8.1.0-dev"
59 | },
60 | "typo3/cms": {
61 | "cms-package-dir": "{$vendor-dir}/typo3/cms",
62 | "web-dir": ".Build/Web"
63 | },
64 | "helhum/typo3-console": {
65 | "install-extension-dummy": false
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [ push, pull_request ]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | fail-fast: false
12 | matrix:
13 | typo3: [ ^8.7 ]
14 | php: [ '7.2', '7.4' ]
15 |
16 | steps:
17 | - name: Start database server
18 | run: sudo /etc/init.d/mysql start
19 |
20 | - name: Checkout
21 | uses: actions/checkout@v2
22 |
23 | - name: Set up PHP Version ${{ matrix.php }}
24 | uses: shivammathur/setup-php@v2
25 | with:
26 | php-version: ${{ matrix.php }}
27 | tools: composer:v2
28 |
29 | - name: Environment Check
30 | run: |
31 | php --version
32 | composer --version
33 |
34 | - name: Validate composer.json and composer.lock
35 | run: composer validate
36 |
37 | - name: Install dependencies with nimut/typo3-complete:${{ matrix.typo3 }}
38 | run: |
39 | composer require --dev nimut/typo3-complete:${{ matrix.typo3 }} --no-progress
40 | git checkout composer.json
41 | ln -nfs .Build/vendor/typo3/cms/typo3 typo3
42 |
43 | - name: Lint PHP
44 | run: find . -name \*.php ! -path "./.Build/*" ! -path "./scripts/*" ! -path "./typo3_src/*" | parallel --gnu php -d display_errors=stderr -l {} > /dev/null \;
45 |
46 | - name: Unit Tests with coverage
47 | if: matrix.typo3 == '^8.7'
48 | run: |
49 | export "UNIT_XML"=.Build/vendor/nimut/testing-framework/res/Configuration/UnitTests.xml
50 | .Build/bin/phpunit --coverage-clover=unittest-coverage.clover --colors -c $UNIT_XML Tests/Unit/
51 |
52 | - name: Functional Tests with coverage
53 | run: |
54 | export "FUNCTIONAL_XML"=.Build/vendor/nimut/testing-framework/res/Configuration/FunctionalTests.xml
55 | find 'Tests/Functional' -wholename '*Test.php' | parallel --gnu 'echo; echo "Running functional test suite {}"; .Build/bin/phpunit --coverage-clover={}functionaltest-coverage.clover --colors -c $FUNCTIONAL_XML {}'
56 | if: matrix.typo3 == '^8.7'
57 | env:
58 | typo3DatabaseHost: 127.0.0.1
59 | typo3DatabaseName: typo3
60 | typo3DatabasePassword: root
61 | typo3DatabaseUsername: root
62 |
63 | - name: Upload coverage results to Scrutinizer
64 | if: matrix.typo3 == '^8.7'
65 | run: |
66 | wget https://scrutinizer-ci.com/ocular.phar
67 | php ocular.phar code-coverage:upload --format=php-clover unittest-coverage.clover
68 | find 'Tests/Functional' -wholename '*Test.php' -exec php ocular.phar code-coverage:upload --format=php-clover {}functionaltest-coverage.clover \;
--------------------------------------------------------------------------------
/Classes/ViewHelpers/DurationViewHelper.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * All rights reserved
10 | *
11 | * This script is part of the TYPO3 project. The TYPO3 project is
12 | * free software; you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation; either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * The GNU General Public License can be found at
18 | * http://www.gnu.org/copyleft/gpl.html.
19 | *
20 | * This script is distributed in the hope that it will be useful,
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 | * GNU General Public License for more details.
24 | *
25 | * This copyright notice MUST APPEAR in all copies of the script!
26 | ***************************************************************/
27 |
28 | use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
29 | use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
30 | use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
31 | use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
32 |
33 | /**
34 | * Class DurationViewHelper
35 | *
36 | * @package AOE\SchedulerTimeline\ViewHelpers
37 | */
38 | class DurationViewHelper extends AbstractViewHelper implements CompilableInterface
39 | {
40 |
41 | use CompileWithRenderStatic;
42 |
43 | /**
44 | * Initializes the arguments
45 | */
46 | public function initializeArguments()
47 | {
48 | parent::initializeArguments();
49 | $this->registerArgument('duration', 'string', 'Duration of the process', true);
50 | }
51 |
52 | /**
53 | *
54 | * @param array $arguments
55 | * @param \Closure $renderChildrenClosure
56 | * @param RenderingContextInterface $renderingContext
57 | *
58 | * @return string
59 | */
60 | public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
61 | {
62 | $duration = $arguments['duration'];
63 |
64 | $hours = intval(intval($duration) / 3600);
65 | $hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
66 | $minutes = intval(($duration / 60) % 60);
67 | $seconds = intval($duration % 60);
68 |
69 | $result = $seconds;
70 | if (intval($minutes) || intval($hours)) {
71 | $seconds = str_pad($seconds, 2, '0', STR_PAD_LEFT);
72 | $result = $minutes . ':' . $seconds;
73 | }
74 | if (intval($hours)) {
75 | $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
76 | $result = $hours . ':' . $minutes . ':' . $seconds;
77 | }
78 | return $result;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Resources/Public/StyleSheet/timeline.css:
--------------------------------------------------------------------------------
1 | #contentwrapper {
2 | float: left;
3 | width: 100%;
4 | }
5 |
6 | #contentcolumn {
7 | margin-left: 300px; /* Set left margin to LeftColumnWidth */
8 | }
9 |
10 | #leftcolumn {
11 | float: left;
12 | width: 300px; /* Width of left column */
13 | margin-left: -100%;
14 | }
15 |
16 | .configuration {
17 | padding: 5px;
18 | }
19 |
20 | #leftcolumn .row {
21 | background-color: #F6F6F6;
22 | border-right: 1px solid #DADFE0;
23 | }
24 |
25 | #leftcolumn .row.hours {
26 | background-color: transparent;
27 | text-align: right;
28 | padding-right: 5px;
29 | font-size: 10px;
30 | }
31 |
32 | #now {
33 | position: absolute;
34 | width: 1px;
35 | height: 100%;
36 | background-color: red;
37 | }
38 |
39 | div.row {
40 | border-bottom: 1px solid #DADFE0;
41 | padding: 0;
42 | margin: 0;
43 | height: 40px;
44 | overflow: hidden;
45 | }
46 |
47 | div.timeline-box {
48 | overflow: auto;
49 | }
50 |
51 | div.timeline-panel {
52 | background-image: url(../Images/hour.png);
53 | border-right: 1px solid black;
54 | position: relative;
55 | }
56 |
57 | div.timeline {
58 | position: relative;
59 | }
60 |
61 | div.hours {
62 | height: 20px;
63 | }
64 |
65 | .detailwrap {
66 | width: 100%;
67 | height: 100%;
68 | }
69 |
70 | .details {
71 | display: none;
72 | background-color: white;
73 | border: 1px solid black;
74 | z-index: 1000;
75 | max-width: 400px;
76 | }
77 |
78 | .details pre {
79 | background-color: white;
80 | overflow: auto;
81 | max-width: 385px;
82 | font-size: 8pt;
83 | line-height: 9pt;
84 | }
85 |
86 | .hour {
87 | width: 240px;
88 | float: left;
89 | text-align: center;
90 | }
91 |
92 | .details-headline {
93 | width: 100%;
94 | height: 28px;
95 | }
96 |
97 | .task-info-details .details-headline {
98 | width: 100%;
99 | height: auto;
100 | background-color: grey;
101 | }
102 |
103 | .details-headline h3 {
104 | padding: 5px;
105 | color: white;
106 | margin: 0;
107 | }
108 |
109 | .details-content {
110 | padding: 5px;
111 | }
112 |
113 | .details-content td.label {
114 | font-weight: bold;
115 | color: black;
116 | }
117 |
118 | .caption-container {
119 | width: 500px;
120 | overflow: hidden;
121 | }
122 |
123 | .task {
124 | position: absolute;
125 | height: 24px;
126 | top: 8px;
127 | cursor: default;
128 | }
129 |
130 | .task-title {
131 | line-height: 16px;
132 | cursor: default;
133 | }
134 |
135 | .status {
136 | width: 100px;
137 | }
138 |
139 | .details-headline, .task { background-image: url(../Images/gradient.png); }
140 |
141 | .details-headline.success, .task.success { background-color: #36B963; }
142 | .details-headline.pending, .task.pending { background-color: #A9ABA8; }
143 | .details-headline.error, .task.error { background-color: #E41300; }
144 | .details-headline.missed, .task.missed { background-color: #F75300; }
145 | .details-headline.running, .task.running { background-color: #FE9D00; }
146 |
147 | div.task.active, div.task:hover { background-color: #00A2FA; }
--------------------------------------------------------------------------------
/Classes/ViewHelpers/IncreaseViewHelper.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * All rights reserved
10 | *
11 | * This script is part of the TYPO3 project. The TYPO3 project is
12 | * free software; you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation; either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * The GNU General Public License can be found at
18 | * http://www.gnu.org/copyleft/gpl.html.
19 | *
20 | * This script is distributed in the hope that it will be useful,
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 | * GNU General Public License for more details.
24 | *
25 | * This copyright notice MUST APPEAR in all copies of the script!
26 | ***************************************************************/
27 |
28 | use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
29 | use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
30 | use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
31 | use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
32 |
33 | /**
34 | * Class IncreaseViewHelper
35 | *
36 | * @package AOE\SchedulerTimeline\ViewHelpers
37 | */
38 | class IncreaseViewHelper extends AbstractViewHelper implements CompilableInterface
39 | {
40 | use CompileWithRenderStatic;
41 |
42 | /**
43 | * View helper returns HTML, thus we need to disable output escaping
44 | *
45 | * @var bool
46 | */
47 | protected $escapeOutput = false;
48 |
49 | /**
50 | * Initializes the arguments
51 | */
52 | public function initializeArguments()
53 | {
54 | parent::initializeArguments();
55 | $this->registerArgument('start', 'string', 'Start time', true);
56 | $this->registerArgument('end', 'string', 'End time', true);
57 | $this->registerArgument('interval', 'string', 'Interval of hours', false, '1');
58 | $this->registerArgument('iterator', 'string', 'Iterator of hours', false, 'i');
59 | }
60 |
61 | /**
62 | *
63 | * @param array $arguments
64 | * @param \Closure $renderChildrenClosure
65 | * @param RenderingContextInterface $renderingContext
66 | *
67 | * @return string
68 | */
69 | public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
70 | {
71 | $templateVariableContainer = $renderingContext->getVariableProvider();
72 |
73 | $start = $arguments['start'];
74 | $end = $arguments['end'];
75 | $interval = $arguments['interval'];
76 | $iterator = $arguments['iterator'];
77 |
78 | $result = '';
79 | for ($i = $start; $i < $end; $i += $interval) {
80 | $templateVariableContainer->add($iterator, $i);
81 | $result .= $renderChildrenClosure();
82 | $templateVariableContainer->remove($iterator);
83 | }
84 | return $result;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Classes/ViewHelpers/StatusViewHelper.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * All rights reserved
10 | *
11 | * This script is part of the TYPO3 project. The TYPO3 project is
12 | * free software; you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation; either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * The GNU General Public License can be found at
18 | * http://www.gnu.org/copyleft/gpl.html.
19 | *
20 | * This script is distributed in the hope that it will be useful,
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 | * GNU General Public License for more details.
24 | *
25 | * This copyright notice MUST APPEAR in all copies of the script!
26 | ***************************************************************/
27 |
28 | use AOE\SchedulerTimeline\Domain\Model\Log;
29 | use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
30 | use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
31 | use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
32 | use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
33 |
34 | /**
35 | * Class StatusViewHelper
36 | *
37 | * @package AOE\SchedulerTimeline\ViewHelpers
38 | */
39 | class StatusViewHelper extends AbstractViewHelper implements CompilableInterface
40 | {
41 |
42 | use CompileWithRenderStatic;
43 |
44 | /**
45 | * View helper returns HTML, thus we need to disable output escaping
46 | *
47 | * @var bool
48 | */
49 | protected $escapeOutput = false;
50 |
51 | /**
52 | * Initializes the arguments
53 | */
54 | public function initializeArguments()
55 | {
56 | parent::initializeArguments();
57 | $this->registerArgument('status', 'string', 'the status of the process', true);
58 | }
59 |
60 | /**
61 | * Prints status html for process
62 | *
63 | * @param array $arguments
64 | * @param \Closure $renderChildrenClosure
65 | * @param RenderingContextInterface $renderingContext
66 | *
67 | * @return string
68 | */
69 | public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
70 | {
71 |
72 | $status = $arguments['status'];
73 |
74 | switch ($status) {
75 | case Log::STATUS_SUCCESS:
76 | $result = '' . $status . '';
77 | break;
78 | case Log::STATUS_PENDING:
79 | $result = '' . $status . '';
80 | break;
81 | case Log::STATUS_RUNNING:
82 | $result = '' . $status . '';
83 | break;
84 | case Log::STATUS_MISSED:
85 | $result = '' . $status . '';
86 | break;
87 | case Log::STATUS_ERROR:
88 | $result = '' . $status . '';
89 | break;
90 | default:
91 | $result = $status;
92 | }
93 | return $result;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Classes/ViewHelpers/Format/SpeakingDateViewHelper.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * All rights reserved
10 | *
11 | * This script is part of the TYPO3 project. The TYPO3 project is
12 | * free software; you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation; either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * The GNU General Public License can be found at
18 | * http://www.gnu.org/copyleft/gpl.html.
19 | *
20 | * This script is distributed in the hope that it will be useful,
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 | * GNU General Public License for more details.
24 | *
25 | * This copyright notice MUST APPEAR in all copies of the script!
26 | ***************************************************************/
27 |
28 | use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
29 | use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
30 | use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
31 | use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
32 |
33 | /**
34 | * Class SpeakingDateViewHelper
35 | *
36 | * @package AOE\SchedulerTimeline\ViewHelpers\Format
37 | */
38 | class SpeakingDateViewHelper extends AbstractViewHelper implements CompilableInterface
39 | {
40 | use CompileWithRenderStatic;
41 |
42 | /**
43 | * Initializes the arguments
44 | */
45 | public function initializeArguments()
46 | {
47 | parent::initializeArguments();
48 | $this->registerArgument('timestamp', 'string', 'Timestamp', true);
49 | $this->registerArgument('defaultFormat', 'string', 'Default time format', false, 'Y.m.d H:i');
50 | $this->registerArgument('todayFormat', 'string', 'Time format for today', false, 'H:i');
51 | $this->registerArgument('tomorrowFormat', 'string', 'Time format for tomorrow', false, '\T\o\m\m\o\r\o\w, H:i');
52 | $this->registerArgument('yesterdayFormat', 'string', 'Time format for yesterday', false, '\Y\e\s\t\e\r\d\a\y, H:i');
53 | }
54 |
55 | /**
56 | *
57 | * @param array $arguments
58 | * @param \Closure $renderChildrenClosure
59 | * @param RenderingContextInterface $renderingContext
60 | * @return string
61 | */
62 | public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
63 | {
64 |
65 | $timestamp = $arguments['timestamp'];
66 | $defaultFormat = $arguments['defaultFormat'];
67 | $todayFormat = $arguments['todayFormat'];
68 | $tomorrowFormat = $arguments['tomorrowFormat'];
69 | $yesterdayFormat = $arguments['yesterdayFormat'];
70 |
71 | $day = date('Ymd', $timestamp);
72 | if ($todayFormat && (date('Ymd') == $day)) {
73 | $result = date($todayFormat, $timestamp);
74 | } elseif ($tomorrowFormat && (date('Ymd', strtotime('+1 day')) == $day)) {
75 | $result = date($tomorrowFormat, $timestamp);
76 | } elseif ($yesterdayFormat && (date('Ymd', strtotime('-1 day')) == $day)) {
77 | $result = date($yesterdayFormat, $timestamp);
78 | } else {
79 | $result = date($defaultFormat, $timestamp);
80 | }
81 | return $result;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Classes/ViewHelpers/GanttViewHelper.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * All rights reserved
10 | *
11 | * This script is part of the TYPO3 project. The TYPO3 project is
12 | * free software; you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation; either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * The GNU General Public License can be found at
18 | * http://www.gnu.org/copyleft/gpl.html.
19 | *
20 | * This script is distributed in the hope that it will be useful,
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 | * GNU General Public License for more details.
24 | *
25 | * This copyright notice MUST APPEAR in all copies of the script!
26 | ***************************************************************/
27 |
28 | use AOE\SchedulerTimeline\Domain\Model\Log;
29 | use TYPO3\CMS\Core\Utility\GeneralUtility;
30 | use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
31 | use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
32 | use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
33 | use TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder;
34 | use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
35 |
36 | /**
37 | * Class GanttViewHelper
38 | *
39 | * @package AOE\SchedulerTimeline\ViewHelpers
40 | */
41 | class GanttViewHelper extends AbstractTagBasedViewHelper implements CompilableInterface
42 | {
43 |
44 | use CompileWithRenderStatic;
45 |
46 | /**
47 | * Initializes the arguments
48 | */
49 | public function initializeArguments()
50 | {
51 | parent::initializeArguments();
52 | $this->registerArgument('log', '\AOE\SchedulerTimeline\Domain\Model\Log', 'Log Record', true);
53 | $this->registerArgument('starttime', 'string', 'Start time', true);
54 | $this->registerArgument('zoom', 'string', 'Zoom level', true);
55 | }
56 |
57 | /**
58 | *
59 | * @param array $arguments
60 | * @param \Closure $renderChildrenClosure
61 | * @param RenderingContextInterface $renderingContext
62 | *
63 | * @return string
64 | */
65 | public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
66 | {
67 | /** @var TagBuilder $tag */
68 | $tag = GeneralUtility::makeInstance(TagBuilder::class);
69 |
70 | /** @var Log $log */
71 | $log = $arguments['log'];
72 | $zoom = $arguments['zoom'];
73 | $startTime = $arguments['starttime'];
74 |
75 | $duration = $log->getDuration() / $zoom;
76 | $duration = ceil($duration / 4) * 4 - 1; // round to numbers dividable by 4, then remove 1 px border
77 | $duration = max($duration, 3);
78 |
79 | $offset = ($log->getStarttime() - $startTime) / $zoom;
80 | if ($offset < 0) { // cut bar
81 | $duration += $offset;
82 | $offset = 0;
83 | }
84 | $tag->setTagName('div');
85 | $tag->addAttribute('style', sprintf('width: %spx; left: %spx;', $duration, $offset));
86 | $tag->addAttribute('class', 'task ' . $log->getStatus());
87 | $tag->addAttribute('id', 'uid_' . $log->getUid());
88 | $tag->setContent($renderChildrenClosure());
89 | return $tag->render();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Tests/Unit/Domain/Repository/LogRepositoryTest.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | use AOE\SchedulerTimeline\Domain\Model\Log;
30 | use AOE\SchedulerTimeline\Domain\Model\Task;
31 | use AOE\SchedulerTimeline\Domain\Repository\LogRepository;
32 | use TYPO3\CMS\Extbase\Object\ObjectManager;
33 |
34 | /**
35 | * Class LogRepositoryTest
36 | * @package AOE\SchedulerTimeline\Tests\Unit\Domain\Repository
37 | */
38 | class LogRepositoryTest extends \Nimut\TestingFramework\TestCase\UnitTestCase
39 | {
40 |
41 | public function setUp()
42 | {
43 | // Make sure that timezone is always the same in all testing environments
44 | date_default_timezone_set('UTC');
45 | }
46 |
47 | /**
48 | * @test
49 | */
50 | public function findGroupedByTaskIgnoresLogEntriesForDeletedTasks()
51 | {
52 | $logCollection = self::getLogCollection();
53 | $logRepository = $this->getMockBuilder(LogRepository::class)
54 | ->setConstructorArgs([new ObjectManager()])
55 | ->setMethods(['findByTime'])
56 | ->getMock();
57 | $logRepository->expects(self::any())->method('findByTime')->willReturn($logCollection);
58 |
59 | $logs = $logRepository->findGroupedByTask(0, time());
60 |
61 | self::assertCount(3, $logs);
62 | self::assertSame($logCollection[0]->getTask(), $logs[1]['task']);
63 | self::assertSame($logCollection[1]->getTask(), $logs[2]['task']);
64 | // The third log collection item is not returned as it has no Task object attached
65 | self::assertSame($logCollection[3]->getTask(), $logs[4]['task']);
66 | }
67 |
68 | /**
69 | * Gets a collection of Log objects, one without an attached Task object
70 | *
71 | * @return array
72 | */
73 | private static function getLogCollection()
74 | {
75 | return array(
76 | self::getLogItem(self::getTaskItem(1)),
77 | self::getLogItem(self::getTaskItem(2)),
78 | self::getLogItem(),
79 | self::getLogItem(self::getTaskItem(4))
80 | );
81 | }
82 |
83 | /**
84 | * Returns a Log object
85 | *
86 | * @param Task $task
87 | * @return Log
88 | */
89 | private static function getLogItem(Task $task = null)
90 | {
91 | $log = new Log();
92 | $log->_setProperty('task', $task);
93 |
94 | return $log;
95 | }
96 |
97 | /**
98 | * Returns a Task object
99 | *
100 | * @param integer $uid
101 | * @return Task
102 | */
103 | private static function getTaskItem($uid = 0)
104 | {
105 | $task = new Task();
106 | $task->_setProperty('uid', $uid);
107 |
108 | return $task;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Resources/Private/Templates/Timeline/Timeline.html:
--------------------------------------------------------------------------------
1 | {namespace s=AOE\SchedulerTimeline\ViewHelpers}
2 |
3 |
4 |
5 |
6 |
7 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/Tests/Unit/Domain/Model/TaskTest.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | use AOE\SchedulerTimeline\Domain\Model\Task;
30 | use Nimut\TestingFramework\TestCase\UnitTestCase;
31 |
32 | /**
33 | * Class TaskTest
34 | *
35 | * @package AOE\SchedulerTimeline\Tests\Unit\Domain\Model
36 | */
37 | class TaskTest extends UnitTestCase
38 | {
39 |
40 | /**
41 | * @var Task
42 | */
43 | protected $subject;
44 |
45 | /**
46 | * Sets up the test case
47 | */
48 | public function setUp()
49 | {
50 | $this->subject = $this->getAccessibleMock('AOE\\SchedulerTimeline\\Domain\\Model\\Task', array('dummy'));
51 | }
52 |
53 | /**
54 | * @test
55 | * @return void
56 | */
57 | public function getClassReturnsClassNameOfSerializedTaskObject()
58 | {
59 | $taskFixture = new \AOE\SchedulerTimeline\Tests\Unit\Domain\Model\Fixtures\EmptyTask();
60 | $serializedTaskFixture = serialize($taskFixture);
61 |
62 | $this->subject->_set('serializedTaskObject', $serializedTaskFixture);
63 | $this->assertEquals('AOE\\SchedulerTimeline\\Tests\\Unit\\Domain\\Model\\Fixtures\\EmptyTask', $this->subject->getClassname());
64 | }
65 |
66 | /**
67 | * @test
68 | * @return void
69 | */
70 | public function getTaskObjectReturnsClassOfSerializedTaksObject()
71 | {
72 | $taskFixture = new \AOE\SchedulerTimeline\Tests\Unit\Domain\Model\Fixtures\EmptyTask();
73 | $serializedTaskFixture = serialize($taskFixture);
74 |
75 | $this->subject->_set('serializedTaskObject', $serializedTaskFixture);
76 | $this->assertEquals($taskFixture, $this->subject->getTaskObject());
77 | }
78 |
79 | /**
80 | * @test
81 | * @return void
82 | */
83 | public function getLogFilePathReturnsFalseIfSerializedTaskObjectDoesntHaveMethodGetLogFilePath()
84 | {
85 | $taskFixture = new \AOE\SchedulerTimeline\Tests\Unit\Domain\Model\Fixtures\EmptyTask();
86 | $serializedTaskFixture = serialize($taskFixture);
87 |
88 | $this->subject->_set('serializedTaskObject', $serializedTaskFixture);
89 | $this->assertFalse($this->subject->getLogFilePath());
90 | }
91 |
92 | /**
93 | * @test
94 | * @return void
95 | */
96 | public function getLogFilePathReturnsPathFromSerializedTaskObject()
97 | {
98 | $taskFixture = new \AOE\SchedulerTimeline\Tests\Unit\Domain\Model\Fixtures\TaskWithLogFilePath();
99 | $serializedTaskFixture = serialize($taskFixture);
100 |
101 | $this->subject->_set('serializedTaskObject', $serializedTaskFixture);
102 | $this->assertEquals('some/file/path', $this->subject->getLogFilePath());
103 | }
104 |
105 | /**
106 | * @test
107 | * @expectedException \Exception
108 | * @expectedExceptionCode 1450187123
109 | * @return void
110 | */
111 | public function getTaskObjectThrowsExceptionIfSerializedTaskObjectIsNotSet()
112 | {
113 | $this->subject->getTaskObject();
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/Classes/Domain/Repository/LogRepository.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | /**
30 | * Class LogRepository
31 | *
32 | * @package AOE\SchedulerTimeline\Domain\Repository
33 | */
34 | class LogRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
35 | {
36 |
37 | /**
38 | * @var int min date timestamp
39 | */
40 | protected $minDate;
41 |
42 | /**
43 | * @var int max date timestamp
44 | */
45 | protected $maxDate;
46 |
47 | /**
48 | * Initialize object
49 | * Ignore storage pid
50 | *
51 | * @return void
52 | */
53 | public function initializeObject()
54 | {
55 | $querySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
56 | $querySettings->setRespectStoragePage(false);
57 | $this->setDefaultQuerySettings($querySettings);
58 | }
59 |
60 | /**
61 | * Find logs by time
62 | *
63 | * @param int $starttime
64 | * @param int $endtime
65 | * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
66 | */
67 | public function findByTime($starttime, $endtime)
68 | {
69 | $query = $this->createQuery();
70 | $query->matching(
71 | $query->logicalAnd(
72 | $query->logicalOr(
73 | $query->greaterThanOrEqual('endtime', $starttime),
74 | $query->equals('endtime', 0)
75 | ),
76 | $query->lessThanOrEqual('starttime', $endtime)
77 | )
78 | );
79 | $query->setOrderings(array('starttime' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING));
80 | return $query->execute();
81 | }
82 |
83 | /**
84 | * Find logs grouped by task
85 | *
86 | * @return array array( => array('task' => , 'logs' => array(, ...) ), ...)
87 | */
88 | public function findGroupedByTask(int $startTime, int $endTime)
89 | {
90 | $logs = $this->findByTime($startTime, $endTime);
91 | $result = array();
92 | foreach ($logs as $log) { /* @var $log \AOE\SchedulerTimeline\Domain\Model\Log */
93 | $task = $log->getTask();
94 | if (NULL === $task) {
95 | continue;
96 | }
97 |
98 | // min/max
99 | $startTime = $log->getStarttime();
100 | $this->minDate = is_null($this->minDate) ? $startTime : min($this->minDate, $startTime);
101 | $this->maxDate = is_null($this->maxDate) ? $startTime : max($this->maxDate, $startTime);
102 |
103 | $result[$task->getUid()]['task'] = $task;
104 | $result[$task->getUid()]['logs'][] = $log;
105 | }
106 | return $result;
107 | }
108 |
109 | /**
110 | * Get min date (from findGroupedByTask)
111 | *
112 | * @return int
113 | */
114 | public function getMinDate()
115 | {
116 | return $this->minDate;
117 | }
118 |
119 | /**
120 | * Get max date (from findGroupedByTask)
121 | *
122 | * @return int
123 | */
124 | public function getMaxDate()
125 | {
126 | return $this->maxDate;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Resources/Public/JavaScript/tooltip.dynamic.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * jQuery Tools @VERSION / Tooltip Dynamic Positioning
4 | *
5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
6 | *
7 | * http://flowplayer.org/tools/tooltip/dynamic.html
8 | *
9 | * Since: July 2009
10 | * Date: @DATE
11 | */
12 | (function($) {
13 |
14 | // version number
15 | var t = $.tools.tooltip;
16 |
17 | t.dynamic = {
18 | conf: {
19 | classNames: "top right bottom left"
20 | }
21 | };
22 |
23 | /*
24 | * See if element is on the viewport. Returns an boolean array specifying which
25 | * edges are hidden. Edges are in following order:
26 | *
27 | * [top, right, bottom, left]
28 | *
29 | * For example following return value means that top and right edges are hidden
30 | *
31 | * [true, true, false, false]
32 | *
33 | */
34 | function getCropping(el) {
35 |
36 | var w = $(window);
37 | var right = w.width() + w.scrollLeft();
38 | var bottom = w.height() + w.scrollTop();
39 |
40 | return [
41 | el.offset().top <= w.scrollTop(), // top
42 | right <= el.offset().left + el.width(), // right
43 | bottom <= el.offset().top + el.height(), // bottom
44 | w.scrollLeft() >= el.offset().left // left
45 | ];
46 | }
47 |
48 | /*
49 | Returns true if all edges of an element are on viewport. false if not
50 |
51 | @param crop the cropping array returned by getCropping function
52 | */
53 | function isVisible(crop) {
54 | var i = crop.length;
55 | while (i--) {
56 | if (crop[i]) { return false; }
57 | }
58 | return true;
59 | }
60 |
61 | // dynamic plugin
62 | $.fn.dynamic = function(conf) {
63 |
64 | if (typeof conf == 'number') { conf = {speed: conf}; }
65 |
66 | conf = $.extend({}, t.dynamic.conf, conf);
67 |
68 | var cls = conf.classNames.split(/\s/), orig;
69 |
70 | this.each(function() {
71 |
72 | var api = $(this).tooltip().onBeforeShow(function(e, pos) {
73 |
74 | // get nessessary variables
75 | var tip = this.getTip(), tipConf = this.getConf();
76 |
77 | /*
78 | We store the original configuration and use it to restore back to the original state.
79 | */
80 | if (!orig) {
81 | orig = [
82 | tipConf.position[0],
83 | tipConf.position[1],
84 | tipConf.offset[0],
85 | tipConf.offset[1],
86 | $.extend({}, tipConf)
87 | ];
88 | }
89 |
90 | /*
91 | display tip in it's default position and by setting visibility to hidden.
92 | this way we can check whether it will be on the viewport
93 | */
94 | $.extend(tipConf, orig[4]);
95 | tipConf.position = [orig[0], orig[1]];
96 | tipConf.offset = [orig[2], orig[3]];
97 |
98 | tip.css({
99 | visibility: 'hidden',
100 | position: 'absolute',
101 | top: pos.top,
102 | left: pos.left
103 | }).show();
104 |
105 | // now let's see for hidden edges
106 | var crop = getCropping(tip);
107 |
108 | // possibly alter the configuration
109 | if (!isVisible(crop)) {
110 |
111 | // change the position and add class
112 | if (crop[2]) { $.extend(tipConf, conf.top); tipConf.position[0] = 'top'; tip.addClass(cls[0]); }
113 | if (crop[3]) { $.extend(tipConf, conf.right); tipConf.position[1] = 'right'; tip.addClass(cls[1]); }
114 | if (crop[0]) { $.extend(tipConf, conf.bottom); tipConf.position[0] = 'bottom'; tip.addClass(cls[2]); }
115 | if (crop[1]) { $.extend(tipConf, conf.left); tipConf.position[1] = 'left'; tip.addClass(cls[3]); }
116 |
117 | // vertical offset
118 | if (crop[0] || crop[2]) { tipConf.offset[0] *= -1; }
119 |
120 | // horizontal offset
121 | if (crop[1] || crop[3]) { tipConf.offset[1] *= -1; }
122 | }
123 |
124 | tip.css({visibility: 'visible'}).hide();
125 |
126 | });
127 |
128 | // restore positioning as soon as possible
129 | api.onBeforeShow(function() {
130 | var c = this.getConf(), tip = this.getTip();
131 | setTimeout(function() {
132 | c.position = [orig[0], orig[1]];
133 | c.offset = [orig[2], orig[3]];
134 | }, 0);
135 | });
136 |
137 | // remove custom class names and restore original effect
138 | api.onHide(function() {
139 | var tip = this.getTip();
140 | tip.removeClass(conf.classNames);
141 | });
142 |
143 | ret = api;
144 |
145 | });
146 |
147 | return conf.api ? ret : this;
148 | };
149 |
150 | }) (jQuery);
151 |
--------------------------------------------------------------------------------
/disabled.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | notifications:
4 | email:
5 | on_success: never
6 | on_failure: never
7 |
8 | sudo: false
9 |
10 | addons:
11 | apt:
12 | packages:
13 | - parallel
14 | - libxml2-utils
15 | - nodejs
16 | - npm
17 |
18 | services:
19 | - mysql
20 |
21 | cache:
22 | directories:
23 | - $HOME/.composer/cache
24 |
25 | before_install:
26 | - composer self-update
27 | - composer --version
28 |
29 | before_script:
30 | # Enables us to test dev-master
31 | - composer config minimum-stability dev
32 | - composer config prefer-stable true
33 | # Installs nimut/typo3-complete
34 | - travis_wait 30 composer require --dev nimut/typo3-complete=$TYPO3_VERSION
35 | - export "TYPO3_PATH_WEB"=$PWD/.Build/Web;
36 | # Locating UnitTests.xml
37 | - export "UNIT_XML"='.Build/vendor/nimut/testing-framework/res/Configuration/UnitTests.xml'
38 | # Location FunctionalTests.xml
39 | - export "FUNCTIONAL_XML"='.Build/vendor/nimut/testing-framework/res/Configuration/FunctionalTests.xml'
40 | # Symlink TYPO3-Core
41 | - ln -nfs .Build/vendor/typo3/cms/typo3 typo3
42 |
43 | script:
44 | - >
45 | echo;
46 | echo "Running xmllint (Xliff)";
47 | find Resources/Private/Language/ -name '*.xlf' -type f | xargs xmllint --noout --schema Tests/Linting/Resources/Xliff.xsd
48 | - >
49 | echo;
50 | echo "Running PHP lint";
51 | find . -name \*.php ! -path "./.Build/*" ! -path "./scripts/*" ! -path "./typo3_src/*" | parallel --gnu php -d display_errors=stderr -l {} > /dev/null \;
52 | # - >
53 | # echo;
54 | # echo "Running JavaScript lint";
55 | # npm install -g jslint;
56 | # find Resources/Public/JavaScript/ -name '*.js' ! -name 'jquery*' ! -name 'tooltip*' -type f | xargs jslint
57 | - >
58 | if [[ "$COVERAGE" == "0" ]]; then
59 | echo;
60 | echo "Running unit tests";
61 | .Build/bin/phpunit --colors -c $UNIT_XML Tests/Unit/
62 | fi
63 | - >
64 | if [[ "$COVERAGE" == "1" ]]; then
65 | echo;
66 | echo "Running unit tests";
67 | .Build/bin/phpunit --coverage-clover=unittest-coverage.clover --colors -c $UNIT_XML Tests/Unit/
68 | fi
69 | - >
70 | if [[ "$FUNCTIONAL" == "1" ]]; then
71 | echo;
72 | export typo3DatabaseName="typo3";
73 | export typo3DatabaseHost="localhost";
74 | export typo3DatabaseUsername="root";
75 | export typo3DatabasePassword="";
76 | find 'Tests/Functional' -wholename '*Test.php' | parallel --gnu 'echo; echo "Running functional test suite {}"; .Build/bin/phpunit --coverage-clover={}functionaltest-coverage.clover --colors -c $FUNCTIONAL_XML {}'
77 | fi
78 | - >
79 | if [[ "$COVERAGE" == "1" ]]; then
80 | echo;
81 | echo "Uploading code coverage results";
82 | wget https://scrutinizer-ci.com/ocular.phar
83 | php ocular.phar code-coverage:upload --format=php-clover unittest-coverage.clover
84 | find 'Tests/Functional' -wholename '*Test.php' -exec php ocular.phar code-coverage:upload --format=php-clover {}functionaltest-coverage.clover \;
85 | fi
86 |
87 | jobs:
88 | allow_failures:
89 | - env: TYPO3_VERSION=^9.5 COVERAGE=0 FUNCTIONAL=1
90 | - env: TYPO3_VERSION=^10.4 COVERAGE=0 FUNCTIONAL=1
91 | - env: TYPO3_VERSION=dev-master COVERAGE=0 FUNCTIONAL=1
92 | include:
93 | - stage: test
94 | env: TYPO3_VERSION=^8.7 COVERAGE=0 FUNCTIONAL=0
95 | php: 7.0
96 | - stage: test
97 | env: TYPO3_VERSION=^8.7 COVERAGE=0 FUNCTIONAL=1
98 | php: 7.0
99 | - stage: test
100 | env: TYPO3_VERSION=^8.7 COVERAGE=0 FUNCTIONAL=0
101 | php: 7.2
102 | - stage: test
103 | env: TYPO3_VERSION=^8.7 COVERAGE=1 FUNCTIONAL=1
104 | php: 7.2
105 | - stage: test
106 | env: TYPO3_VERSION=^9.5 COVERAGE=0 FUNCTIONAL=1
107 | php: 7.2
108 | - stage: test
109 | env: TYPO3_VERSION=^10.4 COVERAGE=0 FUNCTIONAL=1
110 | php: 7.2
111 | - stage: test
112 | env: TYPO3_VERSION=dev-master COVERAGE=0 FUNCTIONAL=1
113 | php: 7.2
114 |
115 | - stage: ship to ter
116 | if: tag IS present
117 | php: 7.2
118 | install: skip
119 | before_script: skip
120 | script:
121 | - |
122 | if [ -n "$TYPO3_ORG_USERNAME" ] && [ -n "$TYPO3_ORG_PASSWORD" ]; then
123 | echo -e "Preparing upload of release ${TRAVIS_TAG} to TER\n";
124 | # Install ter client
125 | composer global require helhum/ter-client
126 | # Build extension files
127 | composer extension-release
128 | # Upload
129 | TAG_MESSAGE=`git log -1 --pretty=%B`
130 | echo "Tag-Message: ${TAG_MESSAGE}"
131 | echo "Uploading release ${TRAVIS_TAG} to TER"
132 | $HOME/.composer/vendor/bin/ter-client upload scheduler_timeline . -u "$TYPO3_ORG_USERNAME" -p "$TYPO3_ORG_PASSWORD" -m "$TAG_MESSAGE"
133 | fi;
--------------------------------------------------------------------------------
/Tests/Functional/Domain/Repository/LogRepositoryTest.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | use Nimut\TestingFramework\TestCase\FunctionalTestCase;
30 |
31 | /**
32 | * Class LogRepositoryTest
33 | *
34 | * @package AOE\SchedulerTimeline\Tests\Functional\Domain\Repository
35 | */
36 | class LogRepositoryTest extends FunctionalTestCase
37 | {
38 |
39 | /**
40 | * @var \AOE\SchedulerTimeline\Domain\Repository\LogRepository
41 | */
42 | protected $logRepository;
43 |
44 | /**
45 | * @var \TYPO3\CMS\Extbase\Object\ObjectManager
46 | */
47 | protected $objectManager;
48 |
49 | /**
50 | * @var array
51 | */
52 | protected $coreExtensionsToLoad = array('scheduler');
53 |
54 | /**
55 | * @var array
56 | */
57 | protected $testExtensionsToLoad = array('typo3conf/ext/scheduler_timeline');
58 |
59 | /**
60 | * SetUp
61 | */
62 | public function setUp()
63 | {
64 | parent::setUp();
65 | $this->importDataSet(__DIR__ . '/Fixtures/tx_schedulertimeline_domain_model_log.xml');
66 | $this->importDataSet(__DIR__ . '/Fixtures/tx_scheduler_task.xml');
67 | $this->objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
68 | $this->logRepository = $this->objectManager->get('AOE\\SchedulerTimeline\\Domain\\Repository\\LogRepository');
69 | }
70 |
71 | /**
72 | * Tears down the fixture
73 | *
74 | * @return void
75 | */
76 | public function tearDown()
77 | {
78 | parent::tearDown();
79 | }
80 |
81 | /**
82 | * @test
83 | */
84 | public function findByTimeReturnsQueryResultInterface()
85 | {
86 | // Order by starttime
87 | $expectedArray = array(5,1,2);
88 |
89 | $startTime = 1445191476; // 18.10.15 18:04
90 | $endTime = 1445191876; // 18.10.15 18:11
91 | $logs = $this->logRepository->findByTime($startTime, $endTime);
92 |
93 | /** @var \AOE\SchedulerTimeline\Domain\Model\Log $log */
94 | foreach ($logs as $log) {
95 | $actualArray[] = $log->getUid();
96 | }
97 |
98 | $this->assertSame(
99 | $expectedArray,
100 | $actualArray
101 | );
102 | }
103 |
104 | /**
105 | * @test
106 | */
107 | public function findGroupedByTaskReturnsMultidimensionArray()
108 | {
109 | $actualArray = array();
110 | $expectedArray = array(
111 | 131 => array(
112 | 'task' => 131,
113 | 'logs' => array(1)
114 | ),
115 | 132 => array(
116 | 'task' => 132,
117 | 'logs' => array(2)
118 | ),
119 | 133 => array(
120 | 'task' => 133,
121 | 'logs' => array(3)
122 | ),
123 | 134 => array(
124 | 'task' => 134,
125 | 'logs' => array(4,5)
126 | ),
127 | );
128 |
129 | $startTime = 1445191476; // 18.10.15 18:04
130 | $endTime = 1445191876; // 18.10.15 18:11
131 | $logsGroupedByTask = $this->logRepository->findGroupedByTask($startTime, $endTime);
132 |
133 | foreach ($logsGroupedByTask as $taskUid => $taskObject) {
134 | $actualArray[$taskUid]['task'] = $taskUid;
135 |
136 | /** @var \AOE\SchedulerTimeline\Domain\Model\Task $task */
137 | foreach ($taskObject as $task) {
138 | /** @var \AOE\SchedulerTimeline\Domain\Model\Log $log */
139 | foreach ($task as $log) {
140 | $actualArray[$taskUid]['logs'][] = $log->getUid();
141 | }
142 | }
143 | }
144 |
145 | $this->assertSame(
146 | sort($expectedArray),
147 | sort($actualArray)
148 | );
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Documentation/_make/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Command file for Sphinx documentation
4 |
5 | if "%SPHINXOPTS%" == "" (
6 | set SPHINXOPTS=-c . -a -E -w ./_not_versioned/warnings.txt
7 | )
8 | if "%SPHINXBUILD%" == "" (
9 | set SPHINXBUILD=/var/www/congstar-congo/devbox/htdocs/typo3temp/tx_sphinx/sphinx-doc/bin/sphinx-build
10 | )
11 | set PAPER=a4
12 | set BUILDDIR=build
13 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% ..
14 | set I18NSPHINXOPTS=%SPHINXOPTS% ..
15 | if NOT "%PAPER%" == "" (
16 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
17 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
18 | )
19 |
20 | if "%1" == "" goto help
21 |
22 | if "%1" == "help" (
23 | :help
24 | echo.Please use `make ^` where ^ is one of
25 | echo. html to make standalone HTML files
26 | echo. dirhtml to make HTML files named index.html in directories
27 | echo. singlehtml to make a single large HTML file
28 | echo. pickle to make pickle files
29 | echo. json to make JSON files
30 | echo. htmlhelp to make HTML files and a HTML help project
31 | echo. qthelp to make HTML files and a qthelp project
32 | echo. devhelp to make HTML files and a Devhelp project
33 | echo. epub to make an epub
34 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
35 | echo. text to make text files
36 | echo. man to make manual pages
37 | echo. texinfo to make Texinfo files
38 | echo. gettext to make PO message catalogs
39 | echo. changes to make an overview over all changed/added/deprecated items
40 | echo. linkcheck to check all external links for integrity
41 | echo. doctest to run all doctests embedded in the documentation if enabled
42 | goto end
43 | )
44 |
45 | if "%1" == "clean" (
46 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
47 | del /q /s %BUILDDIR%\*
48 | goto end
49 | )
50 |
51 | if "%1" == "html" (
52 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
53 | if errorlevel 1 exit /b 1
54 | echo.
55 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
56 | goto end
57 | )
58 |
59 | if "%1" == "dirhtml" (
60 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
61 | if errorlevel 1 exit /b 1
62 | echo.
63 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
64 | goto end
65 | )
66 |
67 | if "%1" == "singlehtml" (
68 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
69 | if errorlevel 1 exit /b 1
70 | echo.
71 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
72 | goto end
73 | )
74 |
75 | if "%1" == "pickle" (
76 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
77 | if errorlevel 1 exit /b 1
78 | echo.
79 | echo.Build finished; now you can process the pickle files.
80 | goto end
81 | )
82 |
83 | if "%1" == "json" (
84 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
85 | if errorlevel 1 exit /b 1
86 | echo.
87 | echo.Build finished; now you can process the JSON files.
88 | goto end
89 | )
90 |
91 | if "%1" == "htmlhelp" (
92 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
93 | if errorlevel 1 exit /b 1
94 | echo.
95 | echo.Build finished; now you can run HTML Help Workshop with the ^
96 | .hhp project file in %BUILDDIR%/htmlhelp.
97 | goto end
98 | )
99 |
100 | if "%1" == "qthelp" (
101 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
102 | if errorlevel 1 exit /b 1
103 | echo.
104 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
105 | .qhcp project file in %BUILDDIR%/qthelp, like this:
106 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Projectname.qhcp
107 | echo.To view the help file:
108 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Projectname.ghc
109 | goto end
110 | )
111 |
112 | if "%1" == "devhelp" (
113 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
114 | if errorlevel 1 exit /b 1
115 | echo.
116 | echo.Build finished.
117 | goto end
118 | )
119 |
120 | if "%1" == "epub" (
121 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
122 | if errorlevel 1 exit /b 1
123 | echo.
124 | echo.Build finished. The epub file is in %BUILDDIR%/epub.
125 | goto end
126 | )
127 |
128 | if "%1" == "latex" (
129 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
130 | if errorlevel 1 exit /b 1
131 | echo.
132 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
133 | goto end
134 | )
135 |
136 | if "%1" == "text" (
137 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
138 | if errorlevel 1 exit /b 1
139 | echo.
140 | echo.Build finished. The text files are in %BUILDDIR%/text.
141 | goto end
142 | )
143 |
144 | if "%1" == "man" (
145 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
146 | if errorlevel 1 exit /b 1
147 | echo.
148 | echo.Build finished. The manual pages are in %BUILDDIR%/man.
149 | goto end
150 | )
151 |
152 | if "%1" == "texinfo" (
153 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
154 | if errorlevel 1 exit /b 1
155 | echo.
156 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
157 | goto end
158 | )
159 |
160 | if "%1" == "gettext" (
161 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
162 | if errorlevel 1 exit /b 1
163 | echo.
164 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
165 | goto end
166 | )
167 |
168 | if "%1" == "changes" (
169 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
170 | if errorlevel 1 exit /b 1
171 | echo.
172 | echo.The overview file is in %BUILDDIR%/changes.
173 | goto end
174 | )
175 |
176 | if "%1" == "linkcheck" (
177 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
178 | if errorlevel 1 exit /b 1
179 | echo.
180 | echo.Link check complete; look for any errors in the above output ^
181 | or in %BUILDDIR%/linkcheck/output.txt.
182 | goto end
183 | )
184 |
185 | if "%1" == "doctest" (
186 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
187 | if errorlevel 1 exit /b 1
188 | echo.
189 | echo.Testing of doctests in the sources finished, look at the ^
190 | results in %BUILDDIR%/doctest/output.txt.
191 | goto end
192 | )
193 |
194 | :end
195 |
--------------------------------------------------------------------------------
/Classes/Domain/Model/Log.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | /**
30 | * Class Log
31 | *
32 | * @package AOE\SchedulerTimeline\Domain\Model
33 | */
34 | class Log extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
35 | {
36 |
37 | const STATUS_PENDING = 'pending';
38 | const STATUS_RUNNING = 'running';
39 | const STATUS_SUCCESS = 'success';
40 | const STATUS_MISSED = 'missed';
41 | const STATUS_ERROR = 'error';
42 |
43 | /**
44 | * @var \AOE\SchedulerTimeline\Domain\Model\Task
45 | */
46 | protected $task;
47 |
48 | /**
49 | * @var int
50 | */
51 | protected $starttime = 0;
52 |
53 | /**
54 | * @var int
55 | */
56 | protected $endtime = 0;
57 |
58 | /**
59 | * @var string
60 | */
61 | protected $exception = '';
62 |
63 | /**
64 | * @var string
65 | */
66 | protected $returnmessage = '';
67 |
68 | /**
69 | * @var int
70 | */
71 | protected $processid = 0;
72 |
73 | /**
74 | * @param \AOE\SchedulerTimeline\Domain\Model\Task $task
75 | */
76 | public function setTask(Task $task)
77 | {
78 | $this->task = $task;
79 | }
80 |
81 | /**
82 | * @param int $starttime
83 | */
84 | public function setStarttime(int $starttime)
85 | {
86 | $this->starttime = $starttime;
87 | }
88 |
89 | /**
90 | * @param int $endtime
91 | */
92 | public function setEndtime(int $endtime)
93 | {
94 | $this->endtime = $endtime;
95 | }
96 |
97 | /**
98 | * @param string $exception
99 | */
100 | public function setException(string $exception)
101 | {
102 | $this->exception = $exception;
103 | }
104 |
105 | /**
106 | * @param string $returnmessage
107 | */
108 | public function setReturnmessage(string $returnmessage)
109 | {
110 | $this->returnmessage = $returnmessage;
111 | }
112 |
113 | /**
114 | * @param int $processid
115 | */
116 | public function setProcessid(int $processid)
117 | {
118 | $this->processid = $processid;
119 | }
120 |
121 | /**
122 | * Get task
123 | *
124 | * @return \AOE\SchedulerTimeline\Domain\Model\Task
125 | */
126 | public function getTask()
127 | {
128 | return $this->task;
129 | }
130 |
131 | /**
132 | * @return the $starttime
133 | */
134 | public function getStarttime()
135 | {
136 | return $this->starttime;
137 | }
138 |
139 | /**
140 | * @return the $endtime
141 | */
142 | public function getEndtime()
143 | {
144 | return $this->endtime;
145 | }
146 |
147 | /**
148 | * @return the $exception
149 | */
150 | public function getException()
151 | {
152 | return unserialize($this->exception);
153 | }
154 |
155 | /**
156 | * @return the $returnmessage
157 | */
158 | public function getReturnmessage()
159 | {
160 | return $this->returnmessage;
161 | }
162 |
163 | /**
164 | * Get the process id
165 | *
166 | * @return int
167 | */
168 | public function getProcessid()
169 | {
170 | return $this->processid;
171 | }
172 |
173 | /**
174 | * @return int duration (in sec)
175 | */
176 | public function getDuration()
177 | {
178 | $endtime = $this->getEndtime() ? $this->getEndtime() : $this->getCurrentTime();
179 | return $endtime - $this->getStarttime();
180 | }
181 |
182 | /**
183 | * Get formatted timespan
184 | *
185 | * @return string
186 | */
187 | public function getTimespan()
188 | {
189 | $timespan = $this->getFormattedDateFromTimestamp($this->getStarttime());
190 | if ($this->isRunning()) {
191 | $timespan .= ' - (still running)';
192 | } else {
193 | $timespan .= ' - ' . $this->getFormattedDateFromTimestamp($this->getEndtime());
194 | }
195 | return $timespan;
196 | }
197 |
198 | /**
199 | * Is this task running?
200 | *
201 | * @return bool
202 | */
203 | public function isRunning()
204 | {
205 | return (!$this->getEndtime());
206 | }
207 |
208 | /**
209 | * Get status
210 | *
211 | * @return string see class constants STATUS_*
212 | */
213 | public function getStatus()
214 | {
215 | if ($this->getException()) {
216 | return self::STATUS_ERROR;
217 | } elseif ($this->isRunning()) {
218 | return self::STATUS_RUNNING;
219 | } else {
220 | return self::STATUS_SUCCESS;
221 | }
222 | }
223 |
224 | /**
225 | * Kill this process
226 | *
227 | * @return void
228 | */
229 | public function kill()
230 | {
231 | if ($this->isRunning()) {
232 | shell_exec('kill '. intval($this->processid));
233 | }
234 | }
235 |
236 | /**
237 | * Returns the current time
238 | *
239 | * Mockable getter for time()
240 | *
241 | * @return int
242 | */
243 | protected function getCurrentTime()
244 | {
245 | return time();
246 | }
247 |
248 | /**
249 | * @param $timestamp
250 | *
251 | * @return bool|string
252 | */
253 | protected function getFormattedDateFromTimestamp($timestamp)
254 | {
255 | return date('H:i', $timestamp);
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/Classes/Domain/Model/Task.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | /**
30 | * Class Task
31 | *
32 | * @package AOE\SchedulerTimeline\Domain\Model
33 | */
34 | class Task extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
35 | {
36 | /**
37 | * @var string
38 | */
39 | protected $serializedTaskObject;
40 |
41 | /**
42 | * @var string
43 | */
44 | protected $logFileContent;
45 |
46 | /**
47 | * @return string
48 | */
49 | public function getSerializedTaskObject(): string
50 | {
51 | return $this->serializedTaskObject;
52 | }
53 |
54 | /**
55 | * @param string $serializedTaskObject
56 | */
57 | public function setSerializedTaskObject(string $serializedTaskObject)
58 | {
59 | $this->serializedTaskObject = $serializedTaskObject;
60 | }
61 |
62 | /**
63 | * Get classname
64 | *
65 | * @return string
66 | */
67 | public function getClassname()
68 | {
69 | return get_class($this->getTaskObject());
70 | }
71 |
72 | /**
73 | * Get task object
74 | *
75 | * @return \TYPO3\CMS\Scheduler\Task\AbstractTask
76 | * @throws \Exception
77 | */
78 | public function getTaskObject()
79 | {
80 | $taskObject = unserialize($this->serializedTaskObject);
81 | if (!is_object($taskObject)) {
82 | throw new \Exception('Inconsitent data: There is no serialized task object in the Task', 1450187123);
83 | }
84 | return $taskObject;
85 | }
86 |
87 | /**
88 | * Get log file path
89 | * Expects $taskObject->getLogFilePath() to return the path
90 | *
91 | * @return string|bool
92 | */
93 | public function getLogFilePath()
94 | {
95 | $taskObject = $this->getTaskObject();
96 | if ($taskObject && is_callable(array($taskObject, 'getLogFilePath'))) {
97 | return $taskObject->getLogFilePath();
98 | }
99 | return false;
100 | }
101 |
102 | /**
103 | * Get log file content
104 | * (If a log file is available. See $this->getLogFilePath())
105 | *
106 | * @return string
107 | */
108 | public function getLogFileContent()
109 | {
110 | if (is_null($this->logFileContent)) {
111 | $this->logFileContent = '';
112 | $logFilePath = $this->getLogFilePath();
113 | if ($logFilePath && is_file($logFilePath)) {
114 | $this->logFileContent = shell_exec('tail -n 20 ' . escapeshellarg($logFilePath));
115 | }
116 | }
117 | return $this->logFileContent;
118 | }
119 |
120 | /**
121 | * Get info for this task
122 | *
123 | * @return array
124 | */
125 | public function getInfo()
126 | {
127 | $registeredClasses = $this->getRegisteredClasses();
128 | return $registeredClasses[$this->getClassname()];
129 | }
130 |
131 | /**
132 | * Get extension
133 | *
134 | * @return string
135 | */
136 | public function getExtension()
137 | {
138 | $info = $this->getInfo();
139 | return $info['extension'];
140 | }
141 |
142 | /**
143 | * Get filename
144 | *
145 | * @return string
146 | */
147 | public function getFilename()
148 | {
149 | $info = $this->getInfo();
150 | return $info['filename'];
151 | }
152 |
153 | /**
154 | * Get title
155 | *
156 | * @return string
157 | */
158 | public function getTitle()
159 | {
160 | $info = $this->getInfo();
161 | return $info['title'];
162 | }
163 |
164 | /**
165 | * Get provider
166 | *
167 | * @return string
168 | */
169 | public function getProvider()
170 | {
171 | $info = $this->getInfo();
172 | return $info['provider'];
173 | }
174 |
175 | /**
176 | * This method a list of all classes that have been registered with the Scheduler
177 | * For each item the following information is provided, as an associative array:
178 | *
179 | * ['extension'] => Key of the extension which provides the class
180 | * ['filename'] => Path to the file containing the class
181 | * ['title'] => String (possibly localized) containing a human-readable name for the class
182 | * ['provider'] => Name of class that implements the interface for additional fields, if necessary
183 | *
184 | * The name of the class itself is used as the key of the list array
185 | *
186 | * @return array List of registered classes
187 | */
188 | protected function getRegisteredClasses()
189 | {
190 | $list = array();
191 | if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'])) {
192 | foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] as $class => $registrationInformation) {
193 | $title = isset($registrationInformation['title']) ? $GLOBALS['LANG']->sL($registrationInformation['title']) : '';
194 | $description = isset($registrationInformation['description']) ? $GLOBALS['LANG']->sL($registrationInformation['description']) : '';
195 |
196 | $list[$class] = array(
197 | 'extension' => $registrationInformation['extension'],
198 | 'title' => $title,
199 | 'description' => $description,
200 | 'provider' => isset($registrationInformation['additionalFields']) ? $registrationInformation['additionalFields'] : ''
201 | );
202 | }
203 | }
204 |
205 | return $list;
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/Documentation/_make/Makefile:
--------------------------------------------------------------------------------
1 | # You can set these variables from the command line.
2 | SPHINXOPTS = -c . -a -E -w ./_not_versioned/warnings.txt
3 | SPHINXBUILD = sphinx-build
4 | PAPER = a4
5 | BUILDDIR = build
6 |
7 | # User-friendly check for sphinx-build
8 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
9 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
10 | endif
11 |
12 | # Internal variables.
13 | PAPEROPT_a4 = -D latex_paper_size=a4
14 | PAPEROPT_letter = -D latex_paper_size=letter
15 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ..
16 | # the i18n builder cannot share the environment and doctrees with the others
17 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ..
18 |
19 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
20 |
21 | help:
22 | @echo "Please use \`make ' where is one of"
23 | @echo " html to make standalone HTML files"
24 | @echo " dirhtml to make HTML files named index.html in directories"
25 | @echo " singlehtml to make a single large HTML file"
26 | @echo " pickle to make pickle files"
27 | @echo " json to make JSON files"
28 | @echo " htmlhelp to make HTML files and a HTML help project"
29 | @echo " qthelp to make HTML files and a qthelp project"
30 | @echo " devhelp to make HTML files and a Devhelp project"
31 | @echo " epub to make an epub"
32 | @echo " pdf to make PDF using rst2pdf"
33 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
34 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
35 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
36 | @echo " text to make text files"
37 | @echo " man to make manual pages"
38 | @echo " texinfo to make Texinfo files"
39 | @echo " info to make Texinfo files and run them through makeinfo"
40 | @echo " gettext to make PO message catalogs"
41 | @echo " changes to make an overview of all changed/added/deprecated items"
42 | @echo " xml to make Docutils-native XML files"
43 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
44 | @echo " linkcheck to check all external links for integrity"
45 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
46 |
47 | clean:
48 | rm -rf $(BUILDDIR)/*
49 |
50 | html:
51 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
52 | @echo
53 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
54 |
55 | dirhtml:
56 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
57 | @echo
58 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
59 |
60 | singlehtml:
61 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
62 | @echo
63 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
64 |
65 | pickle:
66 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
67 | @echo
68 | @echo "Build finished; now you can process the pickle files."
69 |
70 | json:
71 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
72 | @echo
73 | @echo "Build finished; now you can process the JSON files."
74 |
75 | htmlhelp:
76 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
77 | @echo
78 | @echo "Build finished; now you can run HTML Help Workshop with the" \
79 | ".hhp project file in $(BUILDDIR)/htmlhelp."
80 |
81 | qthelp:
82 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
83 | @echo
84 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
85 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
86 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Brute Force Protection.qhcp"
87 | @echo "To view the help file:"
88 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Brute Force Protection.qhc"
89 |
90 | devhelp:
91 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
92 | @echo
93 | @echo "Build finished."
94 | @echo "To view the help file:"
95 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Brute Force Protection"
96 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Brute Force Protection"
97 | @echo "# devhelp"
98 |
99 | epub:
100 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
101 | @echo
102 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
103 |
104 | pdf:
105 | $(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) $(BUILDDIR)/pdf
106 | @echo
107 | @echo "Build finished. The PDF is in $(BUILDDIR)/pdf."
108 |
109 | latex:
110 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
111 | @echo
112 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
113 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
114 | "(use \`make latexpdf' here to do that automatically)."
115 |
116 | latexpdf:
117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
118 | @echo "Running LaTeX files through pdflatex..."
119 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
120 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
121 |
122 | latexpdfja:
123 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
124 | @echo "Running LaTeX files through platex and dvipdfmx..."
125 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
126 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
127 |
128 | text:
129 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
130 | @echo
131 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
132 |
133 | man:
134 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
135 | @echo
136 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
137 |
138 | texinfo:
139 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
140 | @echo
141 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
142 | @echo "Run \`make' in that directory to run these through makeinfo" \
143 | "(use \`make info' here to do that automatically)."
144 |
145 | info:
146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
147 | @echo "Running Texinfo files through makeinfo..."
148 | make -C $(BUILDDIR)/texinfo info
149 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
150 |
151 | gettext:
152 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
153 | @echo
154 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
155 |
156 | changes:
157 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
158 | @echo
159 | @echo "The overview file is in $(BUILDDIR)/changes."
160 |
161 | linkcheck:
162 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
163 | @echo
164 | @echo "Link check complete; look for any errors in the above output " \
165 | "or in $(BUILDDIR)/linkcheck/output.txt."
166 |
167 | doctest:
168 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
169 | @echo "Testing of doctests in the sources finished, look at the " \
170 | "results in $(BUILDDIR)/doctest/output.txt."
171 |
172 | xml:
173 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
174 | @echo
175 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
176 |
177 | pseudoxml:
178 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
179 | @echo
180 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
181 |
--------------------------------------------------------------------------------
/Classes/Controller/TimelineController.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | use AOE\SchedulerTimeline\Converter\FormValueTimestampConverter;
30 | use TYPO3\CMS\Core\Utility\GeneralUtility;
31 | use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
32 |
33 | /**
34 | * Class TimelineController
35 | *
36 | * @package AOE\SchedulerTimeline\Controller
37 | */
38 | class TimelineController extends ActionController
39 | {
40 |
41 | /**
42 | * @var string Key of the extension this controller belongs to
43 | */
44 | protected $extensionName = 'SchedulerTimeline';
45 |
46 | /**
47 | * @var \TYPO3\CMS\Core\Page\PageRenderer
48 | */
49 | protected $pageRenderer;
50 |
51 | /**
52 | * @var \AOE\SchedulerTimeline\Domain\Repository\LogRepository
53 | */
54 | protected $logRepository;
55 |
56 | /**
57 | * @var \AOE\SchedulerTimeline\Domain\Repository\TaskRepository
58 | */
59 | protected $taskRepository;
60 |
61 | /**
62 | * @var \TYPO3\CMS\Backend\Template\DocumentTemplate
63 | */
64 | protected $template;
65 |
66 | /**
67 | * Initializes the controller before invoking an action method.
68 | *
69 | * @return void
70 | */
71 | protected function initializeAction()
72 | {
73 | $this->pageRenderer->addInlineLanguageLabelFile('EXT:scheduler_timeline/Resources/Private/Language/locallang.xml');
74 | }
75 |
76 | /**
77 | * @param \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer
78 | * @return void
79 | */
80 | public function injectPageRenderer(\TYPO3\CMS\Core\Page\PageRenderer $pageRenderer)
81 | {
82 | $this->pageRenderer = $pageRenderer;
83 | }
84 |
85 | /**
86 | * @param \AOE\SchedulerTimeline\Domain\Repository\LogRepository $logRepository
87 | * @return void
88 | */
89 | public function injectLogRepository(\AOE\SchedulerTimeline\Domain\Repository\LogRepository $logRepository)
90 | {
91 | $this->logRepository = $logRepository;
92 | }
93 |
94 | /**
95 | * @param \AOE\SchedulerTimeline\Domain\Repository\TaskRepository $taskRepository
96 | * @return void
97 | */
98 | public function injectTaskRepository(\AOE\SchedulerTimeline\Domain\Repository\TaskRepository $taskRepository)
99 | {
100 | $this->taskRepository = $taskRepository;
101 | }
102 |
103 | /**
104 | * Simple action to list some stuff
105 | */
106 | public function timelineAction()
107 | {
108 | $zoom = 15; // amount of seconds per pixel
109 |
110 | $startTime = strtoTime('-1 hour');
111 | $endTime = time();
112 | $postVars = GeneralUtility::_POST('tx_schedulertimeline_tools_schedulertimelineschedulertimeline');
113 | $timespan = $postVars['timespan'] ?? null;
114 | if ($timespan !== null) {
115 | $startTime = $this->getStartTime($postVars['timespan']);
116 | }
117 | $groupedLogs = $this->logRepository->findGroupedByTask($startTime, $endTime);
118 |
119 | // To have logs that was added this second included,
120 | $startTimeFloor = $this->hourFloor($startTime);
121 | $endTimeCeil = $this->hourCeil($endTime);
122 |
123 | $this->view->assign('groupedLogs', $groupedLogs);
124 | $this->view->assign('starttime', $startTimeFloor);
125 | $this->view->assign('endtime', $endTimeCeil);
126 | $this->view->assign('zoom', $zoom);
127 | $this->view->assign('now', ($GLOBALS['EXEC_TIME'] - $startTimeFloor) / $zoom);
128 | $this->view->assign('timelinePanelWidth', ($endTimeCeil - $startTimeFloor) / $zoom);
129 | $this->view->assign('actionMenuValues', $this->getActionMenuValues());
130 | $this->view->assign('actionMenuSelected', $timespan);
131 | }
132 |
133 | /**
134 | * @param string $timespan
135 | * @return int
136 | */
137 | private function getStartTime(string $timespan)
138 | {
139 | $strToTimeValue = FormValueTimestampConverter::convertValueToStrToTimeValue($timespan);
140 | return strtotime('-' . $strToTimeValue);
141 | }
142 |
143 | /**
144 | * @return array
145 | */
146 | private function getActionMenuValues()
147 | {
148 | return [
149 | '1h' => '1 Hour',
150 | '3h' => '3 Hours',
151 | '1d' => '1 Day',
152 | '3d' => '3 Days',
153 | '1w' => '1 Week',
154 | '2w' => '2 Weeks',
155 | '3w' => '3 Weeks',
156 | '4w' => '4 Weeks',
157 | ];
158 | }
159 |
160 | /**
161 | * Return the last full houd
162 | *
163 | * @param int $timestamp
164 | * @return int
165 | */
166 | protected function hourFloor($timestamp)
167 | {
168 | return mktime(date('H', $timestamp), 0, 0, date('n', $timestamp), date('j', $timestamp), date('Y', $timestamp));
169 | }
170 |
171 | /**
172 | * Returns the next full hour
173 | *
174 | * @param int $timestamp
175 | * @return int
176 | */
177 | protected function hourCeil($timestamp)
178 | {
179 | return mktime(date('H', $timestamp)+1, 0, 0, date('n', $timestamp), date('j', $timestamp), date('Y', $timestamp));
180 | }
181 |
182 |
183 | /**
184 | * Processes a general request. The result can be returned by altering the given response.
185 | *
186 | * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
187 | * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this handler
188 | * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException if the controller doesn't support the current request type
189 | * @return void
190 | */
191 | public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
192 | {
193 | $this->template = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Template\\DocumentTemplate');
194 |
195 | $GLOBALS['SOBE'] = new \stdClass();
196 | $GLOBALS['SOBE']->doc = $this->template;
197 |
198 | parent::processRequest($request, $response);
199 |
200 | $pageHeader = $this->template->startpage(
201 | $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xml:module.title')
202 | );
203 | $pageEnd = $this->template->endPage();
204 |
205 | $response->setContent($pageHeader . $response->getContent() . $pageEnd);
206 | }
207 |
208 |
209 | /**
210 | * Wrapper for t3lib_PageRenderer->addJsFile. Excludes $jsFile from concatenation on TYPO3 4.6+.
211 | *
212 | * @param string $jsFile
213 | * @return void
214 | */
215 | protected function addJsFileToPageRenderer($jsFile)
216 | {
217 | if (version_compare(TYPO3_version, '4.6', '>=')) {
218 | $this->pageRenderer->addJsFile($jsFile, 'text/javascript', true, false, '', true);
219 | } else {
220 | $this->pageRenderer->addJsFile($jsFile);
221 | }
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/Resources/Public/JavaScript/tooltip.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * jQuery Tools @VERSION Tooltip - UI essentials
4 | *
5 | * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
6 | *
7 | * http://flowplayer.org/tools/tooltip/
8 | *
9 | * Since: November 2008
10 | * Date: @DATE
11 | */
12 | (function($) {
13 | // static constructs
14 | $.tools = $.tools || {version: '@VERSION'};
15 |
16 | $.tools.tooltip = {
17 |
18 | conf: {
19 |
20 | // default effect variables
21 | effect: 'toggle',
22 | fadeOutSpeed: "fast",
23 | predelay: 0,
24 | delay: 30,
25 | opacity: 1,
26 | tip: 0,
27 |
28 | // 'top', 'bottom', 'right', 'left', 'center'
29 | position: ['top', 'center'],
30 | offset: [0, 0],
31 | relative: false,
32 | offsetParent: null,
33 | cancelDefault: true,
34 |
35 | // type to event mapping
36 | events: {
37 | def: "mouseenter,mouseleave",
38 | input: "focus,blur",
39 | widget: "focus mouseenter,blur mouseleave",
40 | tooltip: "mouseenter,mouseleave"
41 | },
42 |
43 | // 1.2
44 | layout: '',
45 | tipClass: 'tooltip'
46 | },
47 |
48 | addEffect: function(name, loadFn, hideFn) {
49 | effects[name] = [loadFn, hideFn];
50 | }
51 | };
52 |
53 |
54 | var effects = {
55 | toggle: [
56 | function(done) {
57 | var conf = this.getConf(), tip = this.getTip(), o = conf.opacity;
58 | if (o < 1) { tip.css({opacity: o}); }
59 | tip.show();
60 | done.call();
61 | },
62 |
63 | function(done) {
64 | this.getTip().hide();
65 | done.call();
66 | }
67 | ],
68 |
69 | fade: [
70 | function(done) {
71 | var conf = this.getConf();
72 | this.getTip().fadeTo(conf.fadeInSpeed, conf.opacity, done);
73 | },
74 | function(done) {
75 | this.getTip().fadeOut(this.getConf().fadeOutSpeed, done);
76 | }
77 | ]
78 | };
79 |
80 |
81 | /* calculate tip position relative to the trigger */
82 | function getPosition(trigger, tip, conf) {
83 |
84 |
85 | // get origin top/left position
86 | var top = conf.relative ? trigger.position().top : trigger.offset().top,
87 | left = conf.relative ? trigger.position().left : trigger.offset().left,
88 | pos = conf.position[0];
89 |
90 | top -= tip.outerHeight() - conf.offset[0];
91 | left += trigger.outerWidth() + conf.offset[1];
92 |
93 | // iPad position fix
94 | if (/iPad/i.test(navigator.userAgent)) {
95 | top -= $(window).scrollTop();
96 | }
97 |
98 | // adjust Y
99 | var height = tip.outerHeight() + trigger.outerHeight();
100 | if (pos == 'center') { top += height / 2; }
101 | if (pos == 'bottom') { top += height; }
102 |
103 |
104 | // adjust X
105 | pos = conf.position[1];
106 | var width = tip.outerWidth() + trigger.outerWidth();
107 | if (pos == 'center') { left -= width / 2; }
108 | if (pos == 'left') { left -= width; }
109 |
110 | return {top: top, left: left};
111 | }
112 |
113 |
114 |
115 | function Tooltip(trigger, conf) {
116 |
117 | var self = this,
118 | fire = trigger.add(self),
119 | tip,
120 | timer = 0,
121 | pretimer = 0,
122 | title = trigger.attr("title"),
123 | tipAttr = trigger.attr("data-tooltip"),
124 | effect = effects[conf.effect],
125 | shown,
126 |
127 | // get show/hide configuration
128 | isInput = trigger.is(":input"),
129 | isWidget = isInput && trigger.is(":checkbox, :radio, select, :button, :submit"),
130 | type = trigger.attr("type"),
131 | evt = conf.events[type] || conf.events[isInput ? (isWidget ? 'widget' : 'input') : 'def'];
132 |
133 |
134 | // check that configuration is sane
135 | if (!effect) { throw "Nonexistent effect \"" + conf.effect + "\""; }
136 |
137 | evt = evt.split(/,\s*/);
138 | if (evt.length != 2) { throw "Tooltip: bad events configuration for " + type; }
139 |
140 |
141 | // trigger --> show
142 | trigger.bind(evt[0], function(e) {
143 |
144 | clearTimeout(timer);
145 | if (conf.predelay) {
146 | pretimer = setTimeout(function() { self.show(e); }, conf.predelay);
147 |
148 | } else {
149 | self.show(e);
150 | }
151 |
152 | // trigger --> hide
153 | }).bind(evt[1], function(e) {
154 | clearTimeout(pretimer);
155 | if (conf.delay) {
156 | timer = setTimeout(function() { self.hide(e); }, conf.delay);
157 |
158 | } else {
159 | self.hide(e);
160 | }
161 |
162 | });
163 |
164 |
165 | // remove default title
166 | if (title && conf.cancelDefault) {
167 | trigger.removeAttr("title");
168 | trigger.data("title", title);
169 | }
170 |
171 | $.extend(self, {
172 |
173 | show: function(e) {
174 |
175 | // tip not initialized yet
176 | if (!tip) {
177 |
178 | // data-tooltip
179 | if (tipAttr) {
180 | tip = $(tipAttr);
181 |
182 | // single tip element for all
183 | } else if (conf.tip) {
184 | tip = $(conf.tip).eq(0);
185 |
186 | // autogenerated tooltip
187 | } else if (title) {
188 | tip = $(conf.layout).addClass(conf.tipClass).appendTo(document.body)
189 | .hide().append(title);
190 |
191 | // manual tooltip
192 | } else {
193 | tip = trigger.next();
194 | if (!tip.length) { tip = trigger.parent().next(); }
195 |
196 | }
197 |
198 | if (!tip.length) { throw "Cannot find tooltip for " + trigger; }
199 |
200 | if (conf.offsetParent) {
201 | tip.appendTo($(conf.offsetParent));
202 | }
203 | }
204 |
205 | if (self.isShown()) { return self; }
206 |
207 | // stop previous animation
208 | tip.stop(true, true);
209 |
210 | // get position
211 | var pos = getPosition(trigger, tip, conf);
212 |
213 | // restore title for single tooltip element
214 | if (conf.tip) {
215 | tip.html(trigger.data("title"));
216 | }
217 |
218 | // onBeforeShow
219 | e = e || $.Event();
220 | e.type = "onBeforeShow";
221 | fire.trigger(e, [pos]);
222 | if (e.isDefaultPrevented()) { return self; }
223 |
224 |
225 | // onBeforeShow may have altered the configuration
226 | pos = getPosition(trigger, tip, conf);
227 |
228 | // set position
229 | tip.css({position:'absolute', top: pos.top, left: pos.left});
230 |
231 | shown = true;
232 |
233 | // invoke effect
234 | effect[0].call(self, function() {
235 | e.type = "onShow";
236 | shown = 'full';
237 | fire.trigger(e);
238 | });
239 |
240 |
241 | // tooltip events
242 | var event = conf.events.tooltip.split(/,\s*/);
243 |
244 | if (!tip.data("__set")) {
245 |
246 | tip.bind(event[0], function() {
247 | clearTimeout(timer);
248 | clearTimeout(pretimer);
249 | });
250 |
251 | if (event[1] && !trigger.is("input:not(:checkbox, :radio), textarea")) {
252 | tip.bind(event[1], function(e) {
253 |
254 | // being moved to the trigger element
255 | if (e.relatedTarget != trigger[0]) {
256 | trigger.trigger(evt[1].split(" ")[0]);
257 | }
258 | });
259 | }
260 |
261 | tip.data("__set", true);
262 | }
263 |
264 | return self;
265 | },
266 |
267 | hide: function(e) {
268 |
269 | if (!tip || !self.isShown()) { return self; }
270 |
271 | // onBeforeHide
272 | e = e || $.Event();
273 | e.type = "onBeforeHide";
274 | fire.trigger(e);
275 | if (e.isDefaultPrevented()) { return; }
276 |
277 | shown = false;
278 |
279 | effects[conf.effect][1].call(self, function() {
280 | e.type = "onHide";
281 | fire.trigger(e);
282 | });
283 |
284 | return self;
285 | },
286 |
287 | isShown: function(fully) {
288 | return fully ? shown == 'full' : shown;
289 | },
290 |
291 | getConf: function() {
292 | return conf;
293 | },
294 |
295 | getTip: function() {
296 | return tip;
297 | },
298 |
299 | getTrigger: function() {
300 | return trigger;
301 | }
302 |
303 | });
304 |
305 | // callbacks
306 | $.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","), function(i, name) {
307 |
308 | // configuration
309 | if ($.isFunction(conf[name])) {
310 | $(self).bind(name, conf[name]);
311 | }
312 |
313 | // API
314 | self[name] = function(fn) {
315 | if (fn) { $(self).bind(name, fn); }
316 | return self;
317 | };
318 | });
319 |
320 | }
321 |
322 |
323 | // jQuery plugin implementation
324 | $.fn.tooltip = function(conf) {
325 |
326 | // return existing instance
327 | var api = this.data("tooltip");
328 | if (api) { return api; }
329 |
330 | conf = $.extend(true, {}, $.tools.tooltip.conf, conf);
331 |
332 | // position can also be given as string
333 | if (typeof conf.position == 'string') {
334 | conf.position = conf.position.split(/,?\s/);
335 | }
336 |
337 | // install tooltip for each entry in jQuery object
338 | this.each(function() {
339 | api = new Tooltip($(this), conf);
340 | $(this).data("tooltip", api);
341 | });
342 |
343 | return conf.api ? api: this;
344 | };
345 |
346 | }) (jQuery);
347 |
348 |
349 |
350 |
--------------------------------------------------------------------------------
/Classes/XClass/Scheduler.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | use TYPO3\CMS\Core\Utility\GeneralUtility;
30 |
31 | /**
32 | * Class Scheduler
33 | *
34 | * @package AOE\SchedulerTimeline\XClass
35 | */
36 | class Scheduler extends \TYPO3\CMS\Scheduler\Scheduler
37 | {
38 |
39 | /**
40 | * Wraps the executeTask method
41 | *
42 | * @param \TYPO3\CMS\Scheduler\Task\AbstractTask $task The task to execute
43 | * @return boolean Whether the task was saved successfully to the database or not
44 | * @throws \Exception
45 | */
46 | public function executeTask(\TYPO3\CMS\Scheduler\Task\AbstractTask $task)
47 | {
48 | $taskUid = $task->getTaskUid();
49 |
50 | // log start
51 | $logUid = $this->logStart($taskUid);
52 |
53 | $failure = null;
54 | try {
55 | $result = parent::executeTask($task);
56 | } catch (\Exception $e) {
57 | $failure = $e;
58 | }
59 |
60 | if ($result || $failure) {
61 | $returnMessage = '';
62 | if ($task instanceof \AOE\SchedulerTimeline\Interfaces\ReturnMessage || is_callable(array($task, 'getReturnMessage'))) {
63 | $returnMessage = $task->getReturnMessage();
64 | }
65 |
66 | // log end
67 | $this->logEnd($logUid, $failure, $returnMessage);
68 | } else {
69 | // task was not executed, because another task was running
70 | // and multiple execution is not allowed for this task
71 | $this->removeLog($logUid);
72 | }
73 |
74 | if ($failure instanceof \Exception) {
75 | throw $failure;
76 | }
77 |
78 | return $result;
79 | }
80 |
81 | /**
82 | * Extend the method to cleanup up the log table aswell
83 | *
84 | * @see tx_scheduler::cleanExecutionArrays()
85 | */
86 | protected function cleanExecutionArrays()
87 | {
88 | parent::cleanExecutionArrays();
89 | $this->cleanupLog();
90 | }
91 |
92 | /**
93 | * Cleanup log
94 | *
95 | * @return void
96 | * @throws \Exception
97 | */
98 | protected function cleanupLog()
99 | {
100 | $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['scheduler_timeline']);
101 |
102 | // clean old log entries
103 | $dbObj = $GLOBALS['TYPO3_DB']; /* @var $dbObj \TYPO3\CMS\Core\Database\DatabaseConnection */
104 | $res = $dbObj->exec_DELETEquery('tx_schedulertimeline_domain_model_log', 'endtime > 0 AND endtime <'.(time()- $extConf['cleanLogEntriesOlderThan'] * 60));
105 | if ($res === false) {
106 | GeneralUtility::sysLog('Error while cleaning log', 'scheduler_timeline', 0);
107 | }
108 |
109 | // clean tasks, that exceeded the maxLifetime
110 | $maxDuration = $this->extConf['maxLifetime'] * 60;
111 | $dbObj = $GLOBALS['TYPO3_DB']; /* @var $dbObj \TYPO3\CMS\Core\Database\DatabaseConnection */
112 | $res = $dbObj->exec_UPDATEquery(
113 | 'tx_schedulertimeline_domain_model_log',
114 | 'endtime = 0 AND starttime < ' . (time() - $maxDuration),
115 | array(
116 | 'endtime' => time(),
117 | 'exception' => serialize(array('message' => 'Task was cleaned up, because it exceeded maxLifetime.'))
118 | )
119 | );
120 | if ($res === false) {
121 | GeneralUtility::sysLog('Error while cleaning tasks', 'scheduler_timeline', 0);
122 | }
123 |
124 | // check if process are still alive that have been started more than x minutes ago
125 | $checkProcessesAfter = intval($extConf['checkProcessesAfter']) * 60;
126 | if ($checkProcessesAfter) {
127 | $res = $dbObj->exec_SELECTquery('uid, processid, task', 'tx_schedulertimeline_domain_model_log', 'endtime = 0 AND starttime < ' . (time() - $checkProcessesAfter));
128 | if (is_resource($res)) {
129 | while (($row = $dbObj->sql_fetch_assoc($res)) !== false) {
130 | $processId = $row['processid'];
131 | if (!$this->checkProcess($processId)) {
132 |
133 | // update log
134 | $res2 = $dbObj->exec_UPDATEquery(
135 | 'tx_schedulertimeline_domain_model_log',
136 | 'uid = '.intval($row['uid']),
137 | array(
138 | 'endtime' => time(),
139 | 'exception' => serialize(array('message' => 'Task was cleaned up, because it seems to be dead.'))
140 | )
141 | );
142 | if ($res2 === false) {
143 | throw new \Exception('Error while cleaning tasks');
144 | }
145 |
146 | $exception = new \TYPO3\CMS\Scheduler\FailedExecutionException('Task was cleaned up, because it seems to be dead.');
147 |
148 | // update scheduler task
149 | $res3 = $dbObj->exec_UPDATEquery(
150 | 'tx_scheduler_task',
151 | 'uid = '.intval($row['task']),
152 | array(
153 | 'serialized_executions' => '',
154 | 'lastexecution_failure' => serialize($exception)
155 | )
156 | );
157 |
158 | if ($res3 === false) {
159 | GeneralUtility::sysLog('Error while cleaning tasks', 'scheduler_timeline', 0);
160 | }
161 | }
162 | }
163 | }
164 | }
165 | }
166 |
167 | /**
168 | * Log the start of a task
169 | *
170 | * @param int $taskUid
171 | * @throws \Exception
172 | * @return int
173 | */
174 | protected function logStart($taskUid)
175 | {
176 | $now = time();
177 | $dbObj = $GLOBALS['TYPO3_DB']; /* @var $dbObj \TYPO3\CMS\Core\Database\DatabaseConnection */
178 | $res = $dbObj->exec_INSERTquery('tx_schedulertimeline_domain_model_log', array(
179 | 'pid' => '0',
180 | 'tstamp' => $now,
181 | 'starttime' => $now,
182 | 'task' => $taskUid,
183 | 'processid' => getmypid()
184 | ));
185 | if ($res === false) {
186 | GeneralUtility::sysLog('Error while inserting log entry', 'scheduler_timeline', 0);
187 | }
188 | return $dbObj->sql_insert_id();
189 | }
190 |
191 | /**
192 | * Remove a log entry
193 | *
194 | * @param int $logUid
195 | * @throws \Exception
196 | * @return void
197 | */
198 | protected function removeLog($logUid)
199 | {
200 | $dbObj = $GLOBALS['TYPO3_DB']; /* @var $dbObj \TYPO3\CMS\Core\Database\DatabaseConnection */
201 | $res = $dbObj->exec_DELETEquery('tx_schedulertimeline_domain_model_log', 'uid='.intval($logUid));
202 | if ($res === false) {
203 | GeneralUtility::sysLog('Error while deleting log entry', 'scheduler_timeline', 0);
204 | }
205 | }
206 |
207 | /**
208 | * Log the end of a task
209 | *
210 | * @param int $logUid
211 | * @param \Exception $failure
212 | * @param string $returnMessage
213 | * @throws \Exception
214 | */
215 | protected function logEnd($logUid, $failure, $returnMessage)
216 | {
217 | $exception = '';
218 | if ($failure instanceof \Exception) { /* @var $failure \Exception */
219 | $exception = serialize(array(
220 | 'message' => $failure->getMessage(),
221 | 'stacktrace' => $failure->getTraceAsString(),
222 | 'endtime' => time(),
223 | 'class' => get_class($failure)
224 | ));
225 | }
226 |
227 | $dbObj = $GLOBALS['TYPO3_DB']; /* @var $dbObj \TYPO3\CMS\Core\Database\DatabaseConnection */
228 | $res = $dbObj->exec_UPDATEquery('tx_schedulertimeline_domain_model_log', 'uid='.intval($logUid), array(
229 | 'endtime' => time(),
230 | 'exception' => $exception,
231 | 'returnmessage' => $returnMessage
232 | ));
233 | if ($res === false) {
234 | GeneralUtility::sysLog('Error while updating log entry', 'scheduler_timeline', 0);
235 | }
236 | }
237 |
238 | /**
239 | * Check process
240 | *
241 | * @param int $pid
242 | * @return bool
243 | */
244 | protected function checkProcess($pid)
245 | {
246 | // form the filename to search for
247 | $file = '/proc/' . (int) $pid . '/cmdline';
248 | $fp = false;
249 | if (file_exists($file)) {
250 | $fp = @fopen($file, 'rb');
251 | }
252 |
253 | if (!$fp) { // if file does not exist or cannot be opened, return false
254 | return false;
255 | }
256 | $buf = fgets($fp);
257 | fclose($fp);
258 |
259 | if ($buf === false) { // if we failed to read from file, return false
260 | return false;
261 | }
262 | return true;
263 | }
264 | }
265 |
--------------------------------------------------------------------------------
/Tests/Unit/Domain/Model/LogTest.php:
--------------------------------------------------------------------------------
1 |
9 | *
10 | * All rights reserved
11 | *
12 | * This script is part of the TYPO3 project. The TYPO3 project is
13 | * free software; you can redistribute it and/or modify
14 | * it under the terms of the GNU General Public License as published by
15 | * the Free Software Foundation; either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * The GNU General Public License can be found at
19 | * http://www.gnu.org/copyleft/gpl.html.
20 | *
21 | * This script is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU General Public License for more details.
25 | *
26 | * This copyright notice MUST APPEAR in all copies of the script!
27 | ***************************************************************/
28 |
29 | use AOE\SchedulerTimeline\Domain\Model\Log;
30 | use Nimut\TestingFramework\TestCase\UnitTestCase;
31 |
32 | /**
33 | * Class LogTest
34 | * @package AOE\SchedulerTimeline\Tests\Unit\Domain\Model
35 | */
36 | class LogTest extends UnitTestCase
37 | {
38 |
39 | /**
40 | * @var Log
41 | */
42 | protected $subject;
43 |
44 | public function setUp()
45 | {
46 | // Make sure that timezone is always the same in all testing environments
47 | date_default_timezone_set('UTC');
48 | $this->subject = new \AOE\SchedulerTimeline\Domain\Model\Log();
49 | }
50 |
51 | /**
52 | * @test
53 | */
54 | public function checkInitiationOfSubjectReturnObjectOfDomainModelLog()
55 | {
56 | $this->assertInstanceOf(
57 | 'AOE\SchedulerTimeline\Domain\Model\Log',
58 | $this->subject
59 | );
60 | }
61 |
62 | /**
63 | * @test
64 | */
65 | public function getStarttimeReturnsInitialValueForInteger()
66 | {
67 | $this->assertSame(
68 | 0,
69 | $this->subject->getStarttime()
70 | );
71 | }
72 |
73 | /**
74 | * @test
75 | */
76 | public function getEndtimeReturnsInitialValueForInteger()
77 | {
78 | $this->assertSame(
79 | 0,
80 | $this->subject->getEndtime()
81 | );
82 | }
83 |
84 | /**
85 | * @test
86 | */
87 | public function getExceptionReturnsInitialValueForString()
88 | {
89 | $this->assertSame(
90 | false,
91 | $this->subject->getException()
92 | );
93 | }
94 |
95 | /**
96 | * @test
97 | */
98 | public function getReturnmessageReturnsInitialValueForString()
99 | {
100 | $this->assertSame(
101 | '',
102 | $this->subject->getReturnmessage()
103 | );
104 | }
105 |
106 | /**
107 | * @test
108 | */
109 | public function getProcessIdReturnsInitialValueForInteger()
110 | {
111 | $this->assertSame(
112 | 0,
113 | $this->subject->getProcessid()
114 | );
115 | }
116 |
117 | /**
118 | * @test
119 | */
120 | public function getTaskReturnsNull()
121 | {
122 | $this->assertNull($this->subject->getTask());
123 | }
124 |
125 | /**
126 | * @test
127 | * @dataProvider getDurationReturnsDurationInSecondsDataProvider()
128 | */
129 | public function getDurationReturnsDurationInSeconds($starttime, $endtime, $expectedDuration)
130 | {
131 | $stub = $this->getAccessibleMock(
132 | 'AOE\\SchedulerTimeline\\Domain\\Model\\Log',
133 | array('getStarttime', 'getEndtime', 'getCurrentTime')
134 | );
135 | $stub->expects($this->any())->method('getStarttime')->will($this->returnValue($starttime));
136 | $stub->expects($this->any())->method('getEndtime')->will($this->returnValue($endtime));
137 | $stub->expects($this->any())->method('getCurrentTime')->will($this->returnValue(1000));
138 |
139 | $this->assertSame($expectedDuration, $stub->getDuration());
140 | }
141 |
142 | /**
143 | * @return array
144 | */
145 | public function getDurationReturnsDurationInSecondsDataProvider()
146 | {
147 | return array(
148 | 'With start- and endtime' => array(
149 | 'starttime' => 0,
150 | 'endtime' => 10,
151 | 'expectedDuration' => 10
152 | ),
153 | 'With starttime but no endtime' => array(
154 | 'starttime' => 0,
155 | 'endtime' => null,
156 | 'expectedDuration' => 1000
157 | ),
158 | 'With same start- and endtime' => array(
159 | 'starttime' => 100,
160 | 'endtime' => 100,
161 | 'expectedDuration' => 0
162 | ),
163 | 'With both start- and endtime being zero' => array(
164 | 'starttime' => 0,
165 | 'endtime' => 0,
166 | 'expectedDuration' => 1000
167 | ),
168 | 'With endtime lower than starttime' => array(
169 | 'starttime' => 100,
170 | 'endtime' => 10,
171 | 'expectedDuration' => -90
172 | ),
173 | );
174 | }
175 |
176 | /**
177 | * @test
178 | * @dataProvider isRunningReturnsBooleanDataProvider()
179 | */
180 | public function isRunningReturnsBoolean($endtime, $isRunning)
181 | {
182 | $stub = $this->getMockBuilder('AOE\\SchedulerTimeline\\Domain\\Model\\Log')
183 | ->setMethods(['getEndtime'])
184 | ->disableOriginalConstructor()
185 | ->getMock();
186 | $stub->expects($this->any())->method('getEndtime')->will($this->returnValue($endtime));
187 | $this->assertSame(
188 | $isRunning,
189 | $stub->isRunning()
190 | );
191 | }
192 |
193 | /**
194 | * @return array
195 | */
196 | public function isRunningReturnsBooleanDataProvider()
197 | {
198 | return array(
199 | 'Endtime set to zero' => array(
200 | 'endtime' => 0,
201 | 'isRunning' => true
202 | ),
203 | 'Endtime set to null' => array(
204 | 'entime' => null,
205 | 'isRunning' => true
206 | ),
207 | 'Endtime set' => array(
208 | 'endtime' => '10',
209 | 'isRunning' => false
210 | )
211 | );
212 | }
213 |
214 | /**
215 | * @test
216 | * @dataProvider getFormattedDateFromTimestampReturnsStringDataProvider()
217 | */
218 | public function getFormattedDateFromTimestampReturnsString($timestamp, $expectedFormattedDate)
219 | {
220 | $stub = $this->getAccessibleMock('AOE\\SchedulerTimeline\\Domain\\Model\\Log', array('dummy'));
221 |
222 | $this->assertSame(
223 | $expectedFormattedDate,
224 | $stub->_call('getFormattedDateFromTimestamp', $timestamp)
225 | );
226 | }
227 |
228 | /**
229 | * @return array
230 | */
231 | public function getFormattedDateFromTimestampReturnsStringDataProvider()
232 | {
233 | return array(
234 | 'Empty timestamp' => array(
235 | 'timestamp' => 0,
236 | 'expectedFormattedDate' => '00:00'
237 | ),
238 | 'Timestamp 2015-10-13 16:26' => array(
239 | 'timestamp' => strtotime('2015-10-13 16:26 UTC'),
240 | 'expectedFormattedDate' => '16:26'
241 | ),
242 | 'Timestamp 2015-11-13 10:13' => array(
243 | 'timestamp' => strtotime('2015-11-13 10:13 UTC'),
244 | 'expectedFormattedDate' => '10:13'
245 | ),
246 | );
247 | }
248 |
249 | /**
250 | * @test
251 | *
252 | * @param $isRunning
253 | * @param $starttime
254 | * @param $starttimeFormatted
255 | * @param $endtime
256 | * @param $endtimeFormatted
257 | * @param $expectedString
258 | *
259 | * @dataProvider getTimespanReturnsStringDataProvider()
260 | */
261 | public function getTimespanReturnsString($isRunning, $starttime, $starttimeFormatted, $endtime, $endtimeFormatted, $expectedString)
262 | {
263 | $stub = $this->getAccessibleMock(
264 | 'AOE\\SchedulerTimeline\\Domain\\Model\\Log',
265 | array('isRunning', 'getStarttime', 'getEndtime', 'getFormattedDateFromTimestamp')
266 | );
267 | $stub->expects($this->any())->method('isRunning')->will($this->returnValue($isRunning));
268 | $stub->expects($this->any())->method('getStarttime')->will($this->returnValue($starttime));
269 | $stub->expects($this->any())->method('getEndtime')->will($this->returnValue($endtime));
270 |
271 | $returnMap = array(
272 | array($starttime, $starttimeFormatted),
273 | array($endtime, $endtimeFormatted)
274 | );
275 |
276 | $stub->expects($this->any())->method('getFormattedDateFromTimestamp')->will($this->returnValueMap($returnMap));
277 |
278 | $this->assertSame(
279 | $expectedString,
280 | $stub->getTimespan()
281 | );
282 | }
283 |
284 | /**
285 | * @return array
286 | */
287 | public function getTimespanReturnsStringDataProvider()
288 | {
289 | return array(
290 | 'Task zero as starttime, task still running no endtime' => array(
291 | 'isRunning' => true,
292 | 'starttime' => 0,
293 | 'starttimeFormatted' => '00:00',
294 | 'endtime' => null,
295 | 'endtimeFormatted' => null,
296 | 'expectedString' => '00:00 - (still running)'
297 | ),
298 | 'Task with starttime 2015-10-13 16:26 and no endtime' => array(
299 | 'isRunning' => true,
300 | 'starttime' => strtotime('2015-10-13 16:26'),
301 | 'starttimeFormatted' => '16:26',
302 | 'endtime' => null,
303 | 'endtimeFormatted' => null,
304 | 'expectedString' => '16:26 - (still running)'
305 | ),
306 | 'Task with starttime 2015-11-13 9:26 and endtime 2015-11-13 10:13' => array(
307 | 'isRunning' => false,
308 | 'starttime' => strtotime('2015-11-13 9:26'),
309 | 'starttimeFormatted' => '09:26',
310 | 'endtime' => strtotime('2015-11-13 10:13'),
311 | 'endtimeFormatted' => '10:13',
312 | 'expectedString' => '09:26 - 10:13'
313 | ),
314 | );
315 | }
316 |
317 | /**
318 | * @test
319 | * @dataProvider getStatusReturnStringDataProvider()
320 | */
321 | public function getStatusReturnString($exception, $isRunning, $expectedStatus)
322 | {
323 | $stub = $this->getAccessibleMock('AOE\\SchedulerTimeline\\Domain\\Model\\Log', array('isRunning', 'getException'));
324 | $stub->expects($this->any())->method('isRunning')->will($this->returnValue($isRunning));
325 | $stub->expects($this->any())->method('getException')->will($this->returnValue($exception));
326 |
327 | $this->assertSame(
328 | $expectedStatus,
329 | $stub->getStatus()
330 | );
331 | }
332 |
333 | /**
334 | * @return array
335 | */
336 | public function getStatusReturnStringDataProvider()
337 | {
338 | return array(
339 | 'Task is still running' => array(
340 | 'exception' => null,
341 | 'isRunning' => true,
342 | 'expectedStatus' => \AOE\SchedulerTimeline\Domain\Model\Log::STATUS_RUNNING
343 | ),
344 | 'Task is done' => array(
345 | 'exception' => null,
346 | 'isRunning' => false,
347 | 'expectedStatus' => \AOE\SchedulerTimeline\Domain\Model\Log::STATUS_SUCCESS
348 | ),
349 | 'Task failed with exception' => array(
350 | 'exception' => 's:19:"NotWorkingException"',
351 | 'isRunning' => false,
352 | 'expectedStatus' => \AOE\SchedulerTimeline\Domain\Model\Log::STATUS_ERROR
353 | )
354 | );
355 | }
356 | }
357 |
--------------------------------------------------------------------------------
/Documentation/_make/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Note that not all possible configuration values are present in this
4 | # autogenerated file.
5 | #
6 | # All configuration values have a default; values that are commented out
7 | # serve to show the default.
8 |
9 | import sys
10 | import os
11 | import json
12 | from datetime import date
13 |
14 | # import composer.json
15 |
16 | with open('../../composer.json') as data_file:
17 | composer = json.load(data_file)
18 |
19 | # If extensions (or modules to document with autodoc) are in another directory,
20 | # add these directories to sys.path here. If the directory is relative to the
21 | # documentation root, use os.path.abspath to make it absolute, like shown here.
22 | #sys.path.insert(0, os.path.abspath('.'))
23 |
24 | # -- PHP highlighting configuration --------------------------------------------
25 |
26 | from sphinx.highlighting import lexers
27 | if lexers:
28 | from pygments.lexers.web import PhpLexer
29 | lexers['php'] = PhpLexer(startinline=True)
30 |
31 | # -- General configuration -----------------------------------------------------
32 |
33 | # If your documentation needs a minimal Sphinx version, state it here.
34 | #needs_sphinx = '1.0'
35 |
36 | # Add any Sphinx extension module names here, as strings. They can be
37 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
38 | # ones.
39 | extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.ifconfig']
40 |
41 | # Add any paths that contain templates here, relative to this directory.
42 | templates_path = ['../_templates']
43 |
44 | # The suffix of source filenames.
45 | source_suffix = '.rst'
46 |
47 | # The encoding of source files.
48 | #source_encoding = 'utf-8-sig'
49 |
50 | # The master toctree document.
51 | master_doc = 'Index'
52 |
53 | # General information about the project.
54 | project = composer["title"]
55 | copyright = str(date.today().year) + ' AOE GmbH'
56 |
57 | # The version info for the project you're documenting, acts as replacement for
58 | # |version| and |release|, also used in various other places throughout the
59 | # built documents.
60 | #
61 | # The short X.Y version.
62 | version = '0.4'
63 | # The full version, including alpha/beta/rc tags.
64 | release = composer["version"]
65 |
66 | # The language for content autogenerated by Sphinx. Refer to documentation
67 | # for a list of supported languages.
68 | #language = None
69 |
70 | # There are two options for replacing |today|: either, you set today to some
71 | # non-false value, then it is used:
72 | #today = ''
73 | # Else, today_fmt is used as the format for a strftime call.
74 | today_fmt = '%Y-%m-%d %H:%M'
75 |
76 | # List of patterns, relative to source directory, that match files and
77 | # directories to ignore when looking for source files.
78 | exclude_patterns = ['_make']
79 | exclude_trees = ['_make']
80 |
81 | # The reST default role (used for this markup: `text`) to use for all
82 | # documents.
83 | #default_role = None
84 |
85 | # If true, '()' will be appended to :func: etc. cross-reference text.
86 | #add_function_parentheses = True
87 |
88 | # If true, the current module name will be prepended to all description
89 | # unit titles (such as .. function::).
90 | #add_module_names = True
91 |
92 | # If true, sectionauthor and moduleauthor directives will be shown in the
93 | # output. They are ignored by default.
94 | #show_authors = False
95 |
96 | # The name of the Pygments (syntax highlighting) style to use.
97 | pygments_style = 'sphinx'
98 |
99 | # A list of ignored prefixes for module index sorting.
100 | #modindex_common_prefix = []
101 |
102 | # If true, keep warnings as "system message" paragraphs in the built documents.
103 | #keep_warnings = False
104 |
105 |
106 | # -- Options for HTML output ----------------------------------------------
107 |
108 | # The theme to use for HTML and HTML Help pages. See the documentation for
109 | # a list of builtin themes.
110 | html_theme = 'default'
111 |
112 | # Theme options are theme-specific and customize the look and feel of a theme
113 | # further. For a list of options available for each theme, see the
114 | # documentation.
115 | #html_theme_options = {}
116 |
117 | # Add any paths that contain custom themes here, relative to this directory.
118 | html_theme_path = []
119 |
120 | # The name for this set of Sphinx documents. If None, it defaults to
121 | # " v documentation".
122 | #html_title = None
123 |
124 | # A shorter title for the navigation bar. Default is the same as html_title.
125 | #html_short_title = None
126 |
127 | # The name of an image file (relative to this directory) to place at the top
128 | # of the sidebar.
129 | #html_logo = None
130 |
131 | # The name of an image file (within the static path) to use as favicon of the
132 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
133 | # pixels large.
134 | #html_favicon = None
135 |
136 | # Add any paths that contain custom static files (such as style sheets) here,
137 | # relative to this directory. They are copied after the builtin static files,
138 | # so a file named "default.css" will overwrite the builtin "default.css".
139 | html_static_path = ['../_static']
140 |
141 | # Add any extra paths that contain custom files (such as robots.txt or
142 | # .htaccess) here, relative to this directory. These files are copied
143 | # directly to the root of the documentation.
144 | #html_extra_path = []
145 |
146 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
147 | # using the given strftime format.
148 | #html_last_updated_fmt = '%b %d, %Y'
149 |
150 | # If true, SmartyPants will be used to convert quotes and dashes to
151 | # typographically correct entities.
152 | #html_use_smartypants = True
153 |
154 | # Custom sidebar templates, maps document names to template names.
155 | #html_sidebars = {}
156 |
157 | # Additional templates that should be rendered to pages, maps page names to
158 | # template names.
159 | #html_additional_pages = {}
160 |
161 | # If false, no module index is generated.
162 | #html_domain_indices = True
163 |
164 | # If false, no index is generated.
165 | #html_use_index = True
166 |
167 | # If true, the index is split into individual pages for each letter.
168 | #html_split_index = False
169 |
170 | # If true, links to the reST sources are added to the pages.
171 | #html_show_sourcelink = True
172 |
173 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
174 | #html_show_sphinx = True
175 |
176 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
177 | #html_show_copyright = True
178 |
179 | # If true, an OpenSearch description file will be output, and all pages will
180 | # contain a tag referring to it. The value of this option must be the
181 | # base URL from which the finished HTML is served.
182 | #html_use_opensearch = ''
183 |
184 | # This is the file name suffix for HTML files (e.g. ".xhtml").
185 | #html_file_suffix = None
186 |
187 | # Output file base name for HTML help builder.
188 | htmlhelp_basename = 'felogin_bruteforce_protectiondoc'
189 |
190 |
191 | # -- Options for LaTeX output --------------------------------------------------
192 |
193 | latex_elements = {
194 | # The paper size ('letterpaper' or 'a4paper').
195 | #'papersize': 'letterpaper',
196 |
197 | # The font size ('10pt', '11pt' or '12pt').
198 | #'pointsize': '10pt',
199 |
200 | # Additional stuff for the LaTeX preamble.
201 | 'preamble': '\\usepackage{typo3}'
202 | }
203 |
204 | # Grouping the document tree into LaTeX files. List of tuples
205 | # (source start file, target name, title,
206 | # author, documentclass [howto, manual, or own class]).
207 | latex_documents = [
208 | ('Index', 'felogin_bruteforce_protection.tex', u'Brute Force Protection',
209 | u'Kevin Schu, Andre Wuttig', 'manual'),
210 | ]
211 |
212 | # The name of an image file (relative to this directory) to place at the top of
213 | # the title page.
214 | #latex_logo = None
215 |
216 | # For "manual" documents, if this is true, then toplevel headings are parts,
217 | # not chapters.
218 | #latex_use_parts = False
219 |
220 | # If true, show page references after internal links.
221 | #latex_show_pagerefs = False
222 |
223 | # If true, show URL addresses after external links.
224 | #latex_show_urls = False
225 |
226 | # Documents to append as an appendix to all manuals.
227 | #latex_appendices = []
228 |
229 | # If false, no module index is generated.
230 | #latex_domain_indices = True
231 |
232 |
233 | # -- Options for rst2pdf output ------------------------------------------------
234 |
235 | # Grouping the document tree into PDF files. List of tuples
236 | # (source start file, target name, title, author, options).
237 | #
238 | # If there is more than one author, separate them with \\.
239 | # For example: r'Guido van Rossum\\Fred L. Drake, Jr., editor'
240 | #
241 | # The options element is a dictionary that lets you override
242 | # this config per-document.
243 | # For example,
244 | # ('index', u'MyProject', u'My Project', u'Author Name',
245 | # dict(pdf_compressed = True))
246 | # would mean that specific document would be compressed
247 | # regardless of the global pdf_compressed setting.
248 | pdf_documents = [
249 | ('Index', 'felogin_bruteforce_protection', u'Brute Force Protection',
250 | u'Kevin Schu, Andre Wuttig'),
251 | ]
252 |
253 | # A comma-separated list of custom stylesheets. Example:
254 | pdf_stylesheets = ['sphinx','kerning','a4']
255 |
256 | # A list of folders to search for stylesheets. Example:
257 | pdf_style_path = ['.', '_styles']
258 |
259 | # Create a compressed PDF
260 | # Use True/False or 1/0
261 | # Example: compressed=True
262 | #pdf_compressed = False
263 |
264 | # A colon-separated list of folders to search for fonts. Example:
265 | # pdf_font_path = ['/usr/share/fonts', '/usr/share/texmf-dist/fonts/']
266 |
267 | # Language to be used for hyphenation support
268 | #pdf_language = "en_US"
269 |
270 | # Mode for literal blocks wider than the frame. Can be
271 | # overflow, shrink or truncate
272 | #pdf_fit_mode = "shrink"
273 |
274 | # Section level that forces a break page.
275 | # For example: 1 means top-level sections start in a new page
276 | # 0 means disabled
277 | #pdf_break_level = 0
278 |
279 | # When a section starts in a new page, force it to be 'even', 'odd',
280 | # or just use 'any'
281 | #pdf_breakside = 'any'
282 |
283 | # Insert footnotes where they are defined instead of
284 | # at the end.
285 | #pdf_inline_footnotes = True
286 |
287 | # verbosity level. 0 1 or 2
288 | #pdf_verbosity = 0
289 |
290 | # If false, no index is generated.
291 | #pdf_use_index = True
292 |
293 | # If false, no modindex is generated.
294 | #pdf_use_modindex = True
295 |
296 | # If false, no coverpage is generated.
297 | #pdf_use_coverpage = True
298 |
299 | # Name of the cover page template to use
300 | #pdf_cover_template = 'sphinxcover.tmpl'
301 |
302 | # Documents to append as an appendix to all manuals.
303 | #pdf_appendices = []
304 |
305 | # Enable experimental feature to split table cells. Use it
306 | # if you get "DelayedTable too big" errors
307 | #pdf_splittables = False
308 |
309 | # Set the default DPI for images
310 | #pdf_default_dpi = 72
311 |
312 | # Enable rst2pdf extension modules (default is only vectorpdf)
313 | # you need vectorpdf if you want to use sphinx's graphviz support
314 | #pdf_extensions = ['vectorpdf']
315 |
316 | # Page template name for "regular" pages
317 | #pdf_page_template = 'cutePage'
318 |
319 | # Show Table Of Contents at the beginning?
320 | #pdf_use_toc = True
321 |
322 | # How many levels deep should the table of contents be?
323 | pdf_toc_depth = 9999
324 |
325 | # Add section number to section references
326 | pdf_use_numbered_links = False
327 |
328 | # Background images fitting mode
329 | pdf_fit_background_mode = 'scale'
330 |
331 |
332 | # -- Options for manual page output ---------------------------------------
333 |
334 | # One entry per manual page. List of tuples
335 | # (source start file, name, description, authors, manual section).
336 | man_pages = [
337 | ('Index', 'felogin_bruteforce_protection', u'Brute Force Protection',
338 | [u'Kevin Schu, Andre Wuttig'], 1)
339 | ]
340 |
341 | # If true, show URL addresses after external links.
342 | #man_show_urls = False
343 |
344 |
345 | # -- Options for Texinfo output -------------------------------------------
346 |
347 | # Grouping the document tree into Texinfo files. List of tuples
348 | # (source start file, target name, title, author,
349 | # dir menu entry, description, category)
350 | texinfo_documents = [
351 | ('Index', 'felogin_bruteforce_protection', u'Brute Force Protection',
352 | u'Kevin Schu, Andre Wuttig', 'Brute Force Protection', 'One line description of project.',
353 | 'Miscellaneous'),
354 | ]
355 |
356 | # Documents to append as an appendix to all manuals.
357 | #texinfo_appendices = []
358 |
359 | # If false, no module index is generated.
360 | #texinfo_domain_indices = True
361 |
362 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
363 | #texinfo_show_urls = 'footnote'
364 |
365 | # If true, do not generate a @detailmenu in the "Top" node's menu.
366 | #texinfo_no_detailmenu = False
367 |
368 |
369 | #=================================================
370 | #
371 | # TYPO3 codeblock BEGIN:
372 | #
373 | # Insert this codeblock at the end of your Sphinx
374 | # builder configuration file 'conf.py'.
375 | # This may enable TYPO3 specific features like
376 | # TYPO3 themes. It makes Yaml settings files work.
377 | #
378 | #-------------------------------------------------
379 |
380 | if 1 and "TYPO3 specific":
381 |
382 | try:
383 | t3DocTeam
384 | except NameError:
385 | t3DocTeam = {}
386 |
387 | try:
388 | import t3sphinx
389 | html_theme_path.insert(0, t3sphinx.themes_dir)
390 | html_theme = 'typo3sphinx'
391 | except:
392 | html_theme = 'default'
393 |
394 | t3DocTeam['conf_py_file'] = None
395 | try:
396 | t3DocTeam['conf_py_file'] = __file__
397 | except:
398 | import inspect
399 | t3DocTeam['conf_py_file'] = inspect.getfile(
400 | inspect.currentframe())
401 |
402 | t3DocTeam['conf_py_package_dir'] = os.path.abspath(os.path.dirname(
403 | t3DocTeam['conf_py_file']))
404 | t3DocTeam['relpath_to_master_doc'] = '..'
405 | t3DocTeam['relpath_to_logdir'] = '_not_versioned'
406 | t3DocTeam['path_to_logdir'] = os.path.join(
407 | t3DocTeam['conf_py_package_dir'],
408 | t3DocTeam['relpath_to_logdir'])
409 | t3DocTeam['pathToYamlSettings'] = os.path.join(
410 | t3DocTeam['conf_py_package_dir'],
411 | t3DocTeam['relpath_to_master_doc'], 'Settings.yml')
412 | try:
413 | t3DocTeam['pathToGlobalYamlSettings'] = \
414 | t3sphinx.pathToGlobalYamlSettings
415 | except:
416 | t3DocTeam['pathToGlobalYamlSettings'] = None
417 | if not t3DocTeam['pathToGlobalYamlSettings']:
418 | t3DocTeam['pathToGlobalYamlSettings'] = os.path.join(
419 | t3DocTeam['conf_py_package_dir'], 'GlobalSettings.yml')
420 | try:
421 | __function = t3sphinx.yamlsettings.processYamlSettings
422 | except:
423 | __function = None
424 | if not __function:
425 | try:
426 | import yamlsettings
427 | __function = yamlsettings.processYamlSettings
428 | except:
429 | __function = None
430 | if __function:
431 | __function(globals(), t3DocTeam)
432 |
433 | #-------------------------------------------------
434 | #
435 | # TYPO3 codeblock END.
436 | #
437 | #=================================================
--------------------------------------------------------------------------------
/Documentation/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------