Add job for function upload record to csv

This commit is contained in:
paoloGuagnano
2024-02-23 16:00:48 +01:00
parent 4a042f01ac
commit e7b7f3f31c
11 changed files with 230 additions and 186 deletions

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use App\Http\Requests\FileRequest; use App\Http\Requests\FileRequest;
use App\Http\Requests\StorefileRequest; use App\Http\Requests\StorefileRequest;
use App\Http\Requests\UpdatefileRequest; use App\Http\Requests\UpdatefileRequest;
use App\Jobs\ImportCSVFileJob;
use App\Models\file; use App\Models\file;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -14,28 +15,14 @@ class FileController extends Controller
{ {
public function uploadFile(FileRequest $request): RedirectResponse public function uploadFile(FileRequest $request): RedirectResponse
{ {
//save file in storage/app/public/file_temp
$filename = 'new_file.'.$request->file("filetoinsert")->getClientOriginalExtension(); $filename = 'new_file.'.$request->file("filetoinsert")->getClientOriginalExtension();
$request->file("filetoinsert")->storeAs('file_temp', $filename); $request->file("filetoinsert")->storeAs('file_temp', $filename);
// Leggi il contenuto del file CSV //get file path
$contenutoCSV = Storage::get('file_temp/new_file.csv'); $filepath = storage_path('app/public/file_temp/new_file.csv');
// Analizza il contenuto CSV
$righeCSV = str_getcsv($contenutoCSV, "\n");
// Converte le righe CSV in un array associativo
$dati = [];
foreach ($righeCSV as $riga) {
$dati[] = str_getcsv($riga);
}
// Converte l'array in formato JSON
$json = json_encode($dati);
// Stampa il JSON
echo $json;
dispatch(new ImportCSVFileJob($filepath));
return redirect('/words'); return redirect('/words');
} }

View File

@@ -18,7 +18,7 @@ class FileRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'filetoinsert' => ['required', 'mimes:txt']//, File::types(['csv'])] 'filetoinsert' => ['required', 'mimes:csv']//, File::types(['csv'])]
]; ];
} }

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Word;
use Illuminate\Support\Facades\Storage;
class ImportCSVFileJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $filepath;
/**
* Create a new job instance.
*/
public function __construct($filepath)
{
$this->filepath = $filepath;
}
/**
* Execute the job.
*/
public function handle(): void
{
$mapping = [
'name' => 0, 'translation' => 1,
];
$fileStream = fopen($this->filepath, 'r');
$skipHeader = true;
while ($row = fgetcsv($fileStream)) {
if ($skipHeader) {
$skipHeader = false;
continue;
}
Word::updateOrCreate(
[
'name' => $row[$mapping['name']],
'translation' => $row[$mapping['translation']],
]
);
}
fclose($fileStream);
Storage::delete($this->filepath);
}
}

View File

@@ -38,7 +38,7 @@ return [
'driver' => 'database', 'driver' => 'database',
'table' => 'jobs', 'table' => 'jobs',
'queue' => 'default', 'queue' => 'default',
'retry_after' => 90, 'retry_after' => 1250,
'after_commit' => false, 'after_commit' => false,
], ],

View File

@@ -15,9 +15,9 @@ class AdminUserSeeder extends Seeder
public function run(): void public function run(): void
{ {
$superAdmin = User::create([ $superAdmin = User::create([
'name' => 'Kagir', 'name' => 'paolo',
'email' => 'kagir.dev@gmail.com ', 'email' => 'paolo.guagnano1986@gmail.com',
'password' => Hash::make('Prova123!') 'password' => Hash::make('paolo220186')
]); ]);
$superAdmin->assignRole('ADMIN'); $superAdmin->assignRole('ADMIN');
} }

View File

@@ -1,5 +1,7 @@
@props(['value']) @props(['value'])
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700 dark:text-gray-300']) }}> <label {{ $attributes->merge(['class' => 'col-md-4 col-form-label text-md-end text-start']) }}>
{{ $value ?? $slot }} {{ $value ?? $slot }}
</label> </label>
{{--'block font-medium text-sm text-gray-700 dark:text-gray-300'--}}

View File

@@ -1,3 +1,5 @@
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150']) }}> <button {{ $attributes->merge(['type' => 'submit', 'class' => 'col-md-3 offset-md-5 btn btn-primary']) }}>
{{ $slot }} {{ $slot }}
</button> </button>
{{--inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150--}}

View File

@@ -1,26 +0,0 @@
@props(['items' => []])
@props(['fields' => []])
<table class="table table-striped">
<thead>
<tr>
<th>Italian Word</th>
<th>Dialect Translation</th>
</tr>
</thead>
<tbody>
@forelse ($items as $item)
<tr>
<td>{{ $item->{$fields[0]} }}</td>
<td>{{ $item->{$fields[1]} }}</td>
<td> <a href="edit_record/{{ $item->id }}"><button class="btn btn-primary">Edit</button> </a> </td>
<td> <a href="delete_record/{{ $item->id }}"><button class="btn btn-danger">Delete</button> </a> </td>
</tr>
@empty
<tr>
<td class="text-center" colspan="2">No words</td>
</tr>
@endforelse
</tbody>
</table>

View File

@@ -1,55 +1,60 @@
<section class="space-y-6">
<header>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Delete Account') }}
</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
{{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }}
</p>
</header>
<x-danger-button
x-data=""
x-on:click.prevent="$dispatch('open-modal', 'confirm-user-deletion')"
>{{ __('Delete Account') }}</x-danger-button>
<x-modal name="confirm-user-deletion" :show="$errors->userDeletion->isNotEmpty()" focusable>
<form method="post" action="{{ route('profile.destroy') }}" class="p-6">
@csrf
@method('delete')
<div class="card">
<div class="card-header">
<div>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Are you sure you want to delete your account?') }} {{ __('Delete Account') }}
</h2> </h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400"> <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
{{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }} {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }}
</p> </p>
</div>
</div>
<div class="mt-6"> <div class="card-body">
<x-input-label for="password" value="{{ __('Password') }}" class="sr-only" /> <x-danger-button
x-data=""
x-on:click.prevent="$dispatch('open-modal', 'confirm-user-deletion')"
>{{ __('Delete Account') }}</x-danger-button>
<x-text-input <x-modal name="confirm-user-deletion" :show="$errors->userDeletion->isNotEmpty()" focusable>
id="password" <form method="post" action="{{ route('profile.destroy') }}" class="p-6">
name="password" @csrf
type="password" @method('delete')
class="mt-1 block w-3/4"
placeholder="{{ __('Password') }}"
/>
<x-input-error :messages="$errors->userDeletion->get('password')" class="mt-2" /> <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
</div> {{ __('Are you sure you want to delete your account?') }}
</h2>
<div class="mt-6 flex justify-end"> <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
<x-secondary-button x-on:click="$dispatch('close')"> {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }}
{{ __('Cancel') }} </p>
</x-secondary-button>
<x-danger-button class="ms-3"> <div class="mt-6">
{{ __('Delete Account') }} <x-input-label for="password" value="{{ __('Password') }}" class="sr-only" />
</x-danger-button>
</div> <x-text-input
</form> id="password"
</x-modal> name="password"
</section> type="password"
class="mt-1 block w-3/4"
placeholder="{{ __('Password') }}"
/>
<x-input-error :messages="$errors->userDeletion->get('password')" class="mt-2" />
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-danger-button class="ms-3">
{{ __('Delete Account') }}
</x-danger-button>
</div>
</form>
</x-modal>
</div>
</div>

View File

@@ -1,49 +1,60 @@
<section>
<header>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Update Password') }}
</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
{{ __('Ensure your account is using a long, random password to stay secure.') }}
</p>
</header>
<form method="post" action="{{ route('password.update') }}" class="mt-6 space-y-6">
@csrf
@method('put')
<div class="card">
<div class="card-header">
<div> <div>
<x-input-label for="update_password_current_password" :value="__('Current Password')" /> <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
<x-text-input :notvalid="$errors->updatePassword->has('current_password')" id="update_password_current_password" name="current_password" type="password" class="mt-1 block w-full" autocomplete="current-password" /> {{ __('Update Password') }}
<x-input-error :messages="$errors->updatePassword->get('current_password')" class="mt-2" /> </h2>
</div>
<div> <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
<x-input-label for="update_password_password" :value="__('New Password')" /> {{ __('Ensure your account is using a long, random password to stay secure.') }}
<x-text-input :notvalid="$errors->updatePassword->has('password')" id="update_password_password" name="password" type="password" class="mt-1 block w-full" autocomplete="new-password" /> </p>
<x-input-error :messages="$errors->updatePassword->get('password')" class="mt-2" />
</div> </div>
</div>
<div> <div class="card-body">
<x-input-label for="update_password_password_confirmation" :value="__('Confirm Password')" /> <form method="post" action="{{ route('password.update') }}" class="mt-6 space-y-6">
<x-text-input :notvalid="$errors->updatePassword->has('password_confirmation')" id="update_password_password_confirmation" name="password_confirmation" type="password" class="mt-1 block w-full" autocomplete="new-password" /> @csrf
<x-input-error :messages="$errors->updatePassword->get('password_confirmation')" class="mt-2" /> @method('put')
</div>
<div class="flex items-center gap-4">
<x-primary-button>{{ __('Save') }}</x-primary-button>
@if (session('status') === 'password-updated') <div class="mb-3 row">
<p <x-input-label for="update_password_current_password" :value="__('Current Password')" />
x-data="{ show: true }" <div class="col-md-6">
x-show="show" <x-text-input :notvalid="$errors->updatePassword->has('current_password')" id="update_password_current_password" name="current_password" type="password" class="mt-1 block w-full" autocomplete="current-password" />
x-transition <x-input-error :messages="$errors->updatePassword->get('current_password')" class="mt-2" />
x-init="setTimeout(() => show = false, 2000)" </div>
class="text-sm text-gray-600 dark:text-gray-400" </div>
>{{ __('Saved.') }}</p>
@endif <div class="mb-3 row">
</div> <x-input-label for="update_password_password" :value="__('New Password')" />
</form> <div class="col-md-6">
</section> <x-text-input :notvalid="$errors->updatePassword->has('password')" id="update_password_password" name="password" type="password" class="mt-1 block w-full" autocomplete="new-password" />
<x-input-error :messages="$errors->updatePassword->get('password')" class="mt-2" />
</div>
</div>
<div class="mb-3 row">
<x-input-label for="update_password_password_confirmation" :value="__('Confirm Password')" />
<div class="col-md-6">
<x-text-input :notvalid="$errors->updatePassword->has('password_confirmation')" id="update_password_password_confirmation" name="password_confirmation" type="password" class="mt-1 block w-full" autocomplete="new-password" />
<x-input-error :messages="$errors->updatePassword->get('password_confirmation')" class="mt-2" />
</div>
</div>
<div class="flex items-center gap-4">
<x-primary-button>{{ __('Save') }}</x-primary-button>
@if (session('status') === 'password-updated')
<p
x-data="{ show: true }"
x-show="show"
x-transition
x-init="setTimeout(() => show = false, 2000)"
class="text-sm text-gray-600 dark:text-gray-400"
>{{ __('Saved.') }}</p>
@endif
</div>
</form>
</div>
</div>

View File

@@ -1,64 +1,75 @@
<section> <div class="card">
<header> <div class="card-header">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> <div>
{{ __('Profile Information') }} <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
</h2> {{ __('Profile Information') }}
</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400"> <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
{{ __("Update your account's profile information and email address.") }} {{ __("Update your account's profile information and email address.") }}
</p> </p>
</header> </div>
<div class="float-end">
<a href="{{ route('words.index') }}" class="btn btn-primary"> Back</a>
</div>
</div>
<form id="send-verification" method="post" action="{{ route('verification.send') }}"> <form id="send-verification" method="post" action="{{ route('verification.send') }}">
@csrf @csrf
</form> </form>
<form method="post" action="{{ route('profile.update') }}" class="mt-6 space-y-6"> <div class="card-body">
@csrf <form method="post" action="{{ route('profile.update') }}" class="mt-6 space-y-6">
@method('patch') @csrf
@method('patch')
<div> <div class="mb-3 row">
<x-input-label for="name" :value="__('Name')" /> <x-input-label for="name" :value="__('Name')" />
<x-text-input id="name" name="name" type="text" class="mt-1 block w-full" :value="old('name', $user->name)" required autofocus autocomplete="name" /> <div class="col-md-6">
<x-input-error class="mt-2" :messages="$errors->get('name')" /> <x-text-input id="name" name="name" type="text" class="mt-1 block w-full" :value="old('name', $user->name)" required autofocus autocomplete="name" />
</div> <x-input-error class="mt-2" :messages="$errors->get('name')" />
</div>
</div>
<div> <div class="mb-3 row">
<x-input-label for="email" :value="__('Email')" /> <x-input-label for="email" :value="__('Email')" />
<x-text-input id="email" name="email" type="email" class="mt-1 block w-full" :value="old('email', $user->email)" required autocomplete="username" /> <div class="col-md-6">
<x-input-error class="mt-2" :messages="$errors->get('email')" /> <x-text-input id="email" name="email" type="email" class="mt-1 block w-full" :value="old('email', $user->email)" required autocomplete="username" />
<x-input-error class="mt-2" :messages="$errors->get('email')" />
@if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail()) @if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail())
<div> <div>
<p class="text-sm mt-2 text-gray-800 dark:text-gray-200"> <p class="text-sm mt-2 text-gray-800 dark:text-gray-200">
{{ __('Your email address is unverified.') }} {{ __('Your email address is unverified.') }}
<button form="send-verification" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"> <button form="send-verification" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800">
{{ __('Click here to re-send the verification email.') }} {{ __('Click here to re-send the verification email.') }}
</button> </button>
</p> </p>
@if (session('status') === 'verification-link-sent') @if (session('status') === 'verification-link-sent')
<p class="mt-2 font-medium text-sm text-green-600 dark:text-green-400"> <p class="mt-2 font-medium text-sm text-green-600 dark:text-green-400">
{{ __('A new verification link has been sent to your email address.') }} {{ __('A new verification link has been sent to your email address.') }}
</p> </p>
@endif
</div>
@endif @endif
</div> </div>
@endif </div>
</div>
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<x-primary-button>{{ __('Save') }}</x-primary-button> <x-primary-button>{{ __('Save') }}</x-primary-button>
@if (session('status') === 'profile-updated') @if (session('status') === 'profile-updated')
<p <p
x-data="{ show: true }" x-data="{ show: true }"
x-show="show" x-show="show"
x-transition x-transition
x-init="setTimeout(() => show = false, 2000)" x-init="setTimeout(() => show = false, 2000)"
class="text-sm text-gray-600 dark:text-gray-400" class="text-sm text-gray-600 dark:text-gray-400"
>{{ __('Saved.') }}</p> >{{ __('Saved.') }}</p>
@endif @endif
</div> </div>
</form> </form>
</section> </div>
</div>