From cf9df74ed3be9e26c6f25b7df5506845d1af04e5 Mon Sep 17 00:00:00 2001 From: shibafu Date: Wed, 20 May 2020 01:50:34 +0900 Subject: [PATCH] Export checkin to CSV --- app/Http/Controllers/SettingController.php | 31 ++++++++++++ app/Services/CheckinCsvExporter.php | 57 ++++++++++++++++++++++ resources/views/setting/base.blade.php | 2 + resources/views/setting/export.blade.php | 23 +++++++++ routes/web.php | 2 + 5 files changed, 115 insertions(+) create mode 100644 app/Services/CheckinCsvExporter.php create mode 100644 resources/views/setting/export.blade.php diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index 78636a9..7ffcb25 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\DeactivatedUser; +use App\Services\CheckinCsvExporter; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; @@ -71,6 +72,36 @@ class SettingController extends Controller return redirect()->route('setting.privacy')->with('status', 'プライバシー設定を更新しました。'); } + public function export() + { + return view('setting.export'); + } + + public function exportToCsv(Request $request) + { + $validated = $request->validate([ + 'charset' => ['required', Rule::in(['utf8', 'sjis'])] + ]); + + $charsets = [ + 'utf8' => 'UTF-8', + 'sjis' => 'SJIS-win' + ]; + + $filename = tempnam(sys_get_temp_dir(), 'tissue_export_tmp_'); + try { + $exporter = new CheckinCsvExporter(Auth::user(), $filename, $charsets[$validated['charset']]); + $exporter->execute(); + } catch (\Throwable $e) { + unlink($filename); + throw $e; + } + + return response() + ->download($filename, 'TissueCheckin_' . date('Y-m-d_H-i-s') . '.csv') + ->deleteFileAfterSend(true); + } + public function deactivate() { return view('setting.deactivate'); diff --git a/app/Services/CheckinCsvExporter.php b/app/Services/CheckinCsvExporter.php new file mode 100644 index 0000000..ac38b56 --- /dev/null +++ b/app/Services/CheckinCsvExporter.php @@ -0,0 +1,57 @@ +user = $user; + $this->filename = $filename; + $this->charset = $charset; + } + + public function execute() + { + $csv = Writer::createFromPath($this->filename, 'wb'); + $csv->setNewline("\r\n"); + if ($this->charset === 'SJIS-win') { + $csv->addStreamFilter('convert.mbstring.encoding.UTF-8:SJIS-win'); + } + + $header = ['日時', 'ノート', 'オカズリンク']; + for ($i = 1; $i <= 32; $i++) { + $header[] = "タグ{$i}"; + } + $csv->insertOne($header); + + DB::transaction(function () use ($csv) { + // TODO: そんなに読み取り整合性を保つ努力はしていないのと、chunkの件数これでいいか分からない + $this->user->ejaculations()->with('tags')->orderBy('ejaculated_date') + ->chunk(1000, function ($ejaculations) use ($csv) { + foreach ($ejaculations as $ejaculation) { + $record = [ + $ejaculation->ejaculated_date->format('Y-m-d H:i'), + $ejaculation->note, + $ejaculation->link, + ]; + foreach ($ejaculation->tags as $tag) { + $record[] = $tag->name; + } + $csv->insertOne($record); + } + }); + }); + } +} diff --git a/resources/views/setting/base.blade.php b/resources/views/setting/base.blade.php index 2d53e94..1afa6b3 100644 --- a/resources/views/setting/base.blade.php +++ b/resources/views/setting/base.blade.php @@ -10,6 +10,8 @@ href="{{ route('setting') }}"> プロフィール プライバシー + データのエクスポート アカウントの削除 {{--データのエクスポート +
+

チェックインデータをCSVファイルとしてダウンロードすることができます。

+
+ {{ csrf_field() }} +
文字コード
+
+ +
+
+ +
+ +
+@endsection + +@push('script') +@endpush diff --git a/routes/web.php b/routes/web.php index 184bd18..7ee08fb 100644 --- a/routes/web.php +++ b/routes/web.php @@ -36,6 +36,8 @@ Route::middleware('auth')->group(function () { Route::post('/setting/profile', 'SettingController@updateProfile')->name('setting.profile.update'); Route::get('/setting/privacy', 'SettingController@privacy')->name('setting.privacy'); Route::post('/setting/privacy', 'SettingController@updatePrivacy')->name('setting.privacy.update'); + Route::get('/setting/export', 'SettingController@export')->name('setting.export'); + Route::get('/setting/export/csv', 'SettingController@exportToCsv')->name('setting.export.csv'); Route::get('/setting/deactivate', 'SettingController@deactivate')->name('setting.deactivate'); Route::post('/setting/deactivate', 'SettingController@destroyUser')->name('setting.deactivate.destroy'); // Route::get('/setting/password', 'SettingController@password')->name('setting.password');