diff options
| -rw-r--r-- | app/Http/Controllers/SiteController.php | 48 | ||||
| -rw-r--r-- | resources/css/home.css | 4 | ||||
| -rwxr-xr-x | resources/views/do.blade.php | 48 | ||||
| -rwxr-xr-x | resources/views/home.blade.php | 4 | ||||
| -rwxr-xr-x | resources/views/matrix.blade.php | 8 | ||||
| -rwxr-xr-x | routes/web.php | 29 |
6 files changed, 114 insertions, 27 deletions
diff --git a/app/Http/Controllers/SiteController.php b/app/Http/Controllers/SiteController.php index 301e101..3ef641a 100644 --- a/app/Http/Controllers/SiteController.php +++ b/app/Http/Controllers/SiteController.php @@ -198,4 +198,52 @@ class SiteController extends Controller } } + public function updateTodo(Request $req){ + $file = storage_path('app/todo.json'); + $items = file_exists($file) ? json_decode(file_get_contents($file), true) ?? [] : []; + $op = $req->input('op', 'append'); + + if ($op === 'overwrite') { + $lines = array_filter(array_map('trim', explode("\n", $req->input('content', '')))); + $items = array_values($lines); + } elseif ($op === 'delete') { + $index = (int) $req->input('index'); + array_splice($items, $index, 1); + } else { + // append (default) + $lines = array_filter(array_map('trim', explode("\n", $req->input('content', '')))); + $items = array_merge($items, $lines); + } + + file_put_contents($file, json_encode(array_values($items), JSON_PRETTY_PRINT)); + return redirect('/do')->with('status', 'List updated.'); + } + + public function updateTodoWithToken(Request $req){ + $token = $req->input('token', $req->header('X-Token')); + if (!$token || $token !== env('TODO_TOKEN')) { + abort(403, 'Invalid token.'); + } + + $file = storage_path('app/todo.json'); + $items = file_exists($file) ? json_decode(file_get_contents($file), true) ?? [] : []; + $op = $req->input('op', 'append'); + + if ($op === 'overwrite') { + $lines = array_filter(array_map('trim', explode("\n", $req->input('content', '')))); + $items = array_values($lines); + } elseif ($op === 'delete') { + $index = (int) $req->input('index'); + array_splice($items, $index, 1); + } elseif ($op === 'list') { + return response()->json($items); + } else { + $lines = array_filter(array_map('trim', explode("\n", $req->input('content', '')))); + $items = array_merge($items, $lines); + } + + file_put_contents($file, json_encode(array_values($items), JSON_PRETTY_PRINT)); + return response()->json(['status' => 'ok', 'count' => count($items), 'items' => $items]); + } + } diff --git a/resources/css/home.css b/resources/css/home.css index 3223a44..9977bd6 100644 --- a/resources/css/home.css +++ b/resources/css/home.css @@ -38,12 +38,12 @@ p .light { color: #787878; } section h3 { - color: #3f6d87; + color: #454545; text-decoration: none; } a { font-weight: bold; - color: #548226; + color: #676767; text-decoration: none; padding-bottom: .1rem; border-bottom: 1px dashed gray; diff --git a/resources/views/do.blade.php b/resources/views/do.blade.php new file mode 100755 index 0000000..246c522 --- /dev/null +++ b/resources/views/do.blade.php @@ -0,0 +1,48 @@ +@extends('template') +@section('content') +<main> + <section style="background-color: hsl(0, 0%, 72%); padding: 1rem;"> + <center> + <h2>To Do</h2> + </center> + </section> + + <section> + @if(Auth::check() && Auth::user()->isAdmin()) + <form method="POST" action="/do" style="margin-bottom: 1rem;"> + @csrf + <textarea name="content" rows="3" placeholder="Add a todo item…" style="width: 100%; font-family: monospace; padding: 0.5rem;">{{ old('content') }}</textarea> + <div style="margin-top: 0.5rem; display: flex; gap: 0.5rem;"> + <button type="submit" name="op" value="append">+ Append</button> + <button type="submit" name="op" value="overwrite" onclick="return confirm('This will replace the entire list. Continue?')">⤬ Overwrite</button> + </div> + </form> + @endif + + @if(session('status')) + <p style="color: green;">{{ session('status') }}</p> + @endif + </section> + + <section> + <h3>Current List</h3> + @if(count($items ?? []) === 0) + <p style="color: #888;"><em>Nothing here yet.</em></p> + @else + <ul style="font-family: monospace; line-height: 1.8;"> + @foreach($items as $i => $item) + <li> + <form method="POST" action="/do" style="display: inline;"> + @csrf + <input type="hidden" name="op" value="delete"> + <input type="hidden" name="index" value="{{ $i }}"> + <button type="submit" style="cursor:pointer; background:none; border:none; color:red;" title="Delete">✕</button> + </form> + {{ $item }} + </li> + @endforeach + </ul> + @endif + </section> +</main> +@endsection
\ No newline at end of file diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index d6ac6ec..4bd4b74 100755 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -11,7 +11,6 @@ <p>Welcome</p> <center> . . . </center> </section> -UNDER CONSTRUCTION; APOLOGIES FOR LACKING FUNCTIONALITY. <section id = "fileupload"> <div class = "widget" > <p>File upload capability temporarily disabled</p> @@ -32,6 +31,7 @@ UNDER CONSTRUCTION; APOLOGIES FOR LACKING FUNCTIONALITY. <br><small>40912129 ( goob )</small> </a></div> </secton> +<!-- <section> <div class="widget"> <div class="widget-header"> @@ -61,7 +61,7 @@ UNDER CONSTRUCTION; APOLOGIES FOR LACKING FUNCTIONALITY. </div> </div> </section> - +--> <section class = "widget" id = "dunechapterexcerpts" > <h4>Dune pre-chapter quotes: </h4> <div id = "quote" hx-get = "/dq" hx-trigger = "load,click" hx-swap = "innerHTML"> diff --git a/resources/views/matrix.blade.php b/resources/views/matrix.blade.php index b5deb92..95b10c1 100755 --- a/resources/views/matrix.blade.php +++ b/resources/views/matrix.blade.php @@ -3,8 +3,8 @@ <main> <section style="background-color: hsl(0, 0%, 72%); padding: 1rem; "> <center></center> - <br><h3><a href = "https://matrix.org/">Matrix Communications System</a></h3> - <h2>An open network for secure, decentralised communication</h2> + <br><h4><a href = "https://matrix.org/">Matrix Communications System</a></h4> + <h3>An open network for secure, decentralised communication</h3> </center> </section> <section> @@ -19,13 +19,13 @@ <h3>What is Matrix?</h3> <p> Matrix is an open standard and communication protocol for real-time messaging, voice, and video. - Think of it like email — but for instant messaging. Just like you can send an email from Gmail to + Think of it like email, but for instant messaging. Just like you can send an email from Gmail to a Yahoo address without either party needing to use the same service, Matrix lets you chat with anyone on any Matrix server, from your own account which exists on some server. </p> <p> You don't need to trust a corporation with your conversations. There's no single company running - Matrix — it's a <strong><a href = "https://www.geeksforgeeks.org/system-design/federated-architecture-system-design">federated</a>, <a href = "https://en.wikipedia.org/wiki/Decentralization"></a>decentralized network</a></strong>. Thousands of servers run + Matrix. It's a <a href = "https://www.geeksforgeeks.org/system-design/federated-architecture-system-design">federated</a>, <a href = "https://en.wikipedia.org/wiki/Decentralization">decentralized network</a>. Thousands of servers run independently and talk to each other. My server (<code>belthelziquor.com</code>) is one of them. </p> </section> diff --git a/routes/web.php b/routes/web.php index d98ed5d..6c44689 100755 --- a/routes/web.php +++ b/routes/web.php @@ -144,30 +144,21 @@ Route::get('/newtab', function() { return view('newtab'); }); -//Route::post('/do', function(Request $req) { +Route::get('/do', function(){ + $data = []; $file = storage_path('app/todo.json'); - $items = file_exists($file) ? json_decode(file_get_contents($file), true) ?? [] : []; - $op = $req->input('op', 'append'); - - if ($op === 'overwrite') { - $lines = array_filter(array_map('trim', explode("\n", $req->input('content', '')))); - $items = array_values($lines); - } elseif ($op === 'delete') { - $index = (int) $req->input('index'); - array_splice($items, $index, 1); - } else { - // append (default) - $lines = array_filter(array_map('trim', explode("\n", $req->input('content', '')))); - $items = array_merge($items, $lines); - } + $data['items'] = file_exists($file) ? json_decode(file_get_contents($file), true) ?? [] : []; + return view('do', $data); +}); - file_put_contents($file, json_encode(array_values($items), JSON_PRETTY_PRINT)); - return redirect('/do')->with('status', 'List updated.'); -})->middleware('auth'); +Route::post('/do', [SiteController::class, 'updateTodo'])->middleware('auth'); + +// API-style todo endpoint — token auth, no CSRF needed +Route::post('/api/do', [SiteController::class, 'updateTodoWithToken'])->middleware('throttle:public'); // Catch-all: only allow specific whitelisted views Route::get('/{v}', function($v){ - $allowed = ['notes', 'kyanite', 'marked', 'v', '4', 'matrix', 'psql', 'do']; + $allowed = ['notes', 'kyanite', 'marked', 'v', '4', 'matrix', 'psql']; if (!in_array($v, $allowed)) { abort(404); } |
