-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Produce summary data to feed back into --table option and clean up #13
Closed
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
<a href="https://github.com/catalyst/moodle-tool_advancedreplace/actions/workflows/ci.yml?query=branch%3AMOODLE_401_STABLE"> | ||
<img src="https://github.com/catalyst/moodle-tool_advancedreplace/workflows/ci/badge.svg?branch=MOODLE_401_STABLE"> | ||
</a> | ||
|
||
|
||
# moodle-tool_advancedreplace | ||
|
||
This is a Moodle plugin that allows administrators to search and replace strings in the Moodle database. | ||
|
@@ -8,18 +13,38 @@ They can use simple text search or regular expressions. | |
## GDPR | ||
The plugin does not store any personal data. | ||
|
||
## Branches | ||
|
||
| Moodle version | Branch | PHP | | ||
|-------------------|--------------------|-----------| | ||
| Moodle 4.1+ | `main` | 7.4+ | | ||
|
||
## Installation | ||
|
||
1. Install the plugin the same as any standard Moodle plugin, you can use | ||
git to clone it into your source: | ||
|
||
```sh | ||
git clone [email protected]:catalyst/moodle-tool_advancedreplace.git admin/tool/advancedreplace | ||
|
||
## Examples | ||
- Find all occurrences of "http://example.com/" followed by any number of digits on tables: | ||
|
||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/\d+"` | ||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/\d+" --output=/tmp/result.csv` | ||
- Find all occurrences of "http://example.com/" on a table: | ||
|
||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/" --tables=page` | ||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/\d+" --tables=page --output=/tmp/result.csv` | ||
|
||
- Find all occurrences of "http://example.com/" on multiple tables: | ||
|
||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/" --tables=page,forum` | ||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/\d+" --tables=page,forum --output=/tmp/result.csv` | ||
|
||
- Find all occurrences of "http://example.com/" on different tables and columns: | ||
|
||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/\d+" --tables=page:content,forum:message --output=/tmp/result.csv` | ||
- Find all occurrences of "http://example.com/" on all tables except the ones specified: | ||
|
||
- Replace all occurrences of "http://example.com/" on different tables and columns: | ||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/\d+" --skip-tables=page,forum --output=/tmp/result.csv` | ||
- Find all occurrences of "http://example.com/" on all columns except the ones specified: | ||
|
||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/" --tables=page:content,forum:message` | ||
`php admin/tool/advancedreplace/cli/find.php --regex-match="http://example.com/\d+" --tables=page --skip-columns=intro,display --output=/tmp/result.csv` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -116,8 +116,6 @@ | |
// Show header. | ||
if (!$options['summary']) { | ||
fputcsv($fp, ['table', 'column', 'courseid', 'shortname', 'id', 'match']); | ||
} else { | ||
fputcsv($fp, ['table', 'column']); | ||
} | ||
|
||
// Perform the search. | ||
|
@@ -146,5 +144,20 @@ | |
} | ||
|
||
$progress->update_full(100, "Finished searching into $output"); | ||
|
||
fclose($fp); | ||
|
||
if ($summary) { | ||
// Read the content of the output file. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this all looks weird to me, whats the reason for this? we really don't want to touch the file a second time and we definitely don't want to load it all into memory at once |
||
$filecontent = file_get_contents($output); | ||
// Replace new line with comma. | ||
$filecontent = str_replace("\n", ',', $filecontent); | ||
// Remove the last comma. | ||
$filecontent = substr($filecontent, 0, -1); | ||
// Add a new line at the end. | ||
$filecontent .= "\n"; | ||
// Write the content back to the file. | ||
file_put_contents($output, $filecontent); | ||
} | ||
|
||
exit(0); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
<?php | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
namespace tool_advancedreplace; | ||
|
||
/** | ||
* Helper test. | ||
* | ||
* @package tool_advancedreplace | ||
* @copyright 2024 Catalyst IT Australia Pty Ltd | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
final class helper_test extends \advanced_testcase { | ||
/** | ||
* Data provider for test_build_searching_list. | ||
* | ||
* @return array | ||
*/ | ||
public static function build_searching_list_provider(): array { | ||
return [ | ||
[ | ||
'', '', '', '', | ||
// Should include these tables/columns. | ||
[ | ||
'page' => 'content, intro', | ||
'assign' => 'intro, name', | ||
], | ||
// Should not include these tables/columns. | ||
[ | ||
'page' => 'id, introformat, timecreated, timemodified, timelimit', | ||
'assign' => 'id, introformat, course', | ||
'config' => '', | ||
'logstore_standard_log' => '', | ||
], | ||
], | ||
[ | ||
'page', '', '', '', | ||
[ | ||
'page' => 'content, intro', | ||
], | ||
[ | ||
'assign' => '', | ||
], | ||
], | ||
[ | ||
'page:content,assign:intro', '', '', '', | ||
[ | ||
'page' => 'content', | ||
'assign' => 'intro', | ||
], | ||
[ | ||
'page' => 'intro', | ||
'assign' => 'name', | ||
], | ||
], | ||
[ | ||
'', 'assign', '', '', | ||
[ | ||
'page' => '', | ||
], | ||
[ | ||
'assign' => '', | ||
], | ||
], | ||
[ | ||
'', 'assign', 'content', '', | ||
[ | ||
'page' => '', | ||
], | ||
[ | ||
'assign' => '', | ||
'page:content' => '', | ||
], | ||
], | ||
|
||
]; | ||
} | ||
|
||
/** | ||
* Test build_searching_list. | ||
* | ||
* @dataProvider build_searching_list_provider | ||
* @covers \tool_advancedreplace\helper::build_searching_list | ||
* | ||
* @param string $tables the tables to search | ||
* @param string $skiptables the tables to skip | ||
* @param string $skipcolumns the columns to skip | ||
* @param string $searchstring the search string | ||
* @param array $expectedlist the tables/columns which should be in the result | ||
* @param array $unexpectedlist the tables/columns which should not be in the result | ||
* | ||
* return void | ||
*/ | ||
public function test_build_searching_list(string $tables, string $skiptables, string $skipcolumns , string $searchstring, | ||
array $expectedlist, array $unexpectedlist): void { | ||
$this->resetAfterTest(); | ||
[$count, $searchlist] = helper::build_searching_list($tables, $skiptables, $skipcolumns, $searchstring); | ||
|
||
// Columns should be in the result. | ||
foreach ($expectedlist as $table => $columns) { | ||
// Make sure the table is in the result. | ||
$this->assertArrayHasKey($table, $searchlist); | ||
|
||
// Get the name of the columns that we are going to search. | ||
$searchcolumns = array_map(function ($column) { | ||
return $column->name; | ||
}, $searchlist[$table]); | ||
|
||
if (empty($columns)) { | ||
continue; | ||
} | ||
|
||
// Each column should be in the search list. | ||
$columns = explode(',', $columns); | ||
foreach ($columns as $column) { | ||
// Get all columns in the table. | ||
$this->assertContains(trim($column), $searchcolumns); | ||
} | ||
} | ||
|
||
// Columns should not be in the result. | ||
foreach ($unexpectedlist as $table => $columns) { | ||
if (!empty($columns)) { | ||
// Specific columns of this table should not be in the result. | ||
$this->assertArrayHasKey($table, $searchlist); | ||
$columns = explode(',', $columns); | ||
foreach ($columns as $column) { | ||
$this->assertNotContains(trim($column), $searchlist[$table]); | ||
} | ||
} else { | ||
// The table should not be in the result. | ||
$this->assertArrayNotHasKey($table, $searchlist); | ||
} | ||
|
||
} | ||
} | ||
|
||
/** | ||
* Plain text search. | ||
* | ||
* @covers \tool_advancedreplace\helper::plain_text_search | ||
*/ | ||
public function test_plain_text_search(): void { | ||
$this->resetAfterTest(); | ||
|
||
$searchstring = 'https://example.com.au'; | ||
|
||
// Create a course. | ||
$course = $this->getDataGenerator()->create_course(); | ||
|
||
// Create a page content. | ||
$this->getDataGenerator()->create_module('page', (object) [ | ||
'course' => $course, | ||
'content' => 'This is a page content with a link to https://example.com.au', | ||
'contentformat' => FORMAT_HTML, | ||
]); | ||
|
||
// Create an assignment. | ||
$this->getDataGenerator()->create_module('assign', (object)[ | ||
'course' => $course->id, | ||
'name' => 'Test!', | ||
'intro' => 'This is an assignment with a link to https://example.com.au/5678', | ||
'introformat' => FORMAT_HTML, | ||
]); | ||
|
||
[$count, $searchlist] = helper::build_searching_list('page,assign'); | ||
$result = []; | ||
foreach ($searchlist as $table => $columns) { | ||
foreach ($columns as $column) { | ||
$result = array_merge($result, helper::plain_text_search($searchstring, $table, $column)); | ||
} | ||
} | ||
$this->assertNotNull($result['page']['content']); | ||
$this->assertNotNull($result['assign']['intro']); | ||
} | ||
|
||
/** | ||
* Regular expression search. | ||
* | ||
* @covers \tool_advancedreplace\helper::regular_expression_search | ||
*/ | ||
public function test_regular_expression_search(): void { | ||
$this->resetAfterTest(); | ||
|
||
$searchstring = "https://example.com.au/\d+"; | ||
|
||
// Create a course. | ||
$course = $this->getDataGenerator()->create_course(); | ||
// Create a page content. | ||
$this->getDataGenerator()->create_module('page', (object)[ | ||
'course' => $course, | ||
'content' => 'This is a page content with a link to https://example.com.au/1234', | ||
'contentformat' => FORMAT_HTML, | ||
]); | ||
// Create an assignment. | ||
$this->getDataGenerator()->create_module('assign', (object)[ | ||
'course' => $course->id, | ||
'name' => 'Test!', | ||
'intro' => 'This is an assignment with a link to https://example.com.au/5678', | ||
'introformat' => FORMAT_HTML, | ||
]); | ||
|
||
[$count, $searchlist] = helper::build_searching_list('page,assign'); | ||
$result = []; | ||
foreach ($searchlist as $table => $columns) { | ||
foreach ($columns as $column) { | ||
$result = array_merge($result, helper::regular_expression_search($searchstring, $table, $column)); | ||
} | ||
} | ||
|
||
// Replace "/" with "\/", as it is used as delimiters. | ||
$searchstring = str_replace('/', '\\/', $searchstring); | ||
|
||
// Add delimiters to the search string. | ||
$searchstring = '/' . $searchstring . '/'; | ||
|
||
// Check if page content matches the search string. | ||
$pagecontent = $result['page']['content']; | ||
$this->assertMatchesRegularExpression($searchstring, $pagecontent->current()->content); | ||
|
||
// Check if assignment intro matches the search string. | ||
$assignintro = $result['assign']['intro']; | ||
$this->assertMatchesRegularExpression($searchstring, $assignintro->current()->intro); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why did you combine these?