Skip to content

Commit

Permalink
Added backup restoration support (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
bastien70 authored Sep 13, 2022
1 parent 65e863b commit 391fb57
Show file tree
Hide file tree
Showing 20 changed files with 566 additions and 135 deletions.
17 changes: 7 additions & 10 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,10 @@ on:
jobs:
phpunit:
name: PHPUnit (PHP ${{ matrix.php-version }})
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
env:
SYMFONY_DEPRECATIONS_HELPER: disabled

services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
ports:
- 3307:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

strategy:
matrix:
php-version:
Expand All @@ -45,6 +36,9 @@ jobs:
- name: Install Composer dependencies
uses: ramsey/composer-install@v1

- name: Start mariadb
run: docker-compose -f docker-compose.test.yaml up -d mariadb

- name: Start minio
run: docker-compose -f docker-compose.test.yaml up -d minio createbuckets

Expand All @@ -69,5 +63,8 @@ jobs:
- name: Stop minio
run: docker-compose -f docker-compose.test.yaml stop minio

- name: Stop mariadb
run: docker-compose -f docker-compose.test.yaml stop mariadb

- name: Upload to Codecov
uses: codecov/codecov-action@v2
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ To access your databases backups, click the `Backups` tab.

![Backup list](docs/images/backup-list.png?raw=true)

You will be able to download or delete a backup.
You will be able to download, restore or delete a backup.

## Update the application <a name="update-app"></a>

Expand Down
3 changes: 2 additions & 1 deletion composer.lock

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

9 changes: 8 additions & 1 deletion config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@ services:
- '../src/Kernel.php'

# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
# please note that last definitions always *replace* previous ones

when@test:
services:
App\Tests\Fixtures\DataProvider:
public: true
autowire: true
autoconfigure: true
7 changes: 7 additions & 0 deletions docker-compose.test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ services:
- '3307:3306'
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test_db
volumes:
- ./src/Faker/Provider/fixture.sql:/docker-entrypoint-initdb.d/fixture.sql
- db_data:/var/lib/mysql
minio:
image: minio/minio
environment:
Expand All @@ -30,3 +34,6 @@ services:
/usr/bin/mc policy set public myminio/somebucketname;
exit 0;
"
volumes:
db_data:
31 changes: 31 additions & 0 deletions migrations/Version20220902073138.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20220902073138 extends AbstractMigration
{
public function getDescription(): string
{
return 'Change database options';
}

public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE `database` CHANGE options_reset_auto_increment options_reset_auto_increment TINYINT(1) NOT NULL, CHANGE options_add_drop_database options_add_drop_database TINYINT(1) NOT NULL, CHANGE options_add_drop_table options_add_drop_table TINYINT(1) NOT NULL, CHANGE options_add_drop_trigger options_add_drop_trigger TINYINT(1) NOT NULL, CHANGE options_add_locks options_add_locks TINYINT(1) NOT NULL, CHANGE options_complete_insert options_complete_insert TINYINT(1) NOT NULL');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE `database` CHANGE options_reset_auto_increment options_reset_auto_increment TINYINT(1) DEFAULT 0 NOT NULL, CHANGE options_add_drop_database options_add_drop_database TINYINT(1) DEFAULT 0 NOT NULL, CHANGE options_add_drop_table options_add_drop_table TINYINT(1) DEFAULT 0 NOT NULL, CHANGE options_add_drop_trigger options_add_drop_trigger TINYINT(1) DEFAULT 1 NOT NULL, CHANGE options_add_locks options_add_locks TINYINT(1) DEFAULT 1 NOT NULL, CHANGE options_complete_insert options_complete_insert TINYINT(1) DEFAULT 0 NOT NULL');
}

public function isTransactional(): bool
{
return false;
}
}
6 changes: 3 additions & 3 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ parameters:
-
message: "#^Call to an undefined method App\\\\Entity\\\\AdapterConfig\\:\\:setS3BucketName\\(\\)\\.$#"
count: 2
path: tests/Helper/FlysystemHelperTest.php
path: tests/Fixtures/DataProvider.php

-
message: "#^Method App\\\\Tests\\\\Helper\\\\FlysystemHelperTest\\:\\:getLocalS3Adapter\\(\\)\\ should return App\\\\Entity\\\\LocalAdapter but returns App\\\\Entity\\\\AdapterConfig.$#"
message: "#^Method App\\\\Tests\\\\Fixtures\\\\DataProvider\\:\\:getLocalS3Adapter\\(\\)\\ should return App\\\\Entity\\\\LocalAdapter but returns App\\\\Entity\\\\AdapterConfig.$#"
count: 1
path: tests/Helper/FlysystemHelperTest.php
path: tests/Fixtures/DataProvider.php
12 changes: 12 additions & 0 deletions public/assets/js/confirm-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
document.addEventListener("DOMContentLoaded",(
function() {
document.querySelectorAll(".confirm-action").forEach((function(e){
e.addEventListener("click",(function(t){
t.preventDefault();
document.querySelector("#modal-confirm-button").addEventListener("click",(function(){
location.replace(e.getAttribute("href"));
}));
}));
}));
}
));
41 changes: 41 additions & 0 deletions src/Controller/Admin/BackupCrudController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
use App\Entity\Backup;
use App\Entity\User;
use App\Helper\FlysystemHelper;
use App\Service\BackupService;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
Expand All @@ -28,7 +30,9 @@
use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;
use EasyCorp\Bundle\EasyAdminBundle\Filter\TextFilter;
use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
Expand All @@ -39,6 +43,8 @@ final class BackupCrudController extends AbstractCrudController
public function __construct(
private readonly TranslatorInterface $translator,
private readonly FlysystemHelper $flysystemHelper,
private readonly BackupService $backupService,
private readonly AdminUrlGenerator $adminUrlGenerator,
) {
}

Expand Down Expand Up @@ -75,6 +81,25 @@ public function downloadBackupAction(AdminContext $context): Response
return $this->flysystemHelper->download($backup);
}

public function importBackupAction(AdminContext $context): Response
{
/** @var Backup $backup */
$backup = $context->getEntity()->getInstance();

try {
$this->backupService->import($backup);
$this->addFlash('success', new TranslatableMessage('backup.action.import.flash_success'));
} catch (\RuntimeException $e) {
$this->addFlash('danger', new TranslatableMessage('backup.action.import.flash_error', ['%message%' => $e->getMessage()]));
}

$url = $this->adminUrlGenerator->setController(self::class)
->setAction(Action::INDEX)
->generateUrl();

return $this->redirect($url);
}

/**
* @param Backup $entityInstance
*/
Expand All @@ -89,8 +114,17 @@ public function configureActions(Actions $actions): Actions
$downloadBackupAction = Action::new('downloadBackup', 'backup.action.download')
->linkToCrudAction('downloadBackupAction');

$importBackupAction = Action::new('importBackup', 'backup.action.import.title')
->linkToCrudAction('importBackupAction')
->addCssClass('confirm-action')
->setHtmlAttributes([
'data-bs-toggle' => 'modal',
'data-bs-target' => '#modal-confirm',
]);

return $actions
->add(Crud::PAGE_INDEX, $downloadBackupAction)
->add(Crud::PAGE_INDEX, $importBackupAction)
->remove(Crud::PAGE_INDEX, Action::NEW)
->remove(Crud::PAGE_INDEX, Action::EDIT)
->disable(Action::NEW, Action::EDIT)
Expand All @@ -106,6 +140,13 @@ public function configureCrud(Crud $crud): Crud
;
}

public function configureAssets(Assets $assets): Assets
{
$assets->addJsFile('assets/js/confirm-modal.js');

return parent::configureAssets($assets);
}

public function configureFields(string $pageName): iterable
{
yield DateTimeField::new('createdAt', 'backup.field.created_at')
Expand Down
5 changes: 5 additions & 0 deletions src/Factory/DatabaseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Entity\Database;
use App\Entity\Embed\BackupTask;
use App\Entity\Embed\Options;
use App\Entity\Enum\BackupTaskPeriodicity;
use App\Entity\User;
use App\Repository\DatabaseRepository;
Expand Down Expand Up @@ -81,6 +82,10 @@ protected function getDefaults(): array
'startFrom' => new \DateTime('-1 day'),
'nextIteration' => new \DateTime('-1 day'),
]),
'options' => AnonymousFactory::new(Options::class)->create([
'addDropTable' => true,
'addDropDatabase' => true,
]),
];
}

Expand Down
Loading

0 comments on commit 391fb57

Please sign in to comment.