]> git.localhorst.tv Git - alttp.git/commitdiff
public chat bot log
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 2 Sep 2024 16:16:00 +0000 (18:16 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 2 Sep 2024 16:16:00 +0000 (18:16 +0200)
app/Http/Controllers/ChatBotLogController.php [new file with mode: 0644]
app/Http/Controllers/SitemapXmlController.php
app/Models/ChatBotLog.php
resources/js/app/Routes.js
resources/js/components/channel/Link.js [new file with mode: 0644]
resources/js/components/chat-bot-logs/Item.js
resources/js/components/chat-bot-logs/List.js
resources/js/components/episodes/Channel.js
resources/js/pages/HorstieLog.js [new file with mode: 0644]
routes/api.php

diff --git a/app/Http/Controllers/ChatBotLogController.php b/app/Http/Controllers/ChatBotLogController.php
new file mode 100644 (file)
index 0000000..86bb690
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\ChatBotLog;
+use Illuminate\Http\Request;
+
+class ChatBotLogController extends Controller {
+
+       public function search(Request $request) {
+               $logs = ChatBotLog::with(['channel', 'origin', 'user'])->orderBy('created_at', 'DESC')->limit(50);
+               return $logs->get()->toJson();
+       }
+
+}
index c538bc447be7cfad8de6b462a89871a5b4e11277..f85e40ebb11cfb66e1923bb9db0e967c63915e92 100644 (file)
@@ -76,6 +76,13 @@ class SitemapXmlController extends Controller
                        $urls[] = $url;
                }
 
+               $url = new SitemapUrl();
+               $url->path = '/horstielog';
+               $url->lastmod = ChatBotLog::latest()->first()->created_at;
+               $url->changefreq = 'daily';
+               $url->priority = 0.5;
+               $urls[] = $url;
+
                return response()->view('sitemap', [
                        'urls' => $urls,
                ])->header('Content-Type', 'text/xml');
index a4f1f934b52abea3e0f5422ee47524d9a2fc088b..2819ee07a4881476fc7a7b60fe3683164c732d48 100644 (file)
@@ -2,13 +2,24 @@
 
 namespace App\Models;
 
+use Illuminate\Broadcasting\Channel as PublicChannel;
+use Illuminate\Database\Eloquent\BroadcastsEvents;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
 class ChatBotLog extends Model {
 
+       use BroadcastsEvents;
        use HasFactory;
 
+       public function broadcastOn($event) {
+               return new PublicChannel('ChatBotLog');
+       }
+
+       public function broadcastWith($event) {
+               $this->load(['channel', 'origin', 'user']);
+       }
+
        public function channel() {
                return $this->belongsTo(Channel::class);
        }
index 0e35ddb57180c383bb8ba6a1cb0c0a8c21f6ba4a..5e120040d41cb8410acd0eb5e904e29e3b1d0d4b 100644 (file)
@@ -53,6 +53,13 @@ const router = createBrowserRouter(
                                                '../pages/AlttpSeed'
                                        )}
                                />
+                               <Route
+                                       path="horstielog"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "horstie" */
+                                               '../pages/HorstieLog'
+                                       )}
+                               />
                                <Route
                                        path="locations"
                                        element={<Techniques namespace="locations" type="location" />}
diff --git a/resources/js/components/channel/Link.js b/resources/js/components/channel/Link.js
new file mode 100644 (file)
index 0000000..cb6cb79
--- /dev/null
@@ -0,0 +1,29 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+
+import Icon from '../common/Icon';
+
+const Link = ({ channel }) => {
+       return <Button
+               href={channel.stream_link}
+               rel="noreferer"
+               target="_blank"
+               title={channel.title}
+               variant="outline-twitch"
+       >
+               <Icon.STREAM />
+               &nbsp;
+               {channel.short_name || channel.title}
+       </Button>;
+};
+
+Link.propTypes = {
+       channel: PropTypes.shape({
+               short_name: PropTypes.string,
+               stream_link: PropTypes.string,
+               title: PropTypes.string,
+       }),
+};
+
+export default Link;
index 4c55c59c79ea4198b86d2f8d4b30a3d11352548a..9b4cfcb7a27a18015f75e50acee8c162da18af78 100644 (file)
@@ -4,6 +4,7 @@ import React from 'react';
 import { ListGroup } from 'react-bootstrap';
 import { useTranslation } from 'react-i18next';
 
+import ChannelLink from '../channel/Link';
 import { getUserName } from '../../helpers/User';
 
 const getEntryDate = entry => moment(entry.created_at).fromNow();
@@ -42,7 +43,7 @@ const getEntryInfo = (entry, t) => {
 const Item = ({ entry = {} }) => {
        const { t } = useTranslation();
 
-       return <ListGroup.Item>
+       return <ListGroup.Item className="d-flex justify-content-between">
                <div>
                        <div>
                                {entry.text}
@@ -61,11 +62,17 @@ const Item = ({ entry = {} }) => {
                                {getEntryInfo(entry, t)}
                        </div>
                </div>
+               {entry.channel ?
+                       <div>
+                               <ChannelLink channel={entry.channel} />
+                       </div>
+               : null}
        </ListGroup.Item>;
 };
 
 Item.propTypes = {
        entry: PropTypes.shape({
+               channel: PropTypes.shape({}),
                created_at: PropTypes.string,
                origin: PropTypes.shape({}),
                text: PropTypes.string,
index 0411299aa0393d47af8165aa3ac3dabe4b48f316..52a4de8763780a107924052757178693100ac8a4 100644 (file)
@@ -4,16 +4,37 @@ import { ListGroup } from 'react-bootstrap';
 
 import Item from './Item';
 
-const List = ({ log = [] }) =>
-       <ListGroup variant="flush">
-               {log ? log.map(entry =>
-                       <Item key={entry.id} entry={entry} />
-               ) : null}
-       </ListGroup>;
+class List extends React.Component {
+
+       componentDidMount() {
+               this.timer = setInterval(() => {
+                       this.forceUpdate();
+               }, 30000);
+       }
+
+       componentWillUnmount() {
+               clearInterval(this.timer);
+       }
+
+       render() {
+               const { log } = this.props;
+
+               return <ListGroup variant="flush">
+                       {log ? log.map(entry =>
+                               <Item key={entry.id} entry={entry} />
+                       ) : null}
+               </ListGroup>;
+       }
+
+}
 
 List.propTypes = {
        log: PropTypes.arrayOf(PropTypes.shape({
        })),
 };
 
+List.defaultProps = {
+       log: [],
+};
+
 export default List;
index e2d25d72bf209e59a69fc3d1ca36c79618a3f8cd..24569bea771df1d9ce694d3804abd3ed17774298 100644 (file)
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import { Button } from 'react-bootstrap';
 
+import Link from '../channel/Link';
 import Icon from '../common/Icon';
 import { mayEditRestream } from '../../helpers/permissions';
 import { useUser } from '../../hooks/user';
@@ -10,17 +11,7 @@ const Channel = ({ channel, episode, onEditRestream }) => {
        const { user } = useUser();
 
        return <div className="episode-channel text-nowrap">
-               <Button
-                       href={channel.stream_link}
-                       rel="noreferer"
-                       target="_blank"
-                       title={channel.title}
-                       variant="outline-twitch"
-               >
-                       <Icon.STREAM />
-                       {' '}
-                       {channel.short_name || channel.title}
-               </Button>
+               <Link channel={channel} />
                {onEditRestream && mayEditRestream(user, episode, channel) ?
                        <Button
                                className="ms-1"
diff --git a/resources/js/pages/HorstieLog.js b/resources/js/pages/HorstieLog.js
new file mode 100644 (file)
index 0000000..115b9fe
--- /dev/null
@@ -0,0 +1,64 @@
+import axios from 'axios';
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+
+import List from '../components/chat-bot-logs/List';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+
+export const Component = () => {
+       const [error, setError] = React.useState(null);
+       const [loading, setLoading] = React.useState(true);
+       const [log, setLog] = React.useState([]);
+
+       React.useEffect(() => {
+               const ctrl = new AbortController();
+               if (!log.length) {
+                       setLoading(true);
+               }
+               axios
+                       .get(`/api/chatbotlogs/`, {
+                               signal: ctrl.signal
+                       })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setLog(response.data);
+                       })
+                       .catch(error => {
+                               if (!axios.isCancel(error)) {
+                                       setError(error);
+                                       setLoading(false);
+                                       setLog([]);
+                               }
+                       });
+                       window.Echo.channel(`ChatBotLog`)
+                               .listen('.ChatBotLogCreated', (e) => {
+                                       setLog(l => [e.model, ...l]);
+                               });
+               return () => {
+                       ctrl.abort();
+                       window.Echo.leave(`ChatBotLog`);
+               };
+       }, []);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       return <Container>
+               <h1>Horstie Log</h1>
+               <Helmet>
+                       <title>Horstie Log</title>
+               </Helmet>
+               <ErrorBoundary>
+                       <List log={log} />
+               </ErrorBoundary>
+       </Container>;
+};
index 69a4bbfdc02f9159c52aeaa7bc0aca367011d944..e3ced1d98fb1f2222368228fdf0108ed1c446a84 100644 (file)
@@ -39,6 +39,8 @@ Route::put('channels/{channel}/guessing-game/{name}', 'App\Http\Controllers\Chan
 
 Route::get('guessing-game-monitor/{key}', 'App\Http\Controllers\ChannelController@getGuessingGameMonitor');
 
+Route::get('chatbotlogs', 'App\Http\Controllers\ChatBotLogController@search');
+
 Route::get('content', 'App\Http\Controllers\TechniqueController@search');
 Route::get('content/{tech:name}', 'App\Http\Controllers\TechniqueController@single');
 Route::put('content/{content}', 'App\Http\Controllers\TechniqueController@update');