Skip to content

Commit 308217a

Browse files
committed
Fixed bug when query is empty. Added tests for DownloadLogService.
1 parent bbb6750 commit 308217a

File tree

4 files changed

+320
-16
lines changed

4 files changed

+320
-16
lines changed

plugins/wpgraphql-logging/src/Admin/View/Download/DownloadLogService.php

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
namespace WPGraphQL\Logging\Admin\View\Download;
66

77
use League\Csv\Writer;
8+
use WPGraphQL\Logging\Logger\Database\DatabaseEntity;
89
use WPGraphQL\Logging\Logger\Database\LogsRepository;
10+
use WPGraphQL\Logging\Logger\LoggerService;
911

1012
/**
1113
* Service for handling log downloads.
@@ -49,6 +51,22 @@ public function generate_csv( int $log_id ): void {
4951
}
5052
$writer = Writer::createFromStream( $output );
5153

54+
$headers = $this->get_headers( $log );
55+
$content = $this->get_content( $log );
56+
$writer->insertOne( $headers );
57+
$writer->insertOne( $content );
58+
fclose( $output );
59+
exit;
60+
}
61+
62+
/**
63+
* Get default CSV headers.
64+
*
65+
* @param DatabaseEntity $log The log entry.
66+
*
67+
* @return array The default CSV headers.
68+
*/
69+
public function get_headers(DatabaseEntity $log): array {
5270
$headers = [
5371
'ID',
5472
'Date',
@@ -60,25 +78,28 @@ public function generate_csv( int $log_id ): void {
6078
'Context',
6179
'Extra',
6280
];
81+
return apply_filters( 'wpgraphql_logging_csv_headers', $headers, $log->get_id(), $log );
82+
}
6383

84+
/**
85+
* Get CSV content for a log entry.
86+
*
87+
* @param DatabaseEntity $log The log entry.
88+
*
89+
* @return array The CSV content for the log entry.
90+
*/
91+
public function get_content(DatabaseEntity $log): array {
6492
$content = [
65-
$log->get_id(),
66-
$log->get_datetime(),
67-
$log->get_level(),
68-
$log->get_level_name(),
69-
$log->get_message(),
70-
$log->get_channel(),
71-
$log->get_query(),
93+
$log->get_id() ?? '',
94+
$log->get_datetime() ?? '',
95+
$log->get_level() ?? '',
96+
$log->get_level_name() ?? '',
97+
$log->get_message() ?? '',
98+
$log->get_channel() ?? '',
99+
$log->get_query() ?? '',
72100
wp_json_encode( $log->get_context() ),
73101
wp_json_encode( $log->get_extra() ),
74102
];
75-
76-
77-
$headers = apply_filters( 'wpgraphql_logging_csv_headers', $headers, $log_id, $log );
78-
$content = apply_filters( 'wpgraphql_logging_csv_content', $content, $log_id, $log );
79-
$writer->insertOne( $headers );
80-
$writer->insertOne( $content );
81-
fclose( $output );
82-
exit;
103+
return apply_filters( 'wpgraphql_logging_csv_content', $content, $log->get_id(), $log );
83104
}
84105
}

plugins/wpgraphql-logging/src/Admin/ViewLogsPage.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ public function enqueue_admin_scripts( string $hook_suffix ): void {
130130
'jquery-ui-timepicker-addon',
131131
'jQuery(document).ready(function($){ $(".wpgraphql-logging-datepicker").datetimepicker({ dateFormat: "yy-mm-dd", timeFormat: "HH:mm:ss" }); });'
132132
);
133+
134+
// Allow other plugins to enqueue their own scripts/styles.
135+
do_action( 'wpgraphql_logging_view_logs_admin_enqueue_scripts', $hook_suffix );
133136
}
134137

135138
/**

plugins/wpgraphql-logging/src/Logger/Database/DatabaseEntity.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,10 @@ public function get_query(): ?string {
250250
return null;
251251
}
252252

253-
$query = $context['query'];
253+
$query = $context['query'] ?? null;
254+
if ( is_string( $query ) ) {
255+
return $query;
256+
}
254257

255258
$request = $context['request'] ?? null;
256259
if ( empty( $request ) || ! is_array( $request ) ) {
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WPGraphQL\Logging\wpunit\Admin\View\Download;
6+
7+
use lucatume\WPBrowser\TestCase\WPTestCase;
8+
use WPGraphQL\Logging\Admin\View\Download\DownloadLogService;
9+
use WPGraphQL\Logging\Logger\Database\LogsRepository;
10+
use WPGraphQL\Logging\Logger\Database\DatabaseEntity;
11+
12+
13+
14+
/**
15+
* Test class for DownloadLogService.
16+
*
17+
* @package WPGraphQL\Logging
18+
*
19+
* @since 0.0.1
20+
*/
21+
class DownloadLogServiceTest extends WPTestCase {
22+
23+
private DownloadLogService $service;
24+
private LogsRepository $repository;
25+
26+
27+
protected array $fixture = [
28+
'channel' => 'wpgraphql_logging',
29+
'level' => 200,
30+
'level_name' => 'INFO',
31+
'message' => 'WPGraphQL Outgoing Response',
32+
'context' => [
33+
'site_url' => 'http://test.local',
34+
'wp_version' => '6.8.2',
35+
'wp_debug_mode' => true,
36+
'plugin_version'=> '0.0.1'
37+
],
38+
'extra' => [
39+
'ip' => '127.0.0.1',
40+
'url' => '/index.php?graphql',
41+
'server' => 'test.local',
42+
'referrer' => 'http://test.local/wp-admin/admin.php?page=graphiql-ide',
43+
'process_id' => 5819,
44+
'http_method' => 'POST',
45+
'memory_usage' => '14 MB',
46+
'wpgraphql_query' => 'query GetPost($uri: ID!) { post(id: $uri, idType: URI) { title content } }',
47+
'memory_peak_usage' => '14 MB',
48+
'wpgraphql_variables' => [
49+
'uri' => 'hello-world'
50+
],
51+
'wpgraphql_operation_name' => 'GetPost'
52+
]
53+
];
54+
55+
56+
public function setUp(): void {
57+
parent::setUp();
58+
$this->service = new DownloadLogService();
59+
$this->repository = new LogsRepository();
60+
}
61+
62+
public function tearDown(): void {
63+
$this->repository->delete_all();
64+
parent::tearDown();
65+
}
66+
67+
public function set_as_admin(): void {
68+
$admin_user = $this->factory->user->create(['role' => 'administrator']);
69+
wp_set_current_user($admin_user);
70+
set_current_screen('dashboard');
71+
}
72+
73+
public function test_generate_csv_requires_admin_capabilities(): void {
74+
// Test without admin capabilities
75+
wp_set_current_user(0);
76+
77+
$this->expectException(\WPDieException::class);
78+
$this->expectExceptionMessage('You do not have sufficient permissions to access this page.');
79+
80+
$this->service->generate_csv(1);
81+
}
82+
83+
public function test_generate_csv_requires_valid_log_id_not_zero(): void {
84+
$this->set_as_admin();
85+
86+
$this->expectException(\WPDieException::class);
87+
$this->expectExceptionMessage('Invalid log ID.');
88+
89+
$this->service->generate_csv(0);
90+
}
91+
92+
public function test_generate_csv_requires_valid_log_id_in_database(): void {
93+
$this->set_as_admin();
94+
95+
$this->expectException(\WPDieException::class);
96+
$this->expectExceptionMessage('Log not found.');
97+
98+
$this->service->generate_csv(9999999);
99+
}
100+
101+
public function test_generate_csv_returns_valid_csv(): void {
102+
$this->set_as_admin();
103+
$entity = DatabaseEntity::create(...array_values($this->fixture));
104+
$log_id = $entity->save();
105+
106+
107+
$headers = $this->service->get_headers($entity);
108+
$content = $this->service->get_content($entity);
109+
110+
$this->assertSame([
111+
'ID',
112+
'Date',
113+
'Level',
114+
'Level Name',
115+
'Message',
116+
'Channel',
117+
'Query',
118+
'Context',
119+
'Extra',
120+
], $headers);
121+
122+
$this->assertIsArray($content);
123+
$this->assertCount(9, $content);
124+
$this->assertEquals($log_id, $content[0]);
125+
$this->assertEquals($this->fixture['level'], $content[2]);
126+
$this->assertEquals($this->fixture['level_name'], $content[3]);
127+
$this->assertEquals($this->fixture['message'], $content[4]);
128+
$this->assertEquals($this->fixture['channel'], $content[5]);
129+
$this->assertEquals(wp_json_encode($this->fixture['context']), $content[7]);
130+
$this->assertEquals(wp_json_encode($this->fixture['extra']), $content[8]);
131+
132+
133+
// Capture output
134+
// ob_start();
135+
// $this->service->generate_csv($log_id);
136+
// $output = ob_get_clean();
137+
138+
// // // Parse CSV output
139+
// $lines = explode("\n", trim($output));
140+
// $headers = str_getcsv($lines[0]);
141+
// $content = str_getcsv($lines[1]);
142+
143+
// // Verify headers
144+
// $expected_headers = [
145+
// 'ID',
146+
// 'Date',
147+
// 'Level',
148+
// 'Level Name',
149+
// 'Message',
150+
// 'Channel',
151+
// 'Query',
152+
// 'Context',
153+
// 'Extra',
154+
// ];
155+
// $this->assertEquals($expected_headers, $headers);
156+
157+
// // Verify content
158+
// $this->assertEquals($log_id, $content[0]);
159+
// $this->assertEquals('2023-01-01 12:00:00', $content[1]);
160+
// $this->assertEquals('200', $content[2]);
161+
// $this->assertEquals('INFO', $content[3]);
162+
// $this->assertEquals('Test log message', $content[4]);
163+
// $this->assertEquals('wpgraphql', $content[5]);
164+
// $this->assertEquals('query { posts { nodes { id title } } }', $content[6]);
165+
// $this->assertEquals('{"user_id":1}', $content[7]);
166+
// $this->assertEquals('{"test":"data"}', $content[8]);
167+
// }
168+
169+
// public function test_generate_csv_with_nonexistent_log(): void {
170+
// // Set admin user
171+
// $admin_user = $this->factory->user->create(['role' => 'administrator']);
172+
// wp_set_current_user($admin_user);
173+
// set_current_screen('dashboard');
174+
175+
// $this->expectOutputString('');
176+
177+
// ob_start();
178+
// $this->service->generate_csv(999999);
179+
// $output = ob_get_clean();
180+
181+
// $this->assertEmpty($output);
182+
}
183+
184+
// public function test_csv_filename_filter(): void {
185+
// // Set admin user
186+
// $admin_user = $this->factory->user->create(['role' => 'administrator']);
187+
// wp_set_current_user($admin_user);
188+
// set_current_screen('dashboard');
189+
190+
// // Create test log entry
191+
// global $wpdb;
192+
// $wpdb->insert(
193+
// $wpdb->prefix . 'wpgraphql_logs',
194+
// [
195+
// 'level' => 200,
196+
// 'level_name' => 'INFO',
197+
// 'message' => 'Test message',
198+
// 'channel' => 'wpgraphql',
199+
// 'datetime' => '2023-01-01 12:00:00',
200+
// 'context' => '{}',
201+
// 'extra' => '{}',
202+
// 'query' => 'test query'
203+
// ]
204+
// );
205+
// $log_id = $wpdb->insert_id;
206+
207+
// // Add filter for filename
208+
// add_filter('wpgraphql_logging_csv_filename', function($filename) {
209+
// return 'custom_log_export.csv';
210+
// });
211+
212+
// // Check headers contain custom filename
213+
// ob_start();
214+
// $this->service->generate_csv($log_id);
215+
// $output = ob_get_contents();
216+
// ob_end_clean();
217+
218+
// $headers = headers_list();
219+
// $content_disposition_found = false;
220+
// foreach ($headers as $header) {
221+
// if (strpos($header, 'Content-Disposition') !== false && strpos($header, 'custom_log_export.csv') !== false) {
222+
// $content_disposition_found = true;
223+
// break;
224+
// }
225+
// }
226+
227+
// $this->assertTrue($content_disposition_found);
228+
// }
229+
230+
// public function test_csv_headers_filter(): void {
231+
// // Set admin user
232+
// $admin_user = $this->factory->user->create(['role' => 'administrator']);
233+
// wp_set_current_user($admin_user);
234+
// set_current_screen('dashboard');
235+
236+
// // Create test log entry
237+
// global $wpdb;
238+
// $wpdb->insert(
239+
// $wpdb->prefix . 'wpgraphql_logs',
240+
// [
241+
// 'level' => 200,
242+
// 'level_name' => 'INFO',
243+
// 'message' => 'Test message',
244+
// 'channel' => 'wpgraphql',
245+
// 'datetime' => '2023-01-01 12:00:00',
246+
// 'context' => '{}',
247+
// 'extra' => '{}',
248+
// 'query' => 'test query'
249+
// ]
250+
// );
251+
// $log_id = $wpdb->insert_id;
252+
253+
// // Add filter for headers
254+
// add_filter('wpgraphql_logging_csv_headers', function($headers) {
255+
// return array_merge($headers, ['Custom Field']);
256+
// });
257+
258+
// // Add filter for content
259+
// add_filter('wpgraphql_logging_csv_content', function($content) {
260+
// return array_merge($content, ['Custom Value']);
261+
// });
262+
263+
// ob_start();
264+
// $this->service->generate_csv($log_id);
265+
// $output = ob_get_contents();
266+
// ob_end_clean();
267+
268+
// // Parse CSV output
269+
// $lines = explode("\n", trim($output));
270+
// $headers = str_getcsv($lines[0]);
271+
// $content = str_getcsv($lines[1]);
272+
273+
// // Verify custom header and content
274+
// $this->assertContains('Custom Field', $headers);
275+
// $this->assertContains('Custom Value', $content);
276+
// }
277+
}

0 commit comments

Comments
 (0)