From: Hamatoma Date: Tue, 23 Apr 2024 20:13:00 +0000 (+0200) Subject: V 0.2.0 Module Article X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=7e1714545a8f95759cb14235bfb4a56433a38c49;p=gadeku.git V 0.2.0 Module Article - new: Module Article --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 7addaf4..77e2e0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# V 0.2.0 Module Article + +## Added +- Module Article + # V 0.1.9 Korrektur missing.seeders - missing.seeders: falsche Konfiguration (ohne "Seeder") diff --git a/app/Helpers/MediaWiki.php b/app/Helpers/MediaWiki.php new file mode 120000 index 0000000..d83989f --- /dev/null +++ b/app/Helpers/MediaWiki.php @@ -0,0 +1 @@ +../../vendor/hamatoma/laraknife/resources/helpers/MediaWiki.php \ No newline at end of file diff --git a/app/Helpers/TextProcessor.php b/app/Helpers/TextProcessor.php index e6ff8bb..f7478a5 100644 --- a/app/Helpers/TextProcessor.php +++ b/app/Helpers/TextProcessor.php @@ -3,43 +3,23 @@ namespace App\Helpers; class TextProcessor { - public static function markupToHtml(string $text): string + public static function expandStarItems(string $text): string { - $rc = ''; - $pos = 0; - while (true) { - if (($end = strpos($text, "\r\n\r\n", $pos)) !== false) { - $text2 = substr($text, $pos, $end); - $rc .= self::sentenceToHtml($text2); - $pos = $end + 4; - } else { - $text2 = substr($text, $pos); - if (!empty(trim($text2))) { - $rc .= self::sentenceToHtml($text2); - } - break; - } - } - return $rc; - } - public static function sentenceToHtml(string $text): string - { - $text2 = preg_replace_callback( - '/%trans\((.*?)(\|.*?)?\)%/', - function ($hit) { - $text = $hit[1]; - $info = count($hit) == 2 ? $text : substr($hit[2], 1); - $rc = "$text"; - return $rc; - }, + $rc = preg_replace( + [ + '/\*(\w[^*]+\w)\*/', + '/\*<(\w[^*]+\w)>\*/', + '/\*-(\w[^*]+\w)-\*/', + '/\*\+(\w[^*]+\w)\+\*/' + ], + [ + '%trans($1)%', + '%field($1)%', + '%del($1)%', + '%add($1)%' + ], $text ); - $rc = "

$text2

\n"; - return $rc; - } - public static function starToTrans(string $text): string - { - $rc = preg_replace('/\*(\w[^*]+\w)\*/', '%trans($1)%', $text); return $rc; } } diff --git a/app/Helpers/dummy.html b/app/Helpers/dummy.html new file mode 100644 index 0000000..e69de29 diff --git a/app/Http/Controllers/ArticleController.php b/app/Http/Controllers/ArticleController.php new file mode 100644 index 0000000..6f02c0b --- /dev/null +++ b/app/Http/Controllers/ArticleController.php @@ -0,0 +1,288 @@ +markup_scope; + switch ($type) { + case 1122: // mediawiki + $wiki = new MediaWiki(); + $text = $wiki->ToHtml($article->contents); + break; + case 1223: // html + $text = $article->contents; + break; + default: + case 1121: // plain text + $text = '

' . str_replace('/\r?\n/', "

\n

", $article->contents) . "

"; + break; + } + return $text; + } + /** + * Show the form for creating a new resource. + */ + public function create(Request $request) + { + if ($request->btnSubmit === 'btnCancel') { + $rc = redirect('/article-index'); + } else { + $fields = $request->all(); + if (count($fields) === 0) { + $fields = [ + 'title' => '', + 'contents' => '', + 'info' => '', + 'articletype_scope' => '', + 'markup_scope' => '1122', + 'order' => '0', + 'audio_id' => '' + ]; + } + $optionsArticletype = SProperty::optionsByScope('articletype', $fields['articletype_scope'], '-'); + $optionsMarkup = SProperty::optionsByScope('markup', $fields['markup_scope'], '-'); + $context = new ContextLaraKnife($request, $fields); + $rc = view('article.create', [ + 'context' => $context, + 'optionsArticletype' => $optionsArticletype, + 'optionsMarkup' => $optionsMarkup, + ]); + } + return $rc; + } + /** + * Show the form for editing the specified resource. + */ + public function edit(Article $article, Request $request) + { + if ($request->btnSubmit === 'btnCancel') { + $rc = redirect('/article-index'); + } elseif ($request->btnSubmit === 'btnStore') { + $rc = $this->update($article, $request); + } else { + $fields = $request->all(); + if (count($fields) === 0) { + $fields = [ + 'title' => $article->title, + 'contents' => $article->contents, + 'info' => $article->info, + 'articletype_scope' => $article->articletype_scope, + 'markup_scope' => $article->markup_scope, + 'order' => $article->order ?? '0', + 'audio_id' => $article->audio_id + ]; + } else { + $fields['articletype_scope'] = $article->articletype_scope; + $fields['markup_scope'] = $article->markup_scope; + } + $optionsArticletype = SProperty::optionsByScope('articletype', $article->articletype_scope, ''); + $optionsMarkup = SProperty::optionsByScope('markup', $article->markup_scope, ''); + $fields = $request->btnSubmit !== 'btnPreview' ? null : ['preview' => $this->asPreview($article)]; + $context = new ContextLaraKnife($request, $fields, $article); + $rc = view('article.edit', [ + 'context' => $context, + 'optionsArticletype' => $optionsArticletype, + 'optionsMarkup' => $optionsMarkup, + ]); + } + return $rc; + } + /** + * Remove the specified resource from storage. + */ + public function destroy(Article $article, Request $request) + { + if ($request->btnSubmit === 'btnDelete') { + $article->delete(); + } + return redirect('/article-index'); + } + /** + * Display the database records of the resource. + */ + public function index(Request $request) + { + if ($request->btnSubmit === 'btnNew') { + return redirect('/article-create'); + } else { + $sql = " +SELECT t0.*, + t1.name as articletype_scope, + t2.name as markup_scope, + t3.name as audio_id +FROM articles t0 +LEFT JOIN sproperties t1 ON t1.id=t0.articletype_scope +LEFT JOIN sproperties t2 ON t2.id=t0.markup_scope +LEFT JOIN sproperties t3 ON t3.id=t0.audio_id +"; + $parameters = []; + $fields = $request->all(); + if (count($fields) == 0) { + $fields = [ + 'articletype' => '', + 'markup' => '', + 'text' => '', + '_sortParams' => 'title:asc;id:asc' + ]; + } else { + $conditions = []; + ViewHelper::addConditionComparism($conditions, $parameters, 'articletype_scope', 'articletype'); + ViewHelper::addConditionComparism($conditions, $parameters, 'markup_scope', 'markup'); + ViewHelper::addConditionPattern($conditions, $parameters, 'title,info,contents', 'text'); + $sql = DbHelper::addConditions($sql, $conditions); + } + $sql = DbHelper::addOrderBy($sql, $fields['_sortParams']); + $pagination = new Pagination($sql, $parameters, $fields); + $records = $pagination->records; + $optionsArticletype = SProperty::optionsByScope('articletype', $fields['articletype'], 'all'); + $optionsMarkup = SProperty::optionsByScope('markup', $fields['markup'], 'all'); + $context = new ContextLaraKnife($request, $fields); + return view('article.index', [ + 'context' => $context, + 'records' => $records, + 'optionsArticletype' => $optionsArticletype, + 'optionsMarkup' => $optionsMarkup, + 'pagination' => $pagination + ]); + } + } + /** + * Returns the validation rules. + * @return array The validation rules. + */ + private function rules(bool $isCreate = false): array + { + $rc = [ + 'title' => 'required', + 'contents' => 'required', + 'info' => '', + 'order' => 'integer|min:0|max:9999' + ]; + if ($isCreate) { + $rc['markup_scope'] = 'required'; + $rc['articletype_scope'] = 'required'; + } + return $rc; + } + public static function routes() + { + Route::get('/article-index', [ArticleController::class, 'index'])->middleware('auth'); + Route::post('/article-index', [ArticleController::class, 'index'])->middleware('auth'); + Route::get('/article-create', [ArticleController::class, 'create'])->middleware('auth'); + Route::put('/article-store', [ArticleController::class, 'store'])->middleware('auth'); + Route::post('/article-edit/{article}', [ArticleController::class, 'edit'])->middleware('auth'); + Route::get('/article-edit/{article}', [ArticleController::class, 'edit'])->middleware('auth'); + Route::post('/article-update/{article}', [ArticleController::class, 'update'])->middleware('auth'); + Route::get('/article-show/{article}/delete', [ArticleController::class, 'show'])->middleware('auth'); + Route::delete('/article-show/{article}/delete', [ArticleController::class, 'destroy'])->middleware('auth'); + Route::get('/article-showpretty/{article}', [ArticleController::class, 'showPretty'])->middleware('auth'); + Route::post('/article-showpretty/{article}', [ArticleController::class, 'showPretty'])->middleware('auth'); + } + /** + * Display the specified resource. + */ + public function show(Article $article, Request $request) + { + if ($request->btnSubmit === 'btnCancel') { + $rc = redirect('/article-index')->middleware('auth'); + } else { + $optionsArticletype = SProperty::optionsByScope('articletype', $article->articletype_scope, ''); + $optionsMarkup = SProperty::optionsByScope('markup', $article->markup_scope, ''); + $context = new ContextLaraKnife($request, null, $article); + $rc = view('article.show', [ + 'context' => $context, + 'optionsArticletype' => $optionsArticletype, + 'optionsMarkup' => $optionsMarkup, + 'mode' => 'delete' + ]); + } + return $rc; + } + public function showPretty(Article $article, Request $request) + { + if ($request->btnSubmit === 'btnCancel') { + $rc = redirect('/article-index')->middleware('auth'); + } else { + $text = $this->asPreview($article); + $link = $article->audio_id == null ? null : File::relativeFileLink($article->audio_id); + $context = new ContextLaraKnife($request, ['text' => $text, 'link' => $link], $article); + $rc = view('article.showpretty', [ + 'context' => $context, + 'mode' => 'delete' + ]); + } + return $rc; + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $rc = null; + if ($request->btnSubmit === 'btnStore') { + $fields = $request->all(); + $validator = Validator::make($fields, $this->rules(true)); + if ($validator->fails()) { + $rc = back()->withErrors($validator)->withInput(); + } else { + $validated = $validator->validated(); + $validated['info'] = strip_tags($validated['info']); + $validated['contents'] = TextProcessor::expandStarItems(strip_tags($validated['contents'])); + Article::create($validated); + } + } + if ($rc == null) { + $rc = redirect('/article-index'); + } + return $rc; + } + /** + * Update the specified resource in storage. + */ + public function update(Article $article, Request $request) + { + $rc = null; + if ($request->btnSubmit === 'btnStore') { + $fields = $request->all(); + $validator = Validator::make($fields, $this->rules(false)); + if ($validator->fails()) { + $rc = back()->withErrors($validator)->withInput(); + } else { + $validated = $validator->validated(); + $validated['info'] = strip_tags($validated['info']); + if (empty($article->audio_id) && $request->file('file') != null) { + $filename = FileHelper::textToFilename($article->title); + $moduleId = Module::idOfModule('Article'); + $fileId = File::storeFile($request, $article->title, 1103, 1091, 'audio file of article', $filename, $moduleId, $article->id); + $validated['audio_id'] = $fileId; + } + $article->update($validated); + } + } + if ($rc == null) { + $rc = redirect("/article-edit/$article->id"); + } + return $rc; + } +} diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php index 6138b74..baefe29 100644 --- a/app/Http/Controllers/ChapterController.php +++ b/app/Http/Controllers/ChapterController.php @@ -178,7 +178,6 @@ class ChapterController extends Controller ]); } return $rc; - } /** * Store a newly created resource in storage. @@ -194,7 +193,7 @@ class ChapterController extends Controller } else { $validated = $validator->validated(); $validated['info'] = strip_tags($validated['info']); - $validated['contents'] = TextProcessor::starToTrans($validated['contents']); + $validated['contents'] = TextProcessor::expandStarItems(strip_tags($validated['contents'])); Chapter::create($validated); } } @@ -220,7 +219,7 @@ class ChapterController extends Controller $validated['contents'] = strip_tags($validated['contents']); if (empty($chapter->audio_id) && $request->file('file') != null) { $filename = FileHelper::textToFilename($chapter->title); - $moduleId = Module::idOfModule('chapter'); + $moduleId = Module::idOfModule('Chapter'); $fileId = File::storeFile($request, $chapter->title, 1103, 1091, 'audio file of chapter', $filename, $moduleId , $chapter->id); $validated['audio_id'] = $fileId; } diff --git a/app/Models/Article.php b/app/Models/Article.php new file mode 100644 index 0000000..2cd86c8 --- /dev/null +++ b/app/Models/Article.php @@ -0,0 +1,24 @@ +id(); + $table->timestamps(); + $table->string('title'); + $table->text('contents'); + $table->text('info')->nullable(); + $table->integer('articletype_scope'); + $table->integer('markup_scope'); + $table->integer('order')->nullable(); + $table->foreignId('audio_id')->nullable()->references('id')->on('files'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('articles'); + } +}; diff --git a/database/seeders/MenuitemArticleSeeder.php b/database/seeders/MenuitemArticleSeeder.php new file mode 100644 index 0000000..4680a8d --- /dev/null +++ b/database/seeders/MenuitemArticleSeeder.php @@ -0,0 +1,20 @@ +": "", "Adjective": "Adjektiv", +"Article": "Artikel", +"Articles": "Artikel", +"articletype": "Artikeltyp", +"Articletype": "Artikeltyp", +"Change of an Article": "Änderung eines Artikels", "Change of a Chapter": "Änderung eines Kapitels", "Change of a Noun": "Änderung eines Nomens", "Change of a Phrase": "Änderung eines Satzes", "Change of a Verb": "Änderung eines Verbs", "Change of a Word": "Änderung eines Wortes", +"chapter": "Kapitel", "Chapter": "Kapitel", "Chapters": "Kapitel", +"cloze text": "Lückentext", "Contents": "Inhalt", +"Creation of an Article": "Neuer Artikel", "Creation of a Chapter": "Neues Kapitel", "Creation of a Verb": "Neues Verb", +"Deletion of an Article": "Löschen eines Artikels", "Deletion of a Noun": "Löschen eines Nomens", "Deletion of a Verb": "Löschen eines Verbs", "Deletion of a Word": "Löschen eines Wortes", "feminine": "Femininum", +"free text": "Freier Text", "Genus": "Geschlecht", +"grammar rules": "Grammatikregeln", "Imperfect": "Imperfekt", "masculine": "Maskulinum", "neuter": "Neutrum", @@ -27,6 +38,7 @@ "Phrase": "Satz", "Phrases": "Sätze", "Preposition": "Präposition", +"snaketext": "Schlangentext", "Translation": "Übersetzung", "Verb": "Verb", "Verbs": "Verben", diff --git a/resources/views/article/create.blade.php b/resources/views/article/create.blade.php new file mode 100644 index 0000000..87a8715 --- /dev/null +++ b/resources/views/article/create.blade.php @@ -0,0 +1,19 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + @method('PUT') + + + + + + + +
+@endsection diff --git a/resources/views/article/edit.blade.php b/resources/views/article/edit.blade.php new file mode 100644 index 0000000..20e34a1 --- /dev/null +++ b/resources/views/article/edit.blade.php @@ -0,0 +1,27 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + + + + + + + + + + @if(! empty($context->valueOf('preview'))) +
{!! $context->valueOf('preview') !!} +
+ @endif +
+
+@endsection diff --git a/resources/views/article/index.blade.php b/resources/views/article/index.blade.php new file mode 100644 index 0000000..7395645 --- /dev/null +++ b/resources/views/article/index.blade.php @@ -0,0 +1,39 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + + + + + + + + + + + + {{__('Title')}} + {{__('Articletype')}} + {{__('Markup')}} + {{__('Order')}} + + + + +@foreach ($records as $article) + + + {{$article->title}} + {{ __($article->articletype_scope) }} + {{ __($article->markup_scope) }} + {{$article->order}} + + +@endforeach + + + +
+@endsection diff --git a/resources/views/article/show.blade.php b/resources/views/article/show.blade.php new file mode 100644 index 0000000..7010ef0 --- /dev/null +++ b/resources/views/article/show.blade.php @@ -0,0 +1,17 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + @if($mode === 'delete') + @method('DELETE') + @endif + + + + + + + +
+@endsection diff --git a/resources/views/article/showpretty.blade.php b/resources/views/article/showpretty.blade.php new file mode 100644 index 0000000..7506e3c --- /dev/null +++ b/resources/views/article/showpretty.blade.php @@ -0,0 +1,17 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + +
+ {!! $context->valueOf('text') !!} +
+
+ @if ($context->valueof('link') != null) +
+ +
+ @endif +
+@endsection diff --git a/resources/views/chapter/edit.blade.php b/resources/views/chapter/edit.blade.php index 4e425ba..621dff3 100644 --- a/resources/views/chapter/edit.blade.php +++ b/resources/views/chapter/edit.blade.php @@ -13,8 +13,7 @@ - + label="Audio" width2="10" /> @endsection diff --git a/resources/views/create.blade.php b/resources/views/create.blade.php new file mode 100644 index 0000000..19424ad --- /dev/null +++ b/resources/views/create.blade.php @@ -0,0 +1,11 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + @method('PUT') + + + +
+@endsection diff --git a/resources/views/edit.blade.php b/resources/views/edit.blade.php new file mode 100644 index 0000000..e9d8bca --- /dev/null +++ b/resources/views/edit.blade.php @@ -0,0 +1,10 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + + + +
+@endsection diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php new file mode 100644 index 0000000..a1eb450 --- /dev/null +++ b/resources/views/index.blade.php @@ -0,0 +1,28 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + + + + + + + + + + + + +@foreach ($records as $) + + + + +@endforeach + + + +
+@endsection diff --git a/resources/views/show.blade.php b/resources/views/show.blade.php new file mode 100644 index 0000000..f0227f7 --- /dev/null +++ b/resources/views/show.blade.php @@ -0,0 +1,13 @@ +@extends('layouts.backend') + +@section('content') +
+ @csrf + @if($mode === 'delete') + @method('DELETE') + @endif + + + +
+@endsection diff --git a/routes/web.php b/routes/web.php index 5662c04..0c8298b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -13,6 +13,7 @@ use App\Http\Controllers\PhraseController; use App\Http\Controllers\ReviewController; use App\Http\Controllers\MenuitemController; use App\Http\Controllers\ChapterController; +use App\Http\Controllers\ArticleController; use App\Http\Controllers\SPropertyController; Route::get('/', function () { @@ -35,3 +36,5 @@ PhraseController::routes(); ReviewController::routes(); ChapterController::routes(); + +ArticleController::routes();