Skip to content

404 in dev, not in production #69

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

Closed
beiaduo opened this issue Jun 16, 2023 · 16 comments
Closed

404 in dev, not in production #69

beiaduo opened this issue Jun 16, 2023 · 16 comments

Comments

@beiaduo
Copy link

beiaduo commented Jun 16, 2023

1 composer require simonhamp/laravel-nova-csv-import --with-all-dependencies

2 new LaravelNovaCsvImport,

@beiaduo
Copy link
Author

beiaduo commented Jun 16, 2023

Do you have any documents ?Thank you!

@mberatsanli
Copy link

just adjust the $canImportResource in nova resources

public static $canImportResource = false;

@simonhamp
Copy link
Owner

@beiaduo have you customised your Nova menu by any chance? If so, you will need to manually add the tool link to your menu

@beiaduo
Copy link
Author

beiaduo commented Jun 19, 2023

Just default ,I can see import menu, when I click It ,it show me 404,but when I uploaded to server ,it is working, I don't know why,Just local 404, I will clear cache to retry, Thank you

@simonhamp
Copy link
Owner

@beiaduo that's strange. There's nothing in the package that differentiates between local and production (iirc) so I suggest there's something peculiar happening in your local environment

Hope you can get to the bottom of it. Please share what you find here

@mihaileu
Copy link

same as @beiaduo

@simonhamp
Copy link
Owner

@mihaileu You mean it works fine on your production server but not on your local dev environment?

@kovpynets
Copy link

I acknowledge the error. The situation is similar

@Brissan
Copy link

Brissan commented Jul 3, 2023

Change in ImportController.php getAvailableFieldsForImport function

protected function getAvailableFieldsForImport(string $resource, NovaRequest $request): array  
{  
    try {
        $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));  
            });  
        }  

        $fields = $fieldsCollection->map(function (Field $field) use ($novaResource, $request) {  
            return [  
                'name' => $field->name,  
                'attribute' => $field->attribute,  
                'rules' => $this->extractValidationRules($novaResource, $request)->get($field->attribute),  
            ];  
        });  
    } catch (\Throwable $th) {  
        return [];  
    }  

    // Note: ->values() is used here to avoid this array being turned into an object due to   
    // non-sequential keys (which might happen due to the filtering above.  
    return [  
        $novaResource->uriKey() => $fields->values(),  
    ];  
}  

@beshoo
Copy link

beshoo commented Jul 3, 2023

Same here. once I import a tiny CSV file, I get redirected to a 404 page.. the URL I have been redirected to:

http://127.0.0.1:8000/dashboard/csv-import/configure/43937a4ef0d4743f485d25156ff5eb0d.csv

@Brissan
Copy link

Brissan commented Jul 3, 2023

То же самое здесь. как только я импортирую крошечный CSV-файл, я перенаправляюсь на страницу 404 .. URL, на который я был перенаправлен:

http://127.0.0.1:8000/dashboard/csv-import/configure/43937a4ef0d4743f485d25156ff5eb0d.csv

ChatGPT just told me how to fix the error, threw off the option above, it worked for me immediately as soon as I changed the path where I changed \vendor\simonhamp\laravel-nova-csv-import\src\Http\Controllers

image

@beshoo
Copy link

beshoo commented Jul 3, 2023 via email

@Brissan
Copy link

Brissan commented Jul 3, 2023

<?php

namespace SimonHamp\LaravelNovaCsvImport\Http\Controllers;

use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Collection;
use Inertia\Response;
use Laravel\Nova\Actions\ActionResource;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Nova;
use Laravel\Nova\Resource;
use Laravel\Nova\Rules\Relatable;
use Maatwebsite\Excel\Concerns\ToModel as ModelImporter;

class ImportController
{
    protected $importer;

    protected $filesystem;

    public function __construct(ModelImporter $importer, Filesystem $filesystem)
    {
        $this->importer = $importer;

        $this->filesystem = $filesystem;
    }

    public function configure(NovaRequest $request, string $file): Response
    {
        $file_name = pathinfo($file, PATHINFO_FILENAME);

        $import = $this->importer
            ->toCollection($this->getFilePath($file), $this->getDisk())
            ->first();

        $headings = $import->first()->keys();

        $total_rows = $import->count();

        $config = $this->getConfigForFile($file);

        $rows = $import->take(10)->all();

        $resources = $this->getAvailableResourcesForImport($request);

        $fields = $resources->mapWithKeys(function ($resource) use ($request) {
            return $this->getAvailableFieldsForImport($resource, $request);
        });

        $resources = $resources->mapWithKeys(function ($resource) {
            return [
                $resource::uriKey() => $resource::label(),
            ];
        });

        $mods = $this->importer->getAvailableModifiers();

        return inertia(
            'CsvImport/Configure',
            compact('file', 'file_name', 'resources', 'fields', 'rows', 'total_rows', 'headings', 'config', 'mods')
        );
    }

    /**
     * @throws \Symfony\Component\HttpKernel\Exception\HttpException
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
     */
    public function storeConfig(NovaRequest $request)
    {
        $file = $request->input('file');

        // TODO: Add some validation
        $config = json_encode(
            array_merge(
                $this->getConfigForFile($file),
                [
                    'resource' => $request->input('resource'),
                    'mappings' => $request->input('mappings'),
                    'values' => $request->input('values'),
                    'modifiers' => collect($request->input('modifiers'))
                        ->map(function ($modifiers) {
                            return collect($modifiers)
                                ->reject(function ($modifier) {
                                    return empty($modifier['name']);
                                });
                        }),
                ],
            ),
            JSON_PRETTY_PRINT
        );

        $path = $this->getConfigFilePath($file);

        $this->filesystem->delete($path);

        if (! $this->filesystem->put($path, $config)) {
            return abort(500);
        }
    }

    public function preview(NovaRequest $request, string $file): Response
    {
        $config = $this->getConfigForFile($file);

        $resource = $config['resource'];

        $import = $this->importer
            ->setAttributeMap($columns = $config['mappings'])
            ->setCustomValues($config['values'])
            ->setMeta($config['meta'])
            ->setModifiers($config['modifiers'])
            ->toCollection($this->getFilePath($file), $this->getDisk())
            ->first();

        $total_rows = $import->count();

        $mapped_columns = array_values(array_filter($columns));

        $rows = $import->take(100)->all();

        return inertia(
            'CsvImport/Preview',
            compact('config', 'rows', 'total_rows', 'columns', 'mapped_columns', 'resource', 'file')
        );
    }

    public function import(NovaRequest $request)
    {
        $file = $request->input('file');

        $path = $this->getFilePath($file);

        if (! $config = $this->getConfigForFile($file)) {
            return redirect()->route('csv-import.configure', ['file' => $file]);
        }

        $resource_name = $config['resource'];

        $resource = Nova::resourceInstanceForKey($resource_name);
        $rules = $this->extractValidationRules($resource, $request)->toArray();
        $model_class = $resource->resource::class;

        $import = $this->importer
            ->toCollection($path, $this->getDisk())
            ->first();

        $total_rows = $import->count();

        $this->importer
            ->setResource($resource)
            ->setAttributeMap($config['mappings'])
            ->setRules($rules)
            ->setModelClass($model_class)
            ->setMeta($config['meta'])
            ->setCustomValues($config['values'])
            ->setModifiers($config['modifiers'])
            ->import($path, $this->getDisk());

        $failures = $this->importer->failures();
        $errors = $this->importer->errors();

        $results = $this->getResultsFilePath($file);

        $this->filesystem->delete($results);

        $this->filesystem->put($results, json_encode([
            'total_rows' => $total_rows,
            'imported' => $total_rows - $failures->count() - $errors->count(),
            'failures' => $failures,
            'errors' => $errors,
        ], JSON_PRETTY_PRINT));

        return response()->json(['review' => "/csv-import/review/{$file}"]);
    }

    public function review(NovaRequest $request, string $file): Response
    {
        if (! $results = $this->getLastResultsForFile($file)) {
            return redirect()->route('csv-import.preview', ['file' => $file]);
        }

        $imported = $results['imported'];
        $total_rows = $results['total_rows'];
        $failures = collect($results['failures'])->groupBy('row');
        $errors = collect($results['errors'])->groupBy('row');

        $config = $this->getConfigForFile($file);

        return inertia(
            'CsvImport/Review',
            compact('file', 'failures', 'errors', 'total_rows', 'config', 'imported')
        );
    }

    protected function getAvailableFieldsForImport(string $resource, NovaRequest $request): array
    {
        try {
            $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));
                });
            }

            $fields = $fieldsCollection->map(function (Field $field) use ($novaResource, $request) {
                return [
                    'name' => $field->name,
                    'attribute' => $field->attribute,
                    'rules' => $this->extractValidationRules($novaResource, $request)->get($field->attribute),
                ];
            });
        } catch (\Throwable $th) {
            return [];
        }

        // Note: ->values() is used here to avoid this array being turned into an object due to
        // non-sequential keys (which might happen due to the filtering above.
        return [
            $novaResource->uriKey() => $fields->values(),
        ];
    }

    protected function getAvailableResourcesForImport(NovaRequest $request): Collection
    {
        $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'];
        });
    }

    protected function extractValidationRules(Resource $resource, NovaRequest $request): Collection
    {
        return collect($resource::rulesForCreation($request))->mapWithKeys(function ($rule, $key) {
            foreach ($rule as $i => $r) {
                if (! is_object($r)) {
                    continue;
                }

                // Make sure relation checks start out with a clean query
                if (is_a($r, Relatable::class)) {
                    $rule[$i] = function () use ($r) {
                        $r->query = $r->query->newQuery();

                        return $r;
                    };
                }
            }

            return [$key => $rule];
        });
    }

    protected function getConfigForFile(string $file): array
    {
        $config = $this->getDataFromJsonFile($this->getConfigFilePath($file));

        $config['values'] = $config['values'] ?? [];
        $config['modifiers'] = $config['modifiers'] ?? new \stdClass;

        $original_filename = $config['original_filename'] ?? '';

        $config['meta'] = [
            'file' => $file,
            'file_name' => pathinfo($file, PATHINFO_FILENAME),
            'original_file' => $original_filename,
            'original_file_name' => pathinfo($original_filename, PATHINFO_FILENAME),
        ];

        return $config;
    }

    protected function getLastResultsForFile(string $file): array
    {
        return $this->getDataFromJsonFile($this->getResultsFilePath($file));
    }

    protected function getFilePath(string $file): string
    {
        return "csv-import/{$file}";
    }

    protected function getConfigFilePath(string $file): string
    {
        return $this->getFilePath("{$file}.config.json");
    }

    protected function getResultsFilePath(string $file): string
    {
        return $this->getFilePath("{$file}.results.json");
    }

    protected function getDataFromJsonFile(string $file): array
    {
        if ($this->filesystem->exists($file)) {
            return @json_decode($this->filesystem->get($file), true) ?? [];
        }

        return [];
    }

    protected function getDisk(): ?string
    {
        return config('csv-import.disk');
    }
}

@beshoo
Copy link

beshoo commented Jul 4, 2023

То же самое здесь. как только я импортирую крошечный CSV-файл, я перенаправляюсь на страницу 404 .. URL, на который я был перенаправлен:
http://127.0.0.1:8000/dashboard/csv-import/configure/43937a4ef0d4743f485d25156ff5eb0d.csv

ChatGPT just told me how to fix the error, threw off the option above, it worked for me immediately as soon as I changed the path where I changed \vendor\simonhamp\laravel-nova-csv-import\src\Http\Controllers

image

I dont understand you , your file is exactly as my file.
where is the path you are talking about
:\vendor\simonhamp\laravel-nova-csv-import\src\Http\Controllers

What the file you cahnged@

@simonhamp simonhamp changed the title Hi how to use ? It is show 404 404 in dev, not in production Jul 4, 2023
@simonhamp
Copy link
Owner

@Brissan @beshoo I'm not seeing anything in your replies that are going to help me debug your issue. So I'm not sure whether you're experiencing what @beiaduo originally raised...

It seems you may be better off checking out and adding to #44 instead

@beiaduo
Copy link
Author

beiaduo commented Jul 4, 2023

Sorry sir, I have been working in other places recently and have not taken time to check. I will definitely check when I get home, and then report back all the information. Thank you for your reply

@beiaduo beiaduo closed this as completed Apr 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants