├── .htaccess
├── LICENSE
├── README.md
├── bin
├── cake
├── cake.bat
└── cake.php
├── composer.json
├── config
├── Migrations
│ ├── 20150607191654_initial.php
│ ├── 20150607192040_add_report_id_index_to_incidents.php
│ ├── 20150607192459_add_dev_report_index_to_notifications.php
│ ├── 20160111023543_add_locale_to_incidents.php
│ ├── 20170515135017_fix_long_pma_versions.php
│ ├── 20170530155816_fix_stale_report_states.php
│ └── 20170711060435_AlterIncidents.php
├── app.default.php
├── app_ci.php
├── app_example.php
├── bootstrap.php
├── bootstrap_cli.php
├── forwarding_example.php
├── oauth_example.php
├── paths.php
├── requirements.php
├── routes.php
└── schema
│ ├── i18n.sql
│ └── sessions.sql
├── index.php
├── phpstan-baseline.neon
├── phpstan.neon.dist
├── phpunit.xml.dist
├── src
├── Application.php
├── Console
│ └── Installer.php
├── Controller
│ ├── AppController.php
│ ├── Component
│ │ ├── GithubApiComponent.php
│ │ ├── MailerComponent.php
│ │ └── OrderSearchComponent.php
│ ├── DevelopersController.php
│ ├── ErrorController.php
│ ├── EventsController.php
│ ├── GithubController.php
│ ├── IncidentsController.php
│ ├── NotificationsController.php
│ ├── PagesController.php
│ ├── ReportsController.php
│ └── StatsController.php
├── Forwarding
│ └── Sentry.php
├── Mailer
│ └── Transport
│ │ └── TestTransport.php
├── Model
│ └── Table
│ │ ├── DevelopersTable.php
│ │ ├── IncidentsTable.php
│ │ ├── NotificationsTable.php
│ │ └── ReportsTable.php
├── Report.php
├── Shell
│ ├── CleanOldNotifsShell.php
│ ├── ConsoleShell.php
│ ├── StatsShell.php
│ └── SyncGithubIssueStatesShell.php
└── View
│ ├── AppView.php
│ └── Helper
│ ├── AppHelper.php
│ ├── IncidentsHelper.php
│ └── ReportsHelper.php
├── templates
├── Error
│ ├── error400.php
│ └── error500.php
├── Github
│ └── create_issue.php
├── Incidents
│ └── view.php
├── Notifications
│ └── index.php
├── Pages
│ └── home.php
├── Reports
│ ├── index.php
│ └── view.php
├── Stats
│ └── stats.php
├── element
│ └── flash
│ │ ├── default.php
│ │ ├── error.php
│ │ └── success.php
├── email
│ ├── html
│ │ ├── default.php
│ │ └── report.php
│ └── text
│ │ └── default.php
└── layout
│ ├── ajax.php
│ ├── default.php
│ ├── email
│ ├── html
│ │ └── default.php
│ └── text
│ │ └── default.php
│ ├── error.php
│ ├── flash.php
│ ├── js
│ └── default.php
│ ├── rss
│ └── default.php
│ └── xml
│ └── default.php
├── tests
├── Fixture
│ ├── DevelopersFixture.php
│ ├── IncidentsFixture.php
│ ├── NotificationsFixture.php
│ ├── ReportsFixture.php
│ ├── comment_response.json
│ ├── empty
│ ├── issue_response.json
│ ├── report_issue_16853_js.json
│ ├── report_js.json
│ ├── report_php.json
│ └── user_response.json
├── TestCase
│ ├── AllTestsTest.php
│ ├── Controller
│ │ ├── Component
│ │ │ └── empty
│ │ ├── DevelopersControllerTest.php
│ │ ├── EventsControllerTest.php
│ │ ├── GithubControllerTest.php
│ │ ├── IncidentsControllerTest.php
│ │ ├── NotificationsControllerTest.php
│ │ └── ReportsControllerTest.php
│ ├── Model
│ │ ├── Behavior
│ │ │ └── empty
│ │ └── Table
│ │ │ ├── DevelopersTableTest.php
│ │ │ ├── IncidentsTableTest.php
│ │ │ ├── NotificationsTableTest.php
│ │ │ └── ReportsTableTest.php
│ ├── ReportTest.php
│ ├── Shell
│ │ ├── CleanOldNotifsShellTest.php
│ │ ├── StatsShellTest.php
│ │ └── SyncGithubIssueStatesShellTest.php
│ └── View
│ │ └── Helper
│ │ ├── ReportsHelperTest.php
│ │ └── empty
└── bootstrap.php
└── webroot
├── .htaccess
├── css
├── bootstrap-responsive.css
├── bootstrap-responsive.min.css
├── bootstrap.css
├── bootstrap.min.css
├── cake.generic.css
├── custom.css
├── jquery.dataTables.css
├── jquery.dataTables_themeroller.css
├── jquery.jqplot.min.css
├── shCore.css
└── shThemeDefault.css
├── favicon.ico
├── files
└── empty
├── img
├── Sorting icons.psd
├── back_disabled.png
├── back_enabled.png
├── back_enabled_hover.png
├── cake.icon.png
├── cake.power.gif
├── favicon.ico
├── forward_disabled.png
├── forward_enabled.png
├── forward_enabled_hover.png
├── glyphicons-halflings-white.png
├── glyphicons-halflings.png
├── sort_asc.png
├── sort_asc_disabled.png
├── sort_both.png
├── sort_desc.png
├── sort_desc_disabled.png
├── test-error-icon.png
├── test-fail-icon.png
├── test-pass-icon.png
└── test-skip-icon.png
├── index.php
├── js
├── bootstrap.js
├── bootstrap.min.js
├── custom.js
├── g.bar-min.js
├── g.dot-min.js
├── g.line-min.js
├── g.pie-min.js
├── g.raphael-min.js
├── jqplot.barRenderer.min.js
├── jqplot.canvasAxisTickRenderer.min.js
├── jqplot.canvasTextRenderer.min.js
├── jqplot.categoryAxisRenderer.min.js
├── jqplot.cursor.min.js
├── jqplot.dateAxisRenderer.min.js
├── jqplot.highlighter.min.js
├── jqplot.pointLabels.min.js
├── jquery.dataTables.min.js
├── jquery.jqplot.min.js
├── jquery.js
├── pie.js
├── raphael-min.js
├── shBrushJScript.js
├── shBrushPhp.js
├── shBrushXml.js
└── shCore.js
└── robots.txt
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | RewriteEngine on
3 | RewriteRule ^$ webroot/ [L]
4 | RewriteRule (.*) webroot/$1 [L]
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 phpMyAdmin
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/bin/cake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | ################################################################################
3 | #
4 | # Cake is a shell script for invoking CakePHP shell commands
5 | #
6 | # CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
7 | # Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
8 | #
9 | # Licensed under The MIT License
10 | # For full copyright and license information, please see the LICENSE.txt
11 | # Redistributions of files must retain the above copyright notice.
12 | #
13 | # @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
14 | # @link https://cakephp.org CakePHP(tm) Project
15 | # @since 1.2.0
16 | # @license https://opensource.org/licenses/mit-license.php MIT License
17 | #
18 | ################################################################################
19 |
20 | # Canonicalize by following every symlink of the given name recursively
21 | canonicalize() {
22 | NAME="$1"
23 | if [ -f "$NAME" ]
24 | then
25 | DIR=$(dirname -- "$NAME")
26 | NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME")
27 | fi
28 | while [ -h "$NAME" ]; do
29 | DIR=$(dirname -- "$NAME")
30 | SYM=$(readlink "$NAME")
31 | NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM")
32 | done
33 | echo "$NAME"
34 | }
35 |
36 | # Find a CLI version of PHP
37 | findCliPhp() {
38 | for TESTEXEC in php php-cli /usr/local/bin/php
39 | do
40 | SAPI=$(echo "= PHP_SAPI ?>" | $TESTEXEC 2>/dev/null)
41 | if [ "$SAPI" = "cli" ]
42 | then
43 | echo $TESTEXEC
44 | return
45 | fi
46 | done
47 | echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2
48 | echo "php";
49 | }
50 |
51 | # If current path is a symlink, resolve to real path
52 | realname="$0"
53 | if [ -L "$realname" ]
54 | then
55 | realname=$(readlink -f "$0")
56 | fi
57 |
58 | CONSOLE=$(dirname -- "$(canonicalize "$realname")")
59 | APP=$(dirname "$CONSOLE")
60 |
61 | # If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment
62 | # variable with the correct path in it.
63 | if [ -z "$PHP" ]
64 | then
65 | PHP=$(findCliPhp)
66 | fi
67 |
68 | if [ "$(basename "$realname")" != 'cake' ]
69 | then
70 | exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@"
71 | else
72 | exec "$PHP" "$CONSOLE"/cake.php "$@"
73 | fi
74 |
75 | exit
76 |
--------------------------------------------------------------------------------
/bin/cake.bat:
--------------------------------------------------------------------------------
1 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2 | ::
3 | :: Cake is a Windows batch script for invoking CakePHP shell commands
4 | ::
5 | :: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
6 | :: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
7 | ::
8 | :: Licensed under The MIT License
9 | :: Redistributions of files must retain the above copyright notice.
10 | ::
11 | :: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
12 | :: @link https://cakephp.org CakePHP(tm) Project
13 | :: @since 2.0.0
14 | :: @license https://opensource.org/licenses/mit-license.php MIT License
15 | ::
16 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
17 |
18 | @echo off
19 |
20 | SET app=%0
21 | SET lib=%~dp0
22 |
23 | php "%lib%cake.php" %*
24 |
25 | echo.
26 |
27 | exit /B %ERRORLEVEL%
28 |
--------------------------------------------------------------------------------
/bin/cake.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/php -q
2 | run($argv));
13 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phpmyadmin/error-reporting-server",
3 | "type": "application",
4 | "description": "phpMyAdmin server side component for the error reporting system",
5 | "keywords": ["phpmyadmin","mysql","web"],
6 | "homepage": "https://www.phpmyadmin.net/",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "The phpMyAdmin Team",
11 | "email": "developers@phpmyadmin.net",
12 | "homepage": "https://www.phpmyadmin.net/team/"
13 | }
14 | ],
15 | "support": {
16 | "issues": "https://github.com/phpmyadmin/error-reporting-server/issues",
17 | "wiki": "https://wiki.phpmyadmin.net/",
18 | "source": "https://github.com/phpmyadmin/error-reporting-server"
19 | },
20 | "require": {
21 | "php": "^7.4 || ^8.0",
22 | "ext-curl": "*",
23 | "cakephp/cakephp": "4.2.x",
24 | "cakephp/migrations": "^3.0.0",
25 | "cakephp/plugin-installer": "^1.3",
26 | "composer/ca-bundle": "^1.3"
27 | },
28 | "require-dev": {
29 | "cakedc/cakephp-phpstan": "^2",
30 | "cakephp/bake": "^2.1.1",
31 | "cakephp/debug_kit": "^4.1.2",
32 | "php-mock/php-mock-phpunit": "^2.6",
33 | "phpmyadmin/coding-standard": "^3",
34 | "phpstan/phpstan": "^1",
35 | "phpunit/phpunit": "^9",
36 | "psy/psysh": "@stable"
37 | },
38 | "autoload": {
39 | "psr-4": {
40 | "App\\": "src/"
41 | }
42 | },
43 | "autoload-dev": {
44 | "psr-4": {
45 | "App\\Test\\": "tests/",
46 | "Cake\\Test\\": "vendor/cakephp/cakephp/tests/"
47 | }
48 | },
49 | "scripts": {
50 | "post-install-cmd": "App\\Console\\Installer::postInstall",
51 | "check": [
52 | "@test",
53 | "@phpcs"
54 | ],
55 | "phpcs": "@php ./vendor/bin/phpcs",
56 | "phpcbf": "@php ./vendor/bin/phpcbf",
57 | "test": "@php ./vendor/bin/phpunit",
58 | "phpstan": "@php ./vendor/bin/phpstan"
59 | },
60 | "prefer-stable": true,
61 | "config": {
62 | "sort-packages": true,
63 | "allow-plugins": {
64 | "dealerdirect/phpcodesniffer-composer-installer": true,
65 | "cakephp/plugin-installer": true
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/config/Migrations/20150607192040_add_report_id_index_to_incidents.php:
--------------------------------------------------------------------------------
1 | table('incidents');
16 | $table->addIndex(
17 | ['report_id']
18 | );
19 | $table->update();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/config/Migrations/20150607192459_add_dev_report_index_to_notifications.php:
--------------------------------------------------------------------------------
1 | table('notifications');
16 | $table->addIndex([
17 | 'developer_id',
18 | 'report_id',
19 | ]);
20 | $table->update();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/config/Migrations/20160111023543_add_locale_to_incidents.php:
--------------------------------------------------------------------------------
1 | table('incidents');
31 | $table
32 | ->addColumn('locale', 'string', [
33 | 'default' => null,
34 | 'limit' => 30,
35 | 'null' => true,
36 | ])
37 | ->update();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/config/Migrations/20170515135017_fix_long_pma_versions.php:
--------------------------------------------------------------------------------
1 | _sanitizeVersionsInTable('reports');
18 | Log::debug($count . ' reports updated');
19 |
20 | // Strip phpMyAdmin versions in `incidents` table
21 | $count = $this->_sanitizeVersionsInTable('incidents');
22 | Log::debug($count . ' incidents updated');
23 | }
24 |
25 | public function down(): void
26 | {
27 | // Once applied, this migration can't be reversed
28 | // but the migration itself is idempotent
29 | }
30 |
31 | private function _sanitizeVersionsInTable(string $table): int
32 | {
33 | $sql = 'SELECT `id`, `pma_version` FROM `' . $table . '`';
34 | $count = 0;
35 | $incidentsTable = TableRegistry::getTableLocator()->get('Incidents');
36 | $result = $this->query($sql);
37 |
38 | while ($row = $result->fetch()) {
39 | $strippedVersionString
40 | = IncidentsTable::getStrippedPmaVersion(
41 | $row['pma_version']
42 | );
43 |
44 | if ($strippedVersionString === $row['pma_version']) {
45 | continue;
46 | }
47 |
48 | $this->execute('UPDATE ' . $table . ' SET `pma_version` = \''
49 | . $strippedVersionString . '\' WHERE `id` = \''
50 | . $row['id'] . '\'');
51 |
52 | ++$count;
53 | }
54 |
55 | return $count;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/config/Migrations/20170530155816_fix_stale_report_states.php:
--------------------------------------------------------------------------------
1 | _migrateBasedOnGithubLinked();
15 | $this->_migrateToNewStatus();
16 | $this->_migrateDuplicateReports();
17 | }
18 |
19 | private function _migrateBasedOnGithubLinked(): void
20 | {
21 | $sql = 'UPDATE `reports` SET `status` = \'forwarded\''
22 | . ' WHERE `sourceforge_bug_id` IS NOT NULL AND `status` <> \'fixed\'';
23 | $rowsAffected = $this->execute($sql);
24 |
25 | Log::debug(
26 | $rowsAffected . ' reports are linked to a'
27 | . ' Github issue.'
28 | . ' These have been marked to have a \'forwarded\' status.'
29 | );
30 | }
31 |
32 | private function _migrateToNewStatus(): void
33 | {
34 | $statusMap = [
35 | 'fixed' => 'resolved',
36 | 'open' => 'new',
37 | 'out-of-date' => 'invalid',
38 | 'works-for-me' => 'invalid',
39 | 'wontfix' => 'invalid',
40 | ];
41 |
42 | foreach ($statusMap as $oldStatus => $newStatus) {
43 | $sql = 'UPDATE `reports` SET `status` = \'' . $newStatus . '\''
44 | . ' WHERE `status` = \'' . $oldStatus . '\'';
45 | $rowsAffected = $this->execute($sql);
46 |
47 | Log::debug(
48 | $rowsAffected . ' reports with \'' . $oldStatus . '\''
49 | . ' were mapped to \'' . $newStatus . '\'.'
50 | );
51 | }
52 | }
53 |
54 | private function _migrateDuplicateReports(): void
55 | {
56 | // Find the original reports and set the status
57 | // of their duplicate reports same as their status
58 | $sql = 'SELECT `id`, `status` FROM `reports` WHERE'
59 | . ' `related_to` IS NULL';
60 | $origCount = 0;
61 | $result = $this->query($sql);
62 | $rowsAffected = 0;
63 |
64 | while ($row = $result->fetch()) {
65 | $update_sql = 'UPDATE `reports` SET `status` = \''
66 | . $row['status'] . '\' WHERE `id` = \''
67 | . $row['id'] . '\'';
68 |
69 | $rowsAffected += $this->execute($update_sql);
70 | $origCount++;
71 | }
72 |
73 | Log::debug(
74 | $rowsAffected . ' duplicate reports were mapped to '
75 | . ' same status as their ' . $origCount . ' original reports'
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/config/Migrations/20170711060435_AlterIncidents.php:
--------------------------------------------------------------------------------
1 | table('incidents');
16 | $table->changeColumn('error_message', 'string', [
17 | 'default' => null,
18 | 'limit' => 200,
19 | 'null' => true,
20 | ]);
21 | $table->update();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/config/bootstrap_cli.php:
--------------------------------------------------------------------------------
1 | 'https://sentry.domain.tld',// Without the last /
15 | 'project_id' => 2,// Settings > Security headers (can be found in the URL: api/{project_id}/security)
16 | 'key' => 'xxxxxxxxxxxxxxxxxx',// Settings > Security headers
17 | 'secret' => 'xxxxxxxxxxxxxxxxxxxx',// Settings > Client Keys > DSN (deprecated, use password value of the http basic auth)
18 | // Used to send user feedback
19 | 'dsn_url' => 'https://xxxxxxxxxxxxxxxxxx@sentry.domain.tld/{project_id}',// Settings > Client Keys > DSN
20 | ]);
21 |
22 | // Remove this line or the forwarding will be disabled
23 | Configure::write('Forwarding.Sentry', null);
24 |
--------------------------------------------------------------------------------
/config/oauth_example.php:
--------------------------------------------------------------------------------
1 | '',
13 | 'client_secret' => '',
14 | ]);
15 |
16 | /**
17 | * Configures the github repo to check commit access for
18 | */
19 | Configure::write('GithubRepoPath', 'phpmyadmin/phpmyadmin');
20 |
21 | /**
22 | * Access token for syncing Github issue states
23 | */
24 | Configure::write('GithubAccessToken', '');
25 |
--------------------------------------------------------------------------------
/config/paths.php:
--------------------------------------------------------------------------------
1 | connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
55 |
56 | /**
57 | * ...and connect the rest of 'Pages' controller's URLs.
58 | */
59 | $routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
60 |
61 | $routes->connect('/stats', ['controller' => 'Stats', 'action' => 'stats']);
62 |
63 | $routes->connect(
64 | '/reports/view/{id}',
65 | ['controller' => 'Reports', 'action' => 'view'],
66 | ['_name' => 'reports:view']
67 | )
68 | ->setPass(['id', 'reportId'])
69 | ->setPatterns([
70 | 'id' => '[0-9]+',
71 | ]);
72 |
73 | $routes->connect(
74 | '/github/sync_issue_status',
75 | ['controller' => 'Github', 'action' => 'sync_issue_status']
76 | );
77 |
78 | $routes->connect(
79 | '/github/create_issue/{id}',
80 | ['controller' => 'Github', 'action' => 'create_issue'],
81 | ['_name' => 'github:create_issue']
82 | )
83 | ->setPass(['id', 'reportId'])
84 | ->setPatterns([
85 | 'id' => '[0-9]+',
86 | ]);
87 |
88 | $routes->connect(
89 | '/github/unlink_issue/{id}',
90 | ['controller' => 'Github', 'action' => 'unlink_issue'],
91 | ['_name' => 'github:unlink_issue']
92 | )
93 | ->setPass(['id', 'reportId'])
94 | ->setPatterns([
95 | 'id' => '[0-9]+',
96 | ]);
97 |
98 | $routes->connect(
99 | '/github/link_issue/{id}',
100 | ['controller' => 'Github', 'action' => 'link_issue'],
101 | ['_name' => 'github:link_issue']
102 | )
103 | ->setPass(['id', 'reportId'])
104 | ->setPatterns([
105 | 'id' => '[0-9]+',
106 | ]);
107 | /**
108 | * Connect catchall routes for all controllers.
109 | *
110 | * Using the argument `DashedRoute`, the `fallbacks` method is a shortcut for
111 | *
112 | * ```
113 | * $routes->connect('/:controller', ['action' => 'index'], ['routeClass' => 'DashedRoute']);
114 | * $routes->connect('/:controller/:action/*', [], ['routeClass' => 'DashedRoute']);
115 | * ```
116 | *
117 | * Any route class can be used with this method, such as:
118 | * - DashedRoute
119 | * - InflectedRoute
120 | * - Route
121 | * - Or your own route class
122 | *
123 | * You can remove these routes once you've connected the
124 | * routes you want in your application.
125 | */
126 | $routes->fallbacks(InflectedRoute::class);
127 | });
128 |
129 | /**
130 | * If you need a different set of middleware or none at all,
131 | * open new scope and define routes there.
132 | *
133 | * ```
134 | * Router::scope('/api', function (RouteBuilder $routes) {
135 | * // No $routes->applyMiddleware() here.
136 | * // Connect API actions here.
137 | * });
138 | * ```
139 | */
140 |
--------------------------------------------------------------------------------
/config/schema/i18n.sql:
--------------------------------------------------------------------------------
1 | # Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
2 | #
3 | # Licensed under The MIT License
4 | # For full copyright and license information, please see the LICENSE.txt
5 | # Redistributions of files must retain the above copyright notice.
6 | # MIT License (https://opensource.org/licenses/mit-license.php)
7 |
8 | CREATE TABLE i18n (
9 | id int NOT NULL auto_increment,
10 | locale varchar(6) NOT NULL,
11 | model varchar(255) NOT NULL,
12 | foreign_key int(10) NOT NULL,
13 | field varchar(255) NOT NULL,
14 | content text,
15 | PRIMARY KEY (id),
16 | UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field),
17 | INDEX I18N_FIELD(model, foreign_key, field)
18 | );
19 |
--------------------------------------------------------------------------------
/config/schema/sessions.sql:
--------------------------------------------------------------------------------
1 | # Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
2 | #
3 | # Licensed under The MIT License
4 | # For full copyright and license information, please see the LICENSE.txt
5 | # Redistributions of files must retain the above copyright notice.
6 | # MIT License (https://opensource.org/licenses/mit-license.php)
7 |
8 | CREATE TABLE `sessions` (
9 | `id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
10 | `created` datetime DEFAULT CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+
11 | `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+
12 | `data` blob DEFAULT NULL, -- for PostgreSQL use bytea instead of blob
13 | `expires` int(10) unsigned DEFAULT NULL,
14 | PRIMARY KEY (`id`)
15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
16 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | tests/TestCase/
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | src/
38 | plugins/*/src/
39 |
40 | src/Console/Installer.php
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/Application.php:
--------------------------------------------------------------------------------
1 | bootstrapCli();
49 | }
50 |
51 | /*
52 | * Only try to load DebugKit in development mode
53 | * Debug Kit should not be installed on a production system
54 | */
55 | if (Configure::read('debug')) {
56 | $this->addPlugin(Plugin::class);
57 | }
58 |
59 | // Load more plugins here
60 | }
61 |
62 | /**
63 | * Setup the middleware queue your application will use.
64 | *
65 | * @param MiddlewareQueue $middlewareQueue The middleware queue to setup.
66 | * @return MiddlewareQueue The updated middleware queue.
67 | */
68 | public function middleware($middlewareQueue): MiddlewareQueue
69 | {
70 | $middlewareQueue
71 | // Catch any exceptions in the lower layers,
72 | // and make an error page/response
73 | ->add(new ErrorHandlerMiddleware(Configure::read('Error')))
74 |
75 | // Handle plugin/theme assets like CakePHP normally does.
76 | ->add(new AssetMiddleware([
77 | 'cacheTime' => Configure::read('Asset.cacheTime'),
78 | ]))
79 |
80 | // Add routing middleware.
81 | // If you have a large number of routes connected, turning on routes
82 | // caching in production could improve performance. For that when
83 | // creating the middleware instance specify the cache config name by
84 | // using it's second constructor argument:
85 | // `new RoutingMiddleware($this, '_cake_routes_')`
86 | ->add(new RoutingMiddleware($this));
87 |
88 | return $middlewareQueue;
89 | }
90 |
91 | protected function bootstrapCli(): void
92 | {
93 | try {
94 | $this->addPlugin('Bake');
95 | } catch (MissingPluginException $e) {// phpcs:ignore
96 | // Do not halt if the plugin is missing
97 | }
98 |
99 | $this->addPlugin('Migrations');
100 |
101 | // Load more plugins here
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/Controller/Component/MailerComponent.php:
--------------------------------------------------------------------------------
1 | viewBuilder()->setLayout('default');
55 | $email->viewBuilder()->setTemplate('report');
56 |
57 | $email->setTransport($emailTransport)
58 | ->setViewVars($viewVars)
59 | ->setSubject(
60 | sprintf(
61 | 'A new report has been submitted on the Error Reporting Server: %s',
62 | $viewVars['report']['id']
63 | )
64 | )
65 | ->setEmailFormat('html')
66 | ->setTo($emailTo)
67 | ->setFrom($emailFrom)
68 | ->send();
69 |
70 | return true;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Controller/Component/OrderSearchComponent.php:
--------------------------------------------------------------------------------
1 | []];
45 | $keys = array_keys($aColumns);
46 | $columnsCount = count($aColumns);
47 |
48 | $sSearch = $request->getQuery('sSearch');
49 | if ($sSearch !== '' && $sSearch !== null) {
50 | for ($i = 0; $i < $columnsCount; ++$i) {
51 | if ($request->getQuery('bSearchable_' . ($i + 1)) !== 'true') {
52 | continue;
53 | }
54 |
55 | $searchConditions['OR'][] = [$aColumns[$keys[$i]] . ' LIKE' => '%' . $sSearch . '%'];
56 | }
57 | }
58 |
59 | /* Individual column filtering */
60 | for ($i = 0; $i < $columnsCount; ++$i) {
61 | $searchTerm = $request->getQuery('sSearch_' . ($i + 1));
62 | if ($searchTerm === '' || $searchTerm === null) {
63 | continue;
64 | }
65 |
66 | $searchConditions[] = [$aColumns[$keys[$i]] . ' LIKE' => $searchTerm];
67 | }
68 |
69 | return $searchConditions;
70 | }
71 |
72 | /**
73 | * @param string[] $aColumns The columns
74 | *
75 | * @return array|null
76 | */
77 | public function getOrder(array $aColumns, ServerRequest $request): ?array
78 | {
79 | if ($request->getQuery('iSortCol_0') !== null) {
80 | $order = [];
81 | //Seems like we need to sort with only one column each time, so no need to loop
82 | $sort_column_index = intval($request->getQuery('iSortCol_0'));
83 |
84 | $keys = array_keys($aColumns);
85 |
86 | if (
87 | $sort_column_index > 0
88 | && $request->getQuery('bSortable_' . $sort_column_index) === 'true'
89 | ) {
90 | $order[$aColumns[$keys[$sort_column_index - 1]]] = $request->getQuery('sSortDir_0');
91 | }
92 |
93 | return $order;
94 | }
95 |
96 | return null;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Controller/DevelopersController.php:
--------------------------------------------------------------------------------
1 | loadComponent('GithubApi');
43 | $this->viewBuilder()->setHelpers([
44 | 'Html',
45 | 'Form',
46 | ]);
47 | }
48 |
49 | public function login(): void
50 | {
51 | $url = $this->GithubApi->getRedirectUrl('user:email,public_repo');
52 | $this->redirect($url);
53 | }
54 |
55 | public function callback(): ?Response
56 | {
57 | $code = $this->request->getQuery('code');
58 | $accessToken = $this->GithubApi->getAccessToken($code);
59 | if (empty($code) || empty($accessToken)) {
60 | $flash_class = 'alert alert-error';
61 | $this->Flash->set(
62 | 'We were not able to authenticate you.'
63 | . ' Please try again later',
64 | ['params' => ['class' => $flash_class]]
65 | );
66 |
67 | return $this->redirect('/');
68 | }
69 |
70 | [$userInfo, $status] = $this->GithubApi->getUserInfo($accessToken);
71 | if ($status !== 200) {
72 | $flash_class = 'alert alert-error';
73 | $this->Flash->set(
74 | $userInfo['message'],
75 | ['params' => ['class' => $flash_class]]
76 | );
77 |
78 | return $this->redirect('/');
79 | }
80 |
81 | $userInfo['has_commit_access'] = $this->GithubApi->canCommitTo(
82 | $userInfo['login'],
83 | Configure::read('GithubRepoPath'),
84 | Configure::read('GithubAccessToken')
85 | );
86 |
87 | $this->authenticateDeveloper($userInfo, $accessToken);
88 |
89 | $flash_class = 'alert alert-success';
90 | $this->Flash->set(
91 | 'You have been logged in successfully',
92 | ['params' => ['class' => $flash_class]]
93 | );
94 |
95 | $last_page = $this->request->getSession()->read('last_page');
96 | if (empty($last_page)) {
97 | $last_page = [
98 | 'controller' => 'reports',
99 | 'action' => 'index',
100 | ];
101 | }
102 |
103 | return $this->redirect($last_page);
104 | }
105 |
106 | public function logout(): void
107 | {
108 | $this->request->getSession()->destroy();
109 |
110 | $flash_class = 'alert alert-success';
111 | $this->Flash->set(
112 | 'You have been logged out successfully',
113 | ['params' => ['class' => $flash_class]]
114 | );
115 | $this->redirect('/');
116 | }
117 |
118 | protected function authenticateDeveloper(array $userInfo, string $accessToken): void
119 | {
120 | $developers = $this->Developers->findByGithubId($userInfo['id']);
121 | $developer = $developers->all()->first();
122 | if (! $developer) {
123 | $developer = $this->Developers->newEmptyEntity();
124 | } else {
125 | $this->Developers->id = $developer['id'];
126 | }
127 |
128 | $this->Developers->id = $this->Developers->saveFromGithub($userInfo, $accessToken, $developer);
129 | $this->request->getSession()->write('Developer.id', $this->Developers->id);
130 | $this->request->getSession()->write('access_token', $accessToken);
131 | $this->request->getSession()->write('read_only', ! $userInfo['has_commit_access']);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/Controller/ErrorController.php:
--------------------------------------------------------------------------------
1 | viewBuilder()->setTemplatePath('Error');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Controller/PagesController.php:
--------------------------------------------------------------------------------
1 | redirect('/');
62 | }
63 |
64 | $page = $subpage = $title_for_layout = null;
65 | if (! empty($path[0])) {
66 | $page = $path[0];
67 | }
68 |
69 | if (! empty($path[1])) {
70 | $subpage = $path[1];
71 | }
72 |
73 | if (! empty($path[$count - 1])) {
74 | $title_for_layout = Inflector::humanize($path[$count - 1]);
75 | }
76 |
77 | $this->set([
78 | 'page' => $page,
79 | 'subpage' => $subpage,
80 | 'title_for_layout' => $title_for_layout,
81 | ]);
82 |
83 | try {
84 | $this->render(implode('/', $path));
85 | } catch (MissingViewException $e) {
86 | if (Configure::read('debug')) {
87 | throw $e;
88 | }
89 |
90 | throw new NotFoundException();
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Controller/StatsController.php:
--------------------------------------------------------------------------------
1 | viewBuilder()->setHelpers(['Reports']);
46 | $this->loadModel('Incidents');
47 | }
48 |
49 | public function stats(): void
50 | {
51 | $filter = $this->getTimeFilter();
52 | $relatedEntries = [];
53 | $filter_string = $this->request->getQuery('filter');
54 | if (! $filter_string) {
55 | $filter_string = 'all_time';
56 | }
57 |
58 | $entriesWithCount = [];
59 | //Cache::clear();
60 | foreach ($this->Incidents->summarizableFields as $field) {
61 | $entriesWithCount = Cache::read($field . '_' . $filter_string);
62 | if ($entriesWithCount === null) {
63 | $entriesWithCount = TableRegistry::getTableLocator()->get('Reports')->
64 | getRelatedByField($field, 25, false, false, $filter['limit']);
65 | $entriesWithCount = json_encode($entriesWithCount);
66 | Cache::write($field . '_' . $filter_string, $entriesWithCount);
67 | }
68 |
69 | $relatedEntries[$field] = json_decode($entriesWithCount, true);
70 | }
71 |
72 | $this->set('related_entries', $relatedEntries);
73 | $this->set('columns', $this->Incidents->summarizableFields);
74 | $this->set('filter_times', $this->Incidents->filterTimes);
75 | $this->set('selected_filter', $this->request->getQuery('filter'));
76 |
77 | $query = [
78 | 'group' => 'grouped_by',
79 | 'order' => 'Incidents.created',
80 | ];
81 |
82 | if (isset($filter['limit'])) {
83 | $query['conditions'] = [
84 | 'Incidents.created >=' => $filter['limit'],
85 | ];
86 | }
87 |
88 | $this->Incidents->recursive = -1;
89 | $downloadStats = Cache::read('downloadStats_' . $filter_string);
90 | if ($downloadStats === null) {
91 | $downloadStats = $this->Incidents->find('all', $query);
92 | $downloadStats->select([
93 | 'grouped_by' => $filter['group'],
94 | 'date' => "DATE_FORMAT(Incidents.created, '%a %b %d %Y %T')",
95 | 'count' => $downloadStats->func()->count('*'),
96 | ]);
97 | $downloadStats = json_encode($downloadStats->toArray());
98 | Cache::write('downloadStats_' . $filter_string, $downloadStats);
99 | }
100 |
101 | $this->set('download_stats', json_decode($downloadStats, true));
102 | }
103 |
104 | /**
105 | * @return mixed I am not sure about the type
106 | */
107 | protected function getTimeFilter()
108 | {
109 | if ($this->request->getQuery('filter')) {
110 | $filter = $this->Incidents->filterTimes[$this->request->getQuery('filter')];
111 | }
112 |
113 | if (isset($filter)) {
114 | return $filter;
115 | }
116 |
117 | return $this->Incidents->filterTimes['all_time'];
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/Mailer/Transport/TestTransport.php:
--------------------------------------------------------------------------------
1 | getHeaders(
26 | [
27 | 'from',
28 | 'sender',
29 | 'replyTo',
30 | 'readReceipt',
31 | 'returnPath',
32 | 'to',
33 | 'cc',
34 | 'subject',
35 | ]
36 | );
37 |
38 | $message = trim($message->getBodyString());
39 | $result = [
40 | 'headers' => $headers,
41 | 'message' => $message,
42 | ];
43 |
44 | Configure::write('test_transport_email', $result);
45 |
46 | return $result;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Model/Table/DevelopersTable.php:
--------------------------------------------------------------------------------
1 | full_name = $githubInfo['name'];
41 | $developer->gravatar_id = $githubInfo['gravatar_id'];
42 | $developer->email = $githubInfo['email'];
43 | $developer->github_id = $githubInfo['id'];
44 | $developer->access_token = $accessToken;
45 | $developer->has_commit_access = $githubInfo['has_commit_access'] ? 1 : 0;
46 | if ($this->save($developer)) {
47 | return $developer->id;
48 | }
49 |
50 | return null;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Model/Table/NotificationsTable.php:
--------------------------------------------------------------------------------
1 | [
44 | 'numeric' => [
45 | 'rule' => ['numeric'],
46 | 'allowEmpty' => false,
47 | 'required' => true,
48 | ],
49 | ],
50 | 'report_id' => [
51 | 'numeric' => [
52 | 'rule' => ['numeric'],
53 | 'allowEmpty' => false,
54 | 'required' => true,
55 | ],
56 | ],
57 | ];
58 |
59 | /**
60 | * The Associations below have been created with all possible keys,
61 | * those that are not needed can be removed.
62 | */
63 |
64 | /**
65 | * belongsTo associations.
66 | *
67 | * @param array $config Config array
68 | * @return void Nothing
69 | */
70 | public function initialize(array $config): void
71 | {
72 | $this->belongsTo('Reports', [
73 | 'className' => 'Reports',
74 | 'foreignKey' => 'report_id',
75 | ]);
76 | }
77 |
78 | /**
79 | * To Add Multiple Notifications for New report.
80 | *
81 | * @param int $report_id id of the new Report
82 | *
83 | * @return bool|object value. True on success. False on any type of failure.
84 | */
85 | public static function addNotifications(int $report_id)
86 | {
87 | if (! is_int($report_id)) {
88 | throw new InvalidArgumentException('Invalid Argument "$report_id"! Integer Expected.');
89 | }
90 |
91 | $devs = TableRegistry::getTableLocator()->get('Developers')->find('all');
92 | $notoficationTable = TableRegistry::getTableLocator()->get('Notifications');
93 | $res = true;
94 | foreach ($devs as $dev) {
95 | $notification = $notoficationTable->newEmptyEntity();
96 | $notification->developer_id = $dev['id'];
97 | $notification->report_id = $report_id;
98 | $notification->created = date('Y-m-d H:i:s', time());
99 | $notification->modified = date('Y-m-d H:i:s', time());
100 | $res = $notoficationTable->save($notification);
101 | }
102 |
103 | return $res;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/Shell/CleanOldNotifsShell.php:
--------------------------------------------------------------------------------
1 | setCommand($this->name)
56 | ->setDescription('Clean old notifications');
57 | }
58 |
59 | public function initialize(): void
60 | {
61 | parent::initialize();
62 | $this->loadModel('Notifications');
63 | }
64 |
65 | public function execute(Arguments $args, ConsoleIo $io)
66 | {
67 | $XTime = time() - 60 * 24 * 3600;
68 | $conditions = ['Notifications.created <' => date('Y-m-d H:i:s', $XTime)];
69 |
70 | if ($this->Notifications->find('all', ['conditions' => $conditions])->count() === 0) {
71 | // Check if there are any notifications to delete
72 | Log::write(
73 | 'info',
74 | 'No notifications found for deleting!',
75 | 'cron_jobs'
76 | );
77 | } elseif ($this->Notifications->deleteAll($conditions)) {
78 | // Try deleting the matched records
79 | Log::write(
80 | 'info',
81 | 'Old notifications deleted successfully!',
82 | 'cron_jobs'
83 | );
84 | } else {
85 | // If NOT successful, print out an error message
86 | Log::write(
87 | 'error',
88 | 'Deleting old notifications failed!',
89 | 'cron_jobs'
90 | );
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Shell/ConsoleShell.php:
--------------------------------------------------------------------------------
1 | setCommand($this->name)
54 | ->setDescription('Open an interactive console');
55 | }
56 |
57 | /**
58 | * Start the shell and interactive console.
59 | *
60 | * @return int|void
61 | */
62 | public function execute(Arguments $args, ConsoleIo $io)
63 | {
64 | if (! class_exists(PsyShell::class)) {
65 | $io->err('Unable to load Psy\Shell. ');
66 | $io->err('');
67 | $io->err('Make sure you have installed psysh as a dependency,');
68 | $io->err('and that Psy\Shell is registered in your autoloader.');
69 | $io->err('');
70 | $io->err('If you are using composer run');
71 | $io->err('');
72 | $io->err('$ php composer.phar require --dev psy/psysh ');
73 | $io->err('');
74 |
75 | return 1;
76 | }
77 |
78 | $io->out('You can exit with `CTRL-C` or `exit` ');
79 | $io->out('');
80 |
81 | Log::drop('debug');
82 | Log::drop('error');
83 | $io->setLoggers(false);
84 | restore_error_handler();
85 | restore_exception_handler();
86 |
87 | $psy = new PsyShell();
88 | $psy->run();
89 | }
90 |
91 | /**
92 | * Display help for this console.
93 | *
94 | * @return ConsoleOptionParser The console option
95 | */
96 | public function getOptionParser(): ConsoleOptionParser
97 | {
98 | $parser = new ConsoleOptionParser($this->name, false);
99 | $parser->setDescription(
100 | 'This shell provides a REPL that you can use to interact ' .
101 | 'with your application in an interactive fashion. You can use ' .
102 | 'it to run adhoc queries with your models, or experiment ' .
103 | 'and explore the features of CakePHP and your application.' .
104 | "\n\n" .
105 | 'You will need to have psysh installed for this Shell to work.'
106 | );
107 |
108 | return $parser;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Shell/StatsShell.php:
--------------------------------------------------------------------------------
1 | setCommand($this->name)
57 | ->setDescription('Build stats');
58 | }
59 |
60 | public function initialize(): void
61 | {
62 | parent::initialize();
63 | $this->loadModel('Incidents');
64 | $this->loadModel('Reports');
65 | }
66 |
67 | public function execute(Arguments $args, ConsoleIo $io)
68 | {
69 | foreach ($this->Incidents->filterTimes as $filter_string => $filter) {
70 | foreach ($this->Incidents->summarizableFields as $field) {
71 | $io->out('processing ' . $filter_string . ':' . $field);
72 | $entriesWithCount = $this->Reports->
73 | getRelatedByField($field, 25, false, false, $filter['limit']);
74 | $entriesWithCount = json_encode($entriesWithCount);
75 | Cache::write($field . '_' . $filter_string, $entriesWithCount);
76 | }
77 |
78 | $query = [
79 | 'group' => 'grouped_by',
80 | 'order' => 'Incidents.created',
81 | ];
82 | if (isset($filter['limit'])) {
83 | $query['conditions'] = [
84 | 'Incidents.created >=' => $filter['limit'],
85 | ];
86 | }
87 |
88 | $downloadStats = $this->Incidents->find('all', $query);
89 | $downloadStats->select([
90 | 'grouped_by' => $filter['group'],
91 | 'date' => "DATE_FORMAT(Incidents.created, '%a %b %d %Y %T')",
92 | 'count' => $downloadStats->func()->count('*'),
93 | ]);
94 | $downloadStats = json_encode($downloadStats->toArray());
95 | Cache::write('downloadStats_' . $filter_string, $downloadStats);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Shell/SyncGithubIssueStatesShell.php:
--------------------------------------------------------------------------------
1 | setCommand($this->name)
58 | ->setDescription('Sync GitHub issues states');
59 | }
60 |
61 | /**
62 | * @return int
63 | */
64 | public function execute(Arguments $args, ConsoleIo $io)
65 | {
66 | Log::debug(
67 | 'STARTED: Job "'
68 | . 'github/sync_issue_status'
69 | . '" at '
70 | . date('d-m-Y G:i:s (e)'),
71 | ['scope' => 'cron_jobs']
72 | );
73 |
74 | Configure::write('CronDispatcher', true);
75 | if (PHP_SAPI !== 'cli') {
76 | exit;
77 | }
78 |
79 | $session = Session::create();
80 | $session->write('Developer.id', 1);
81 | $request = new ServerRequest([
82 | 'url' => '/github/sync_issue_status',
83 | 'params' => [
84 | 'controller' => 'Github',
85 | 'action' => 'sync_issue_status',
86 | ],
87 | 'session' => $session,
88 | ]);
89 |
90 | $server = new Application('');
91 | $response = $server->handle($request);
92 | if ($response->getStatusCode() === 200) {
93 | Log::debug(
94 | 'FINISHED: Job "'
95 | . 'github/sync_issue_status'
96 | . '" at '
97 | . date('d-m-Y G:i:s (e)'),
98 | ['scope' => 'cron_jobs']
99 | );
100 |
101 | return 0;
102 | }
103 |
104 | Log::error(
105 | 'ERROR: Job "'
106 | . 'github/sync_issue_status'
107 | . '" at '
108 | . date('d-m-Y G:i:s (e)')
109 | . ' response code: ' . $response->getStatusCode(),
110 | ['scope' => 'cron_jobs']
111 | );
112 |
113 | return 1;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/View/AppView.php:
--------------------------------------------------------------------------------
1 | ('
31 | . $entry['count'] . ')';
32 | }
33 |
34 | $fullString = implode(', ', $values);
35 | $remaining = $totalCount - count($values);
36 | if ($remaining) {
37 | $fullString .= ' and ' . $remaining . ' others ';
38 | }
39 |
40 | return $fullString;
41 | }
42 |
43 | /**
44 | * @param mixed $reports The reports
45 | * @return string comma separated list
46 | */
47 | public function createReportsLinks($reports): string
48 | {
49 | $links = [];
50 | foreach ($reports as $report) {
51 | $links[] = $this->linkToReport($report);
52 | }
53 |
54 | return implode(', ', $links);
55 | }
56 |
57 | /**
58 | * @param mixed $report The report
59 | * @return string HTML link
60 | */
61 | public function linkToReport($report): string
62 | {
63 | $reportId = $report['id'];
64 |
65 | return ' #' . $reportId . ' ';
66 | }
67 |
68 | /**
69 | * @param mixed $incident The incident
70 | * @return string HTML link
71 | */
72 | public function linkToReportFromIncident($incident): string
73 | {
74 | $reportId = $incident['report_id'];
75 |
76 | return ' #' . $reportId . ' ';
77 | }
78 |
79 | /**
80 | * @param mixed $incidents The incidents
81 | * @return string HTML
82 | */
83 | public function getStacktracesForIncidents($incidents): string
84 | {
85 | $count = 0;
86 | $html = '';
87 | foreach ($incidents as $incident) {
88 | $class = 'well span5';
89 |
90 | if ($count % 2 === 1) {
91 | $class .= ' ';
92 | } else {
93 | $html .= '
';
94 | }
95 |
96 | $html .= $this->Incidents->getStacktrace($incident, $class);
97 | ++$count;
98 | }
99 |
100 | $html .= '
';
101 |
102 | return $html;
103 | }
104 |
105 | /**
106 | * @return string HTML code
107 | */
108 | public function getChartArray(string $arrayName, array $columns, array $relatedEntries): string
109 | {
110 | $finalData = [];
111 | foreach ($columns as $column) {
112 | $data = [
113 | 'name' => $column,
114 | 'title' => Inflector::humanize($column),
115 | 'labels' => [],
116 | 'values' => [],
117 | ];
118 | foreach ($relatedEntries[$column] as $entry) {
119 | $count = $entry['count'];
120 | $data['labels'][] = $entry[$column] . ' (' . $count . ')';
121 | $data['values'][] = $count;
122 | }
123 |
124 | $finalData[] = $data;
125 | }
126 |
127 | return 'var ' . $arrayName . ' = '
128 | . json_encode(
129 | $finalData,
130 | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
131 | ) . ';';
132 | }
133 |
134 | /**
135 | * @return string HTML
136 | */
137 | public function getLineChartData(string $arrayName, array $entries): string
138 | {
139 | $data = [];
140 | foreach ($entries as $entry) {
141 | $data[] = [$entry['date'], $entry['count']];
142 | }
143 |
144 | return 'var ' . $arrayName . ' = '
145 | . json_encode(
146 | $data,
147 | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
148 | ) . ';';
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/templates/Error/error400.php:
--------------------------------------------------------------------------------
1 | layout = 'dev_error';
7 |
8 | $this->assign('title', $message);
9 | //$this->assign('templateName', 'error400');
10 |
11 | $this->start('file');
12 | ?>
13 | queryString)) : ?>
14 |
15 | SQL Query:
16 | = h($error->queryString) ?>
17 |
18 |
19 | params)) : ?>
20 | SQL Query Params:
21 | = Debugger::dump($error->params) ?>
22 |
23 | = $this->element('auto_table_warning') ?>
24 | end();
31 | }
32 |
33 | ?>
34 | = h($message) ?>
35 |
36 | = __d('cake', 'Error') ?>:
37 | = sprintf(
38 | __d('cake', 'The requested address %s was not found on this server.'),
39 | '' . $url . ' '
40 | ) ?>
41 |
42 |
--------------------------------------------------------------------------------
/templates/Error/error500.php:
--------------------------------------------------------------------------------
1 | layout = 'dev_error';
8 |
9 | $this->assign('title', $message);
10 | $this->assign('templateName', 'error500.php');
11 |
12 | $this->start('file');
13 | ?>
14 | queryString)) : ?>
15 |
16 | SQL Query:
17 | = h($error->queryString) ?>
18 |
19 |
20 | params)) : ?>
21 | SQL Query Params:
22 | = Debugger::dump($error->params) ?>
23 |
24 | element('auto_table_warning');
26 |
27 | if (extension_loaded('xdebug') && stripos((string) ini_get('xdebug.mode'), 'coverage') !== false) {
28 | xdebug_print_function_stack();
29 | }
30 |
31 | $this->end();
32 | }
33 |
34 | ?>
35 | = __d('cake', 'An Internal Error has occurred') ?>
36 |
37 | = __d('cake', 'Error') ?>:
38 | = h($message) ?>
39 |
40 |
--------------------------------------------------------------------------------
/templates/Github/create_issue.php:
--------------------------------------------------------------------------------
1 | =
2 | $this->Form->create(
3 | null,
4 | [
5 | 'label' => ['class' => 'control-label'],
6 | 'div' => ['class' => 'control-group'],
7 | 'class' => 'input-xxlarge',
8 | 'between' => '',
9 | 'after' => '
',
10 | 'class' => 'form-horizontal',
11 | ]
12 | );
13 | ?>
14 |
15 | GitHub Issue
16 | =
17 | $this->Form->input(
18 | 'summary',
19 | [
20 | 'placeholder' => 'Summary',
21 | 'value' => $error_name,
22 | ]
23 | );
24 | ?>
25 | =
26 | $this->Form->input(
27 | 'description',
28 | [
29 | 'placeholder' => 'Description',
30 | 'rows' => 10,
31 | 'value' => $error_message,
32 | ]
33 | );
34 | ?>
35 | = $this->Form->input('labels', ['placeholder' => 'Labels']); ?>
36 |
37 |
38 |
39 |
40 | Heads up!
41 | The link to the error report is automatically added to the end of the description and an extra label is added to denote that the report is from the automated error reporting system
42 |
43 |
44 |
45 | Submit
46 |
47 |
48 |
--------------------------------------------------------------------------------
/templates/Incidents/view.php:
--------------------------------------------------------------------------------
1 | Incident #= $incident['id']; ?>
2 | [Report = $this->Reports->linkToReportFromIncident($incident); ?>]
3 |
4 |
5 |
6 | Error Type
7 |
8 | = $incident['exception_type'] ? 'php' : 'js'; ?>
9 |
10 |
11 |
12 | Error Name
13 |
14 | = $incident['error_name']; ?>
15 |
16 |
17 |
18 | Error Message
19 |
20 | = $incident['error_message']; ?>
21 |
22 |
23 |
24 | Submission Date
25 |
26 | = $incident['created']; ?>
27 |
28 |
29 |
30 | PMA Version
31 |
32 | = $incident['full_report']['pma_version']; ?>
33 |
34 |
35 |
36 | PHP Version
37 |
38 | = $incident['full_report']['php_version']; ?>
39 |
40 |
41 |
42 | Browser
43 |
44 | =
45 | $incident['full_report']['browser_name'] . ' '
46 | . $incident['full_report']['browser_version'];
47 | ?>
48 |
49 |
50 |
51 | Useragent
52 |
53 | = $incident['full_report']['user_agent_string']; ?>
54 |
55 |
56 |
57 | Server Software
58 |
59 | = $incident['full_report']['server_software']; ?>
60 |
61 |
62 |
63 | User OS
64 |
65 | = $incident['user_os']; ?>
66 |
67 |
68 |
69 | Locale
70 |
71 | = $incident['full_report']['locale']; ?>
72 |
73 |
74 |
75 | Script name
76 |
77 | = $incident['script_name']; ?>
78 |
79 |
80 |
81 | URI
82 |
83 |
84 | = 'NA'; ?>
85 |
86 | = $incident['full_report']['exception']['uri']; ?>
87 |
88 |
89 |
90 |
91 | Configuration storage enabled
92 |
93 | = $incident['full_report']['configuration_storage']; ?>
94 |
95 |
96 |
97 |
98 |
99 | Description submited by user:
100 |
101 | = nl2br($incident['steps']); ?>
102 |
103 |
104 |
105 | Stacktrace:
106 | = $this->Incidents->getStacktrace($incident, 'well'); ?>
107 |
108 |
109 | Microhistory:
110 |
111 |
112 | = 'NA'; ?>
113 |
114 | =
115 | json_encode(
116 | $incident['full_report']['microhistory'],
117 | JSON_PRETTY_PRINT
118 | );
119 | ?>
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/templates/Notifications/index.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
= __('Notifications'); ?>
8 |
61 |
62 |
--------------------------------------------------------------------------------
/templates/Pages/home.php:
--------------------------------------------------------------------------------
1 | assign('title', 'Home'); ?>
2 | phpMyAdmin Error Reporting System
3 | This is the error reporting system for phpMyAdmin. Error reports are sent
4 | here where they are collected, stored, tagged and archived. They may also be
5 | siphoned off by the team developers to the bug tracker at github.com
6 | You can view the error reports by logging in with GitHub. For editing the reports, you need to have commit access to the phpmyadmin repo on GitHub.
7 | To validate your status you need to click the login button on top and authorize us to validate your commit access status on GitHub.
8 |
--------------------------------------------------------------------------------
/templates/Reports/index.php:
--------------------------------------------------------------------------------
1 | 'reports',
8 | 'action' => 'data_tables',
9 | ]
10 | );
11 | ?>
12 | Reports
13 |
128 |
--------------------------------------------------------------------------------
/templates/Stats/stats.php:
--------------------------------------------------------------------------------
1 | Stats and Graphs
2 |
3 |
16 |
17 |
18 | There were no incidents reported in this time period
19 |
20 |
21 |
22 |
23 |
87 |
--------------------------------------------------------------------------------
/templates/element/flash/default.php:
--------------------------------------------------------------------------------
1 |
8 | = h($message) ?>
9 |
--------------------------------------------------------------------------------
/templates/element/flash/error.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/templates/element/flash/success.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/templates/email/html/default.php:
--------------------------------------------------------------------------------
1 |
16 | ' . $line . "
\n";
21 | endforeach;
22 |
--------------------------------------------------------------------------------
/templates/email/html/report.php:
--------------------------------------------------------------------------------
1 |
21 |
22 | A new error report has been added on the phpMyAdmin's Error Reporting System.
23 |
24 |
25 | The details of the report are as follows:
26 |
27 |
28 |
29 |
30 | Error Type
31 | = $report['exception_type'] ? 'php' : 'js'; ?>
32 |
33 |
34 | Error Name
35 | = $report['error_name']; ?>
36 |
37 |
38 | Error Message
39 | = $report['error_message']; ?>
40 |
41 |
42 | PMA Versions
43 |
44 | =
45 | $this->Reports->entriesFromIncidents(
46 | $related_entries['pma_version'],
47 | $pma_version_distinct_count,
48 | 'pma_version'
49 | );
50 | ?>
51 |
52 |
53 |
54 | PHP Versions
55 |
56 | =
57 | $this->Reports->entriesFromIncidents(
58 | $related_entries['php_version'],
59 | $php_version_distinct_count,
60 | 'php_version'
61 | );
62 | ?>
63 |
64 |
65 |
66 | Browsers
67 |
68 | =
69 | $this->Reports->entriesFromIncidents(
70 | $related_entries['browser'],
71 | $browser_distinct_count,
72 | 'browser'
73 | );
74 | ?>
75 |
76 |
77 |
78 |
79 | Location
80 | = $report['location']; ?>
81 |
82 |
83 | Line Number
84 | = $report['linenumber']; ?>
85 |
86 |
87 |
88 | Script Name
89 |
90 | =
91 | $this->Reports->entriesFromIncidents(
92 | $related_entries['script_name'],
93 | $script_name_distinct_count,
94 | 'script_name'
95 | );
96 | ?>
97 |
98 |
99 |
100 |
101 | Configuration Storage
102 |
103 | =
104 | $this->Reports->entriesFromIncidents(
105 | $related_entries['configuration_storage'],
106 | $configuration_storage_distinct_count,
107 | 'configuration_storage'
108 | );
109 | ?>
110 |
111 |
112 |
113 | Server Software
114 |
115 | =
116 | $this->Reports->entriesFromIncidents(
117 | $related_entries['server_software'],
118 | $server_software_distinct_count,
119 | 'server_software'
120 | );
121 | ?>
122 |
123 |
124 |
125 | User OS
126 |
127 | =
128 | $this->Reports->entriesFromIncidents(
129 | $related_entries['user_os'],
130 | $user_os_distinct_count,
131 | 'user_os'
132 | );
133 | ?>
134 |
135 |
136 |
137 | Locale
138 |
139 | =
140 | $this->Reports->entriesFromIncidents(
141 | $related_entries['locale'],
142 | $locale_distinct_count,
143 | 'locale'
144 | );
145 | ?>
146 |
147 |
148 |
149 | Incident Count
150 | = count($incidents) . ' incidents of this bug'; ?>
151 |
152 |
153 | Submission Date
154 |
155 | = $report['created']; ?>
156 |
157 |
158 |
159 |
160 |
161 | You can view the detailed report at
162 |
166 | #= $report['id'] ?> .
167 |
168 |
--------------------------------------------------------------------------------
/templates/email/text/default.php:
--------------------------------------------------------------------------------
1 |
16 | = $content;
17 |
--------------------------------------------------------------------------------
/templates/layout/ajax.php:
--------------------------------------------------------------------------------
1 |
16 | = $this->fetch('content');
17 |
--------------------------------------------------------------------------------
/templates/layout/default.php:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 | = $this->Html->charset(); ?>
26 |
27 | = $this->fetch('title'); ?>
28 | phpMyAdmin - Error Reporting Server
29 |
30 |
31 | = $this->Html->meta('icon'); ?>
32 |
33 |
34 | = $this->Html->css($css_files); ?>
35 |
36 |
37 | = $this->Html->script($js_files); ?>
38 |
39 |
40 | =
41 | $this->Html->scriptBlock(
42 | 'var notifications_count = ' . $notif_count . ';',
43 | ['inline' => true]
44 | );
45 | ?>
46 |
47 |
48 |
49 |
101 |
102 |
103 |
104 | = $this->Flash->render(); ?>
105 | = $this->fetch('content'); ?>
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/templates/layout/email/html/default.php:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 | New Report Notification - phpMyAdmin Error Reporting System
22 |
27 |
28 |
29 | fetch('content'); ?>
30 |
31 |
32 | This email was automatically sent by
33 | phpMyAdmin's
34 | Error Reporting System .
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/templates/layout/email/text/default.php:
--------------------------------------------------------------------------------
1 |
17 | fetch('content'); ?>
18 |
19 | This email was sent using the CakePHP Framework, http://cakephp.org.
20 |
--------------------------------------------------------------------------------
/templates/layout/error.php:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 | Html->charset(); ?>
24 |
25 | fetch('title'); ?>
26 | phpMyAdmin - Error Reporting Server - Error
27 |
28 |
29 | Html->meta('icon'); ?>
30 |
31 |
32 | Html->css($css_files);
34 | }
35 |
36 | ?>
37 |
38 |
39 |
40 |
45 |
46 |
47 |
48 | fetch('content'); ?>
49 |
Code:
50 |
Url:
51 |
52 |
53 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/templates/layout/flash.php:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 | Html->charset(); ?>
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/templates/layout/js/default.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/templates/layout/rss/default.php:
--------------------------------------------------------------------------------
1 | fetch('title');
7 | endif;
8 |
9 | echo $this->Rss->document(
10 | $this->Rss->channel(
11 | [],
12 | $channel,
13 | $this->fetch('content')
14 | )
15 | );
16 |
--------------------------------------------------------------------------------
/templates/layout/xml/default.php:
--------------------------------------------------------------------------------
1 | fetch('content');
3 |
--------------------------------------------------------------------------------
/tests/Fixture/DevelopersFixture.php:
--------------------------------------------------------------------------------
1 | 'developers'];
18 |
19 | /**
20 | * Records.
21 | *
22 | * @var array
23 | */
24 | public $records = [
25 | [
26 | 'id' => 1,
27 | 'github_id' => 1,
28 | 'full_name' => 'Lorem ipsum dolor sit amet',
29 | 'email' => 'Lorem ipsum dolor sit amet',
30 | 'gravatar_id' => 'Lorem ipsum dolor sit amet',
31 | 'access_token' => 'Lorem ipsum dolor sit amet',
32 | 'created' => '2013-08-29 22:11:02',
33 | 'modified' => '2013-08-29 22:11:02',
34 | 'has_commit_access' => 1,
35 | ],
36 | [
37 | 'id' => 2,
38 | 'github_id' => 2,
39 | 'full_name' => 'Lorem ipsum dolor sit amet',
40 | 'email' => 'Lorem ipsum dolor sit amet',
41 | 'gravatar_id' => 'Lorem ipsum dolor sit amet',
42 | 'access_token' => 'Lorem ipsum dolor sit amet',
43 | 'created' => '2013-08-29 22:11:02',
44 | 'modified' => '2013-08-29 22:11:02',
45 | 'has_commit_access' => 0,
46 | ],
47 | ];
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Fixture/IncidentsFixture.php:
--------------------------------------------------------------------------------
1 | 'incidents'];
18 |
19 | /**
20 | * Records.
21 | *
22 | * @var array
23 | */
24 | public $records = [
25 | [
26 | 'id' => 1,
27 | 'error_name' => 'Lorem ipsum dolor sit amet',
28 | 'error_message' => 'Lorem ipsum dolor sit amet',
29 | 'pma_version' => 'Lorem ipsum dolor sit amet',
30 | 'php_version' => '5.5',
31 | 'browser' => 'Lorem ipsum dolor sit amet',
32 | 'user_os' => 'Lorem ipsum dolor sit amet',
33 | 'locale' => 'Lorem ipsum dolor sit amet',
34 | 'server_software' => 'Lorem ipsum dolor sit amet',
35 | 'stackhash' => 'hash1',
36 | 'configuration_storage' => 'Lorem ipsum dolor sit amet',
37 | 'script_name' => 'Lorem ipsum dolor sit amet',
38 | 'steps' => 'Lorem ipsum dolor sit amet',
39 | 'stacktrace' => '[{"context": ["test"]}]',
40 | 'full_report' => '{"pma_version": "", "php_version": "","browser_name": ""
41 | , "browser_version": "", "user_agent_string": "", "server_software":
42 | "", "locale": "", "exception":{"uri":""}, "configuration_storage":"",
43 | "microhistory":""}',
44 | 'report_id' => 1,
45 | 'created' => '2013-08-29 18:10:01',
46 | 'modified' => '2013-08-29 18:10:01',
47 | ],
48 | [
49 | 'id' => 2,
50 | 'error_name' => 'Lorem ipsum dolor sit amet',
51 | 'error_message' => 'Lorem ipsum dolor sit amet',
52 | 'pma_version' => 'Lorem ipsum dolor sit amet',
53 | 'php_version' => '5.3',
54 | 'browser' => 'Lorem ipsum dolor sit amet',
55 | 'user_os' => 'Lorem ipsum dolor sit amet',
56 | 'locale' => 'Lorem ipsum dolor sit amet',
57 | 'server_software' => 'Lorem ipsum dolor sit amet',
58 | 'stackhash' => 'hash4',
59 | 'configuration_storage' => 'Lorem ipsum dolor sit amet',
60 | 'script_name' => 'Lorem ipsum dolor sit amet',
61 | 'steps' => 'Lorem ipsum dolor sit amet',
62 | 'stacktrace' => '[{"context": ["test"]}]',
63 | 'full_report' => '{"pma_version": "1.2"}',
64 | 'report_id' => 4,
65 | 'created' => '2013-08-29 18:10:01',
66 | 'modified' => '2013-08-29 18:10:01',
67 | ],
68 | [
69 | 'id' => 3,
70 | 'error_name' => 'Lorem ipsum dolor sit amet',
71 | 'error_message' => 'Lorem ipsum dolor sit amet',
72 | 'pma_version' => 'Lorem ipsum dolor sit amet',
73 | 'php_version' => '5.3',
74 | 'browser' => 'Lorem ipsum dolor sit amet',
75 | 'user_os' => 'Lorem ipsum dolor sit amet',
76 | 'locale' => 'Lorem ipsum dolor sit amet',
77 | 'server_software' => 'Lorem ipsum dolor sit amet',
78 | 'stackhash' => 'hash4',
79 | 'configuration_storage' => 'Lorem ipsum dolor sit amet',
80 | 'script_name' => 'Lorem ipsum dolor sit amet',
81 | 'steps' => null,
82 | 'stacktrace' => '[{"context": ["test"]}]',
83 | 'full_report' => '{"pma_version": "1.2"}',
84 | 'report_id' => 4,
85 | 'created' => '2013-08-29 18:10:00',
86 | 'modified' => '2013-08-29 18:10:00',
87 | ],
88 |
89 | [
90 | 'id' => 4,
91 | 'error_name' => 'Lorem ipsum dolor sit amet',
92 | 'error_message' => 'Lorem ipsum dolor sit amet',
93 | 'pma_version' => 'Lorem ipsum dolor sit amet',
94 | 'php_version' => '5.3',
95 | 'browser' => 'Lorem ipsum dolor sit amet',
96 | 'user_os' => 'Lorem ipsum dolor sit amet',
97 | 'locale' => 'Lorem ipsum dolor sit amet',
98 | 'server_software' => 'Lorem ipsum dolor sit amet',
99 | 'stackhash' => 'hash3',
100 | 'configuration_storage' => 'Lorem ipsum dolor sit amet',
101 | 'script_name' => 'Lorem ipsum dolor sit amet',
102 | 'steps' => null,
103 | 'stacktrace' => '[{"context": ["test"]}]',
104 | 'full_report' => '{"pma_version": "1.2"}',
105 | 'report_id' => 2,
106 | 'created' => '2013-08-29 18:10:00',
107 | 'modified' => '2013-08-29 18:10:00',
108 | ],
109 |
110 | [
111 | 'id' => 5,
112 | 'error_name' => 'Lorem ipsum dolor sit amet',
113 | 'error_message' => 'Lorem ipsum dolor sit amet',
114 | 'pma_version' => 'Lorem ipsum dolor sit amet',
115 | 'php_version' => '5.3',
116 | 'browser' => 'Lorem ipsum dolor sit amet',
117 | 'user_os' => 'Lorem ipsum dolor sit amet',
118 | 'locale' => 'Lorem ipsum dolor sit amet',
119 | 'server_software' => 'Lorem ipsum dolor sit amet',
120 | 'stackhash' => 'hash3',
121 | 'configuration_storage' => 'Lorem ipsum dolor sit amet',
122 | 'script_name' => 'Lorem ipsum dolor sit amet',
123 | 'steps' => null,
124 | 'stacktrace' => '[{"context": ["test"]}]',
125 | 'full_report' => '{"pma_version": "1.2"}',
126 | 'report_id' => 5,
127 | 'created' => '2013-08-29 18:10:00',
128 | 'modified' => '2013-08-29 18:10:00',
129 | ],
130 | ];
131 | }
132 |
--------------------------------------------------------------------------------
/tests/Fixture/NotificationsFixture.php:
--------------------------------------------------------------------------------
1 | 'notifications'];
18 |
19 | /**
20 | * Records.
21 | *
22 | * @var array
23 | */
24 | public $records = [
25 | [
26 | 'id' => 1,
27 | 'developer_id' => 1,
28 | 'report_id' => 1,
29 | 'created' => '2014-01-01 07:05:09',
30 | 'modified' => '2014-01-01 07:05:09',
31 | ],
32 | [
33 | 'id' => 2,
34 | 'developer_id' => 1,
35 | 'report_id' => 4,
36 | 'created' => '2014-01-02 07:05:09',
37 | 'modified' => '2014-01-03 07:05:09',
38 | ],
39 | [
40 | 'id' => 3,
41 | 'developer_id' => 2,
42 | 'report_id' => 4,
43 | 'created' => '2014-07-02 07:05:09',
44 | 'modified' => '2014-07-03 07:05:09',
45 | ],
46 | ];
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Fixture/ReportsFixture.php:
--------------------------------------------------------------------------------
1 | 'reports'];
18 |
19 | /** @var array */
20 | public $records = [
21 | [
22 | 'id' => 1,
23 | 'error_message' => 'Lorem ipsum dolor sit amet',
24 | 'error_name' => 'error2',
25 | 'pma_version' => '4.0',
26 | 'status' => 'forwarded',
27 | 'location' => 'filename_1.php',
28 | 'linenumber' => 1,
29 | 'sourceforge_bug_id' => 1,
30 | 'related_to' => null,
31 | 'created' => '2013-08-28 21:47:17',
32 | 'modified' => '2013-08-28 21:47:17',
33 | ],
34 | [
35 | 'id' => 2,
36 | 'error_message' => 'Lorem ipsum dolor sit amet',
37 | 'error_name' => 'error2',
38 | 'pma_version' => '4.0',
39 | 'status' => 'forwarded',
40 | 'location' => 'filename_2.php',
41 | 'linenumber' => 2,
42 | 'sourceforge_bug_id' => 2,
43 | 'related_to' => null,
44 | 'created' => '2013-08-28 21:47:17',
45 | 'modified' => '2013-08-28 21:47:17',
46 | ],
47 | [
48 | 'id' => 4,
49 | 'error_message' => 'Lorem ipsum dolor sit amet',
50 | 'error_name' => 'error1',
51 | 'pma_version' => '3.8',
52 | 'status' => 'forwarded',
53 | 'location' => 'filename_3.js',
54 | 'linenumber' => 4,
55 | 'sourceforge_bug_id' => 4,
56 | 'related_to' => null,
57 | 'created' => '2013-08-28 21:47:17',
58 | 'modified' => '2013-08-28 21:47:17',
59 | ],
60 | [
61 | 'id' => 5,
62 | 'error_message' => 'Lorem ipsum dolor sit amet',
63 | 'error_name' => 'error1',
64 | 'pma_version' => '3.8',
65 | 'status' => 'new',
66 | 'location' => 'filename_4.js',
67 | 'linenumber' => 3,
68 | 'sourceforge_bug_id' => null,
69 | 'related_to' => null,
70 | 'created' => '2013-08-28 21:47:17',
71 | 'modified' => '2013-08-28 21:47:17',
72 | ],
73 | ];
74 | }
75 |
--------------------------------------------------------------------------------
/tests/Fixture/comment_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 1,
3 | "url": "https://api.github.com/repos/phpmyadmin/Hello-World/issues/comments/1",
4 | "html_url": "https://github.com/pma-bot/Hello-World/issues/1347#issuecomment-1",
5 | "body": "Me too",
6 | "user": {
7 | "login": "pma-bot",
8 | "id": 1,
9 | "avatar_url": "https://github.com/images/error/pma-bot_happy.gif",
10 | "gravatar_id": "",
11 | "url": "https://api.github.com/users/pma-bot",
12 | "html_url": "https://github.com/phpmyadmin",
13 | "followers_url": "https://api.github.com/users/pma-bot/followers",
14 | "following_url": "https://api.github.com/users/pma-bot/following{/other_user}",
15 | "gists_url": "https://api.github.com/users/pma-bot/gists{/gist_id}",
16 | "starred_url": "https://api.github.com/users/pma-bot/starred{/owner}{/repo}",
17 | "subscriptions_url": "https://api.github.com/users/pma-bot/subscriptions",
18 | "organizations_url": "https://api.github.com/users/pma-bot/orgs",
19 | "repos_url": "https://api.github.com/users/pma-bot/repos",
20 | "events_url": "https://api.github.com/users/pma-bot/events{/privacy}",
21 | "received_events_url": "https://api.github.com/users/pma-bot/received_events",
22 | "type": "User",
23 | "site_admin": false
24 | },
25 | "created_at": "2011-04-14T16:00:49Z",
26 | "updated_at": "2011-04-14T16:00:49Z"
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Fixture/empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpmyadmin/error-reporting-server/e3b009546293dd94cdb1711c21bb803944bc5627/tests/Fixture/empty
--------------------------------------------------------------------------------
/tests/Fixture/report_issue_16853_js.json:
--------------------------------------------------------------------------------
1 | {
2 | "pma_version": "5.2.0-dev",
3 | "browser_name": "FIREFOX",
4 | "browser_version": "90.0",
5 | "user_os": "Win",
6 | "server_software": "nginx/1.14.2",
7 | "user_agent_string": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0",
8 | "locale": "en",
9 | "configuration_storage": "disabled",
10 | "php_version": "7.4.14",
11 | "script_name": "index.php",
12 | "exception_type": "js",
13 | "exception": {
14 | "mode": "stack",
15 | "name": "TypeError",
16 | "message": "can't access property \"transaction\", db is null",
17 | "stack": [
18 | {
19 | "func": "DesignerOfflineDB').append(data.message).dialog({"
74 | ],
75 | "uri": "js/dist/designer/move.js?v=5.2.0-dev",
76 | "scriptname": "js/dist/designer/move.js"
77 | },
78 | {
79 | "func": "c",
80 | "line": "2",
81 | "column": "28327",
82 | "context": [
83 | "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
84 | "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
85 | ""
86 | ],
87 | "uri": "js/vendor/jquery/jquery.min.js?v=5.2.0-dev",
88 | "scriptname": "js/vendor/jquery/jquery.min.js"
89 | },
90 | {
91 | "func": "fireWith",
92 | "line": "2",
93 | "column": "29072",
94 | "context": [
95 | "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
96 | "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
97 | ""
98 | ],
99 | "uri": "js/vendor/jquery/jquery.min.js?v=5.2.0-dev",
100 | "scriptname": "js/vendor/jquery/jquery.min.js"
101 | },
102 | {
103 | "func": "l",
104 | "line": "2",
105 | "column": "79901",
106 | "context": [
107 | "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
108 | "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
109 | ""
110 | ],
111 | "uri": "js/vendor/jquery/jquery.min.js?v=5.2.0-dev",
112 | "scriptname": "js/vendor/jquery/jquery.min.js"
113 | },
114 | {
115 | "func": "o/<",
116 | "line": "2",
117 | "column": "82355",
118 | "context": [
119 | "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
120 | "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
121 | ""
122 | ],
123 | "uri": "js/vendor/jquery/jquery.min.js?v=5.2.0-dev",
124 | "scriptname": "js/vendor/jquery/jquery.min.js"
125 | }
126 | ],
127 | "uri": "index.php?route=%2Fdatabase%2Fdesigner"
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/tests/Fixture/report_js.json:
--------------------------------------------------------------------------------
1 | {
2 | "exception": {
3 | "mode": "stack",
4 | "name": "ReferenceError",
5 | "message": "a is not defined",
6 | "stack": [
7 | {
8 | "func": "PMA_exception",
9 | "line": 312,
10 | "column": "5",
11 | "context": [
12 | " }",
13 | "",
14 | "}",
15 | "",
16 | "function PMA_exception() {",
17 | " a()",
18 | "}",
19 | "",
20 | "function exception(){",
21 | " a()",
22 | "}"
23 | ],
24 | "filename": "error.js"
25 | },
26 | {
27 | "func": "new_func",
28 | "line": 257,
29 | "column": "33",
30 | "context": [
31 | " */",
32 | " wrap_function: function(func) {",
33 | " if (!func.wrapped) {",
34 | " var new_func = function(){",
35 | " try {",
36 | " return func.apply(this, arguments)",
37 | " } catch(x) {",
38 | " TraceKit.report(x);",
39 | " }",
40 | " };",
41 | " new_func.wrapped = true;"
42 | ],
43 | "filename": "error_report.js"
44 | }
45 | ],
46 | "useragent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36",
47 | "uri": "tbl_structure.php?target="
48 | },
49 | "steps": "