From 9eccd26f1435fd719fd68e9fa4f4d8a9ef2157f7 Mon Sep 17 00:00:00 2001 From: Monaye Win <> Date: Fri, 4 Dec 2020 14:00:24 -0800 Subject: [PATCH 01/17] allow dynamically set the import based on the requester --- src/Http/Controllers/ImportController.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index ab72445..3f7bc4d 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -39,7 +39,7 @@ public function preview(NovaRequest $request, $file) $resources = collect(Nova::$resources); - $resources = $resources->filter(function ($resource) { + $resources = $resources->filter(function ($resource) use ($request) { if ($resource === ActionResource::class) { return false; } @@ -47,8 +47,14 @@ public function preview(NovaRequest $request, $file) if (!isset($resource::$model)) { return false; } + + $resourceReflection = (new \ReflectionClass((string) $resource)); - $static_vars = (new \ReflectionClass((string) $resource))->getStaticProperties(); + $static_vars = $resourceReflection->getStaticProperties(); + + if($resourceReflection->hasMethod('canImportWithCSV')) { + return $resource::canImportWithCSV($request); + } if(!isset($static_vars['canImportResource'])) { return true; From 4f7e671063514a88feb10f8ac3e1e3fa90aeb730 Mon Sep 17 00:00:00 2001 From: Monaye Win <> Date: Fri, 4 Dec 2020 14:14:33 -0800 Subject: [PATCH 02/17] rename method to match with static value. added documentation --- README.md | 17 +++++++++++++++++ src/Http/Controllers/ImportController.php | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0d5c263..53588c1 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,23 @@ class NovaServiceProvider extends NovaApplicationServiceProvider } ``` +## Options +|Option|Description|Default| +|------|-----------|-------| +static $canImportResource | set static boolean value to allow import to the Nova Resource | true +method canImportResource | define the function to return boolean to allow import to the Nova Resource. Precede static value. | N/A + + +### example + +```php +// App\Nova\User +public static function canImportWithCSV(Request $request) +{ + return $request->user()->can("create", self::$model); +} +``` + ## Testing We need tests! Can you help? Please consider contributing. diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index 3f7bc4d..cb8bb42 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -52,8 +52,8 @@ public function preview(NovaRequest $request, $file) $static_vars = $resourceReflection->getStaticProperties(); - if($resourceReflection->hasMethod('canImportWithCSV')) { - return $resource::canImportWithCSV($request); + if($resourceReflection->hasMethod('canImportResource')) { + return $resource::canImportResource($request); } if(!isset($static_vars['canImportResource'])) { From df5116a8f4b5210c1d892100e331c15ce7437509 Mon Sep 17 00:00:00 2001 From: Monaye Win <> Date: Fri, 11 Dec 2020 15:01:27 -0800 Subject: [PATCH 03/17] - add exceptAttributesImportResource method allow attributes to be omit - allow config to export - added documentation --- README.md | 28 ++++++-- src/Http/Controllers/ImportController.php | 84 +++++++++++++---------- src/ToolServiceProvider.php | 6 ++ 3 files changed, 78 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 53588c1..0c8822e 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,13 @@ class NovaServiceProvider extends NovaApplicationServiceProvider ``` ## Options -|Option|Description|Default| -|------|-----------|-------| -static $canImportResource | set static boolean value to allow import to the Nova Resource | true -method canImportResource | define the function to return boolean to allow import to the Nova Resource. Precede static value. | N/A - +type |Option|Description|Default| +|-----|------|-----------|-------| +static | $canImportResource | set static boolean value to allow import to the Nova Resource | true +method | canImportResource | define the function to return boolean to allow import to the Nova Resource. Precede static value. | N/A +method | exceptAttributesImportResource | define the function to return attributes that would need not show up in selection of import | N/A + ### example ```php @@ -51,6 +52,23 @@ public static function canImportWithCSV(Request $request) } ``` +## Importer Class +The package use https://github.com/Maatwebsite/Laravel-Nova-Excel class behind the science. All the attributes and data are passed to the `importer` class which implements many of class provided by the Laravel-Nova-Excel. You can find more information here: https://docs.laravel-excel.com/3.1/imports/basics.html#importing-basics +You can define your own importer class to customize to your needs by providing class name in config file. + + Export config file + ``` + php artisan vendor:publish --tag=nova-csv-import + ``` + +define own importer class +``` + App\Utilities\Importer::class, +]; +``` ## Testing We need tests! Can you help? Please consider contributing. diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index cb8bb42..318b24d 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -20,8 +20,7 @@ class ImportController public function __construct() { - $class = config('laravel-nova-csv-import.importer'); - + $class = config('nova-csv-importer.importer'); $this->importer = new $class; } @@ -37,52 +36,67 @@ public function preview(NovaRequest $request, $file) $sample = $import->take(10)->all(); - $resources = collect(Nova::$resources); - - $resources = $resources->filter(function ($resource) use ($request) { - if ($resource === ActionResource::class) { - return false; - } + $resources = $this->getAvailableResourcesForImport($request); - if (!isset($resource::$model)) { - return false; - } - - $resourceReflection = (new \ReflectionClass((string) $resource)); - - $static_vars = $resourceReflection->getStaticProperties(); + $fields = $resources->mapWithKeys(function ($resource) use ($request) { + return $this->getAvailableFieldsForImport($resource, $request); + }); - if($resourceReflection->hasMethod('canImportResource')) { - return $resource::canImportResource($request); - } + $resources = $resources->mapWithKeys(function ($resource) { + return [$resource::uriKey() => $resource::label()]; + }); - if(!isset($static_vars['canImportResource'])) { - return true; - } + return response()->json(compact('sample', 'resources', 'fields', 'total_rows', 'headings')); + } - return isset($static_vars['canImportResource']) && $static_vars['canImportResource']; - }); + public function getAvailableFieldsForImport(String $resource, $request) + { + $novaResource = new $resource(new $resource::$model); + $fieldsCollection = collect($novaResource->creationFields($request)); - $fields = $resources->map(function ($resource) { - $model = $resource::$model; + if (method_exists($novaResource, 'exceptAttributesImportResource')) { + $fieldsCollection = $fieldsCollection->filter(function(Field $field) use ($novaResource, $request){ + return !in_array($field->attribute, $novaResource->exceptAttributesImportResource($request)); + }); + } - return new $resource(new $model); - })->mapWithKeys(function (Resource $resource) use ($request) { - $fields = collect($resource->creationFields($request)) - ->map(function (Field $field) { + $fields = $fieldsCollection->map(function (Field $field) { return [ 'name' => $field->name, 'attribute' => $field->attribute ]; }); - return [$resource->uriKey() => $fields]; - }); + + return [$novaResource->uriKey() => $fields]; + } - $resources = $resources->mapWithKeys(function ($resource) { - return [$resource::uriKey() => $resource::label()]; - }); + public function getAvailableResourcesForImport(NovaRequest $request) { - return response()->json(compact('sample', 'resources', 'fields', 'total_rows', 'headings')); + $novaResources = collect(Nova::authorizedResources($request)); + + return $novaResources->filter(function ($resource) use ($request) { + if ($resource === ActionResource::class) { + return false; + } + + if (!isset($resource::$model)) { + return false; + } + + $resourceReflection = (new \ReflectionClass((string) $resource)); + + if($resourceReflection->hasMethod('canImportResource')) { + return $resource::canImportResource($request); + } + + $static_vars = $resourceReflection->getStaticProperties(); + + if(!isset($static_vars['canImportResource'])) { + return true; + } + + return isset($static_vars['canImportResource']) && $static_vars['canImportResource']; + }); } public function import(NovaRequest $request, $file) diff --git a/src/ToolServiceProvider.php b/src/ToolServiceProvider.php index b352e88..ec2925b 100644 --- a/src/ToolServiceProvider.php +++ b/src/ToolServiceProvider.php @@ -28,6 +28,10 @@ public function boot() Nova::serving(function (ServingNova $event) { }); + + $this->publishes([ + __DIR__.'/config.php' => config_path('nova-csv-importer.php') + ], 'nova-csv-import'); } /** @@ -55,5 +59,7 @@ protected function routes() public function register() { // + $this->mergeConfigFrom(__DIR__.'/config.php', 'nova-csv-importer'); + } } From acd7184e488230ddc529a419bfb54bf0c2f9a11d Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:23:10 -0800 Subject: [PATCH 04/17] Update src/Http/Controllers/ImportController.php Co-authored-by: Simon Hamp --- src/Http/Controllers/ImportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index 318b24d..307c235 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -85,7 +85,7 @@ public function getAvailableResourcesForImport(NovaRequest $request) { $resourceReflection = (new \ReflectionClass((string) $resource)); - if($resourceReflection->hasMethod('canImportResource')) { + if ($resourceReflection->hasMethod('canImportResource')) { return $resource::canImportResource($request); } From b0e3b482c67105a63e8aded476635573ee5198c4 Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:23:20 -0800 Subject: [PATCH 05/17] Update src/Http/Controllers/ImportController.php Co-authored-by: Simon Hamp --- src/Http/Controllers/ImportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index 307c235..8b70d19 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -91,7 +91,7 @@ public function getAvailableResourcesForImport(NovaRequest $request) { $static_vars = $resourceReflection->getStaticProperties(); - if(!isset($static_vars['canImportResource'])) { + if (!isset($static_vars['canImportResource'])) { return true; } From 7ff9bea75efe5e40a0fbd82695a05759fa267714 Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:23:38 -0800 Subject: [PATCH 06/17] Update src/ToolServiceProvider.php Co-authored-by: Simon Hamp --- src/ToolServiceProvider.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ToolServiceProvider.php b/src/ToolServiceProvider.php index ec2925b..298809b 100644 --- a/src/ToolServiceProvider.php +++ b/src/ToolServiceProvider.php @@ -58,8 +58,6 @@ protected function routes() */ public function register() { - // $this->mergeConfigFrom(__DIR__.'/config.php', 'nova-csv-importer'); - } } From e5fe7ddc9cf3b3288b80f27dee3b505be0a6e2a2 Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:23:47 -0800 Subject: [PATCH 07/17] Update README.md Co-authored-by: Simon Hamp --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c8822e..6e2fdf1 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ method | canImportResource | define the function to return boolean to allow impo method | exceptAttributesImportResource | define the function to return attributes that would need not show up in selection of import | N/A -### example +### Example ```php // App\Nova\User From fb06fe2631062a56db5b65b741556f944a47c363 Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:24:26 -0800 Subject: [PATCH 08/17] Update README.md Co-authored-by: Simon Hamp --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e2fdf1..584bece 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ method | exceptAttributesImportResource | define the function to return attribut ```php // App\Nova\User -public static function canImportWithCSV(Request $request) +public static function canImportResource(Request $request) { return $request->user()->can("create", self::$model); } From 3c3a221445c27f70942c9ff330a4e3b1b21e38db Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:24:37 -0800 Subject: [PATCH 09/17] Update README.md Co-authored-by: Simon Hamp --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 584bece..19cae88 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,9 @@ public static function canImportResource(Request $request) ``` ## Importer Class -The package use https://github.com/Maatwebsite/Laravel-Nova-Excel class behind the science. All the attributes and data are passed to the `importer` class which implements many of class provided by the Laravel-Nova-Excel. You can find more information here: https://docs.laravel-excel.com/3.1/imports/basics.html#importing-basics -You can define your own importer class to customize to your needs by providing class name in config file. +This package uses [maatwebsite/excel](https://github.com/Maatwebsite/Laravel-Excel) behind the scenes to handle the actual import. You can find more information about how importing [works here](https://docs.laravel-excel.com/3.1/imports/basics.html#importing-basics) + +You can define your own importer class by providing the relevant class name in your published copy of this package's config file. Export config file ``` From 3431274ca30516e28783d04c58eaa7557c571796 Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:24:59 -0800 Subject: [PATCH 10/17] Update README.md Co-authored-by: Simon Hamp --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 19cae88..754d485 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ This package uses [maatwebsite/excel](https://github.com/Maatwebsite/Laravel-Exc You can define your own importer class by providing the relevant class name in your published copy of this package's config file. - Export config file - ``` - php artisan vendor:publish --tag=nova-csv-import - ``` +Publish the config file +``` +php artisan vendor:publish --tag=nova-csv-import +``` define own importer class ``` From 2e48433b9486e162ed08e08faae15d3c954c353c Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:25:11 -0800 Subject: [PATCH 11/17] Update README.md Co-authored-by: Simon Hamp --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 754d485..36a840c 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Publish the config file php artisan vendor:publish --tag=nova-csv-import ``` -define own importer class +Define and register your own importer class ``` Date: Mon, 14 Dec 2020 09:25:22 -0800 Subject: [PATCH 12/17] Update README.md Co-authored-by: Simon Hamp --- README.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 36a840c..30dcd31 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,18 @@ class NovaServiceProvider extends NovaApplicationServiceProvider ``` ## Options -type |Option|Description|Default| -|-----|------|-----------|-------| -static | $canImportResource | set static boolean value to allow import to the Nova Resource | true -method | canImportResource | define the function to return boolean to allow import to the Nova Resource. Precede static value. | N/A -method | exceptAttributesImportResource | define the function to return attributes that would need not show up in selection of import | N/A +By default, all of your Nova Resources will be available for import. However, there are a number of ways that you can explicitly limit what's available for importing. + +`public static $canImportResource = false;` +*Default:* `true` +Add this static property to your Resource to prevent it from showing up in the Nova CSV Import tool interface. + +`public static function canImportResource($request): bool` +Define a `canImportResource` method to use more complex logic to decide if this Resource can be shown during import. If defined, this takes precedence over the `$canImportResource` property. + +`public function excludeAttributesFromImport(): array` +*Default:* `[]` +Define a `excludeAttributesFromImport` method that returns an array of attribute names that you want to _exclude_ from being visible in the import tool for this Resource. ### Example From c15a362599ca3fc50c76d6ad30864fe66eb2f8b6 Mon Sep 17 00:00:00 2001 From: Monaye Win Date: Mon, 14 Dec 2020 09:25:58 -0800 Subject: [PATCH 13/17] Update src/Http/Controllers/ImportController.php Co-authored-by: Simon Hamp --- src/Http/Controllers/ImportController.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index 8b70d19..6699100 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -54,9 +54,8 @@ public function getAvailableFieldsForImport(String $resource, $request) $novaResource = new $resource(new $resource::$model); $fieldsCollection = collect($novaResource->creationFields($request)); - if (method_exists($novaResource, 'exceptAttributesImportResource')) { - $fieldsCollection = $fieldsCollection->filter(function(Field $field) use ($novaResource, $request){ - return !in_array($field->attribute, $novaResource->exceptAttributesImportResource($request)); + if (method_exists($novaResource, 'excludeAttributesFromImport')) {$fieldsCollection = $fieldsCollection->filter(function(Field $field) use ($novaResource, $request) { + return !in_array($field->attribute, $novaResource->exludeAttributesFromImport($request)); }); } From 411b854a7555182021df0e186d68764ce6af1aa8 Mon Sep 17 00:00:00 2001 From: Monaye Win <> Date: Mon, 14 Dec 2020 09:29:52 -0800 Subject: [PATCH 14/17] remove duplicate config merger --- src/ToolServiceProvider.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ToolServiceProvider.php b/src/ToolServiceProvider.php index 298809b..9493db3 100644 --- a/src/ToolServiceProvider.php +++ b/src/ToolServiceProvider.php @@ -19,8 +19,6 @@ public function boot() { $this->loadViewsFrom(__DIR__.'/../resources/views', 'laravel-nova-csv-import'); - $this->mergeConfigFrom(__DIR__.'/config.php', 'laravel-nova-csv-import'); - $this->app->booted(function () { $this->routes(); }); From 50d07b874efcd3613736800d953dbcf8e3443657 Mon Sep 17 00:00:00 2001 From: Monaye Win <> Date: Mon, 14 Dec 2020 09:44:07 -0800 Subject: [PATCH 15/17] fix typo on method name --- src/Http/Controllers/ImportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index 6699100..b3d1ca1 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -55,7 +55,7 @@ public function getAvailableFieldsForImport(String $resource, $request) $fieldsCollection = collect($novaResource->creationFields($request)); if (method_exists($novaResource, 'excludeAttributesFromImport')) {$fieldsCollection = $fieldsCollection->filter(function(Field $field) use ($novaResource, $request) { - return !in_array($field->attribute, $novaResource->exludeAttributesFromImport($request)); + return !in_array($field->attribute, $novaResource->excludeAttributesFromImport($request)); }); } From 29324a82702258b1173f6893b4153f24ed24de8f Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Mon, 14 Dec 2020 19:35:50 +0000 Subject: [PATCH 16/17] Make excludeAttributesFromImport static --- README.md | 2 +- src/Http/Controllers/ImportController.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 30dcd31..7f5776b 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Add this static property to your Resource to prevent it from showing up in the N `public static function canImportResource($request): bool` Define a `canImportResource` method to use more complex logic to decide if this Resource can be shown during import. If defined, this takes precedence over the `$canImportResource` property. -`public function excludeAttributesFromImport(): array` +`public static function excludeAttributesFromImport(): array` *Default:* `[]` Define a `excludeAttributesFromImport` method that returns an array of attribute names that you want to _exclude_ from being visible in the import tool for this Resource. diff --git a/src/Http/Controllers/ImportController.php b/src/Http/Controllers/ImportController.php index b3d1ca1..bd4d619 100644 --- a/src/Http/Controllers/ImportController.php +++ b/src/Http/Controllers/ImportController.php @@ -54,8 +54,9 @@ public function getAvailableFieldsForImport(String $resource, $request) $novaResource = new $resource(new $resource::$model); $fieldsCollection = collect($novaResource->creationFields($request)); - if (method_exists($novaResource, 'excludeAttributesFromImport')) {$fieldsCollection = $fieldsCollection->filter(function(Field $field) use ($novaResource, $request) { - return !in_array($field->attribute, $novaResource->excludeAttributesFromImport($request)); + if (method_exists($novaResource, 'excludeAttributesFromImport')) { + $fieldsCollection = $fieldsCollection->filter(function(Field $field) use ($novaResource, $request) { + return !in_array($field->attribute, $novaResource::excludeAttributesFromImport($request)); }); } From 458fbda3f9e3f39258efaf848aa538919b896b06 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Mon, 14 Dec 2020 19:43:50 +0000 Subject: [PATCH 17/17] Improve the readme some more --- README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7f5776b..4297cd8 100644 --- a/README.md +++ b/README.md @@ -37,15 +37,15 @@ class NovaServiceProvider extends NovaApplicationServiceProvider ## Options By default, all of your Nova Resources will be available for import. However, there are a number of ways that you can explicitly limit what's available for importing. -`public static $canImportResource = false;` -*Default:* `true` +`public static $canImportResource = false;` +*Default:* `true` Add this static property to your Resource to prevent it from showing up in the Nova CSV Import tool interface. -`public static function canImportResource($request): bool` +`public static function canImportResource($request): bool` Define a `canImportResource` method to use more complex logic to decide if this Resource can be shown during import. If defined, this takes precedence over the `$canImportResource` property. -`public static function excludeAttributesFromImport(): array` -*Default:* `[]` +`public static function excludeAttributesFromImport(): array` +*Default:* `[]` Define a `excludeAttributesFromImport` method that returns an array of attribute names that you want to _exclude_ from being visible in the import tool for this Resource. @@ -57,19 +57,24 @@ public static function canImportResource(Request $request) { return $request->user()->can("create", self::$model); } + +public static function excludeAttributesFromImport() +{ + return ['password']; +} ``` ## Importer Class -This package uses [maatwebsite/excel](https://github.com/Maatwebsite/Laravel-Excel) behind the scenes to handle the actual import. You can find more information about how importing [works here](https://docs.laravel-excel.com/3.1/imports/basics.html#importing-basics) +This package uses [maatwebsite/excel](https://github.com/Maatwebsite/Laravel-Excel) behind the scenes to handle the actual import. You can find more information about how importing [works here](https://docs.laravel-excel.com/3.1/imports/basics.html#importing-basics). You can define your own importer class by providing the relevant class name in your published copy of this package's config file. -Publish the config file +First, publish the config file: ``` php artisan vendor:publish --tag=nova-csv-import ``` -Define and register your own importer class +Then, define and register your own importer class: ```