mirror of
https://github.com/mgerb/go-discord-bot
synced 2026-01-09 16:42:48 +00:00
@@ -2,7 +2,7 @@ import { Provider } from 'mobx-react';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
||||||
import { Admin, Clips, Downloader, NotFound, Oauth, Soundboard, Stats, VideoArchive } from './pages';
|
import { Admin, Clips, Downloader, NotFound, Oauth, Soundboard, Stats, UploadHistory, VideoArchive } from './pages';
|
||||||
import './scss/index.scss';
|
import './scss/index.scss';
|
||||||
import { rootStoreInstance } from './stores';
|
import { rootStoreInstance } from './stores';
|
||||||
import { Wrapper } from './wrapper';
|
import { Wrapper } from './wrapper';
|
||||||
@@ -14,6 +14,7 @@ const App: any = (): any => {
|
|||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/" component={Soundboard} />
|
<Route exact path="/" component={Soundboard} />
|
||||||
|
<Route path="/upload-history" component={UploadHistory} />
|
||||||
<Route path="/downloader" component={Downloader} />
|
<Route path="/downloader" component={Downloader} />
|
||||||
<Route path="/clips" component={Clips} />
|
<Route path="/clips" component={Clips} />
|
||||||
<Route path="/oauth" component={Oauth} />
|
<Route path="/oauth" component={Oauth} />
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SoundService } from '../../services';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
sound: SoundType;
|
||||||
|
type: 'sounds' | 'clips';
|
||||||
|
showDiscordPlay?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {}
|
||||||
|
|
||||||
|
export interface SoundType {
|
||||||
|
extension: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClipPlayerControl extends React.Component<IProps, IState> {
|
||||||
|
checkExtension(extension: string) {
|
||||||
|
switch (extension) {
|
||||||
|
case 'wav':
|
||||||
|
return true;
|
||||||
|
case 'mp3':
|
||||||
|
return true;
|
||||||
|
case 'mpeg':
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePlayAudioInBrowser(sound: SoundType, type: string) {
|
||||||
|
const url = `/public/${type.toLowerCase()}/` + sound.name + '.' + sound.extension;
|
||||||
|
const audio = new Audio(url);
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlayDiscord = (sound: SoundType) => {
|
||||||
|
SoundService.playSound(sound);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { sound, showDiscordPlay, type } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.checkExtension(sound.extension) && (
|
||||||
|
<div className="flex flex--center">
|
||||||
|
<a
|
||||||
|
href={`/public/${type.toLowerCase()}/` + sound.name + '.' + sound.extension}
|
||||||
|
download
|
||||||
|
title="Download"
|
||||||
|
className="fa fa-download link"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
title="Play in browser"
|
||||||
|
className="fa fa-play link"
|
||||||
|
aria-hidden="true"
|
||||||
|
style={{ paddingLeft: '15px' }}
|
||||||
|
onClick={() => this.handlePlayAudioInBrowser(sound, type)}
|
||||||
|
/>
|
||||||
|
{showDiscordPlay && (
|
||||||
|
<i
|
||||||
|
title="Play in discord"
|
||||||
|
className="fa fa-play-circle link fa-lg"
|
||||||
|
aria-hidden="true"
|
||||||
|
style={{ paddingLeft: '10px' }}
|
||||||
|
onClick={() => this.onPlayDiscord(sound)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,5 +2,4 @@ export * from './embedded-youtube/embedded-youtube';
|
|||||||
export * from './header/header';
|
export * from './header/header';
|
||||||
export * from './navbar/navbar';
|
export * from './navbar/navbar';
|
||||||
export * from './sound-list/sound-list';
|
export * from './sound-list/sound-list';
|
||||||
export * from './upload-history/upload-history';
|
|
||||||
export * from './uploader/uploader';
|
export * from './uploader/uploader';
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom';
|
||||||
import { IClaims, Permissions } from '../../model';
|
|
||||||
import { OauthService, StorageService } from '../../services';
|
import { OauthService, StorageService } from '../../services';
|
||||||
|
import { AppStore } from '../../stores';
|
||||||
import './navbar.scss';
|
import './navbar.scss';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
claims?: IClaims;
|
appStore: AppStore;
|
||||||
open: boolean;
|
|
||||||
onNavClick: () => void;
|
onNavClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ export class Navbar extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderLoginButton() {
|
renderLoginButton() {
|
||||||
const { claims } = this.props;
|
const { claims } = this.props.appStore;
|
||||||
|
|
||||||
if (!this.state.oauthUrl) {
|
if (!this.state.oauthUrl) {
|
||||||
return null;
|
return null;
|
||||||
@@ -69,19 +68,17 @@ export class Navbar extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { claims, open } = this.props;
|
const { claims, navbarOpen, hasModPermissions, hasAdminPermissions } = this.props.appStore;
|
||||||
const openClass = open ? 'navbar--open' : '';
|
const openClass = navbarOpen ? 'navbar--open' : '';
|
||||||
return (
|
return (
|
||||||
<div className={'navbar ' + openClass}>
|
<div className={'navbar ' + openClass}>
|
||||||
{this.renderNavLink('Soundboard', '/', { exact: true })}
|
{this.renderNavLink('Soundboard', '/', { exact: true })}
|
||||||
|
{hasModPermissions() && this.renderNavLink('Upload History', '/upload-history')}
|
||||||
{this.renderNavLink('Video Archive', '/video-archive')}
|
{this.renderNavLink('Video Archive', '/video-archive')}
|
||||||
{this.renderNavLink('Youtube Downloader', '/downloader')}
|
{this.renderNavLink('Youtube Downloader', '/downloader')}
|
||||||
{this.renderNavLink('Clips', '/clips')}
|
{this.renderNavLink('Clips', '/clips')}
|
||||||
{this.renderNavLink('Stats', '/stats')}
|
{this.renderNavLink('Stats', '/stats')}
|
||||||
{claims &&
|
{hasAdminPermissions() && this.renderNavLink('Admin', '/admin')}
|
||||||
claims.permissions &&
|
|
||||||
claims.permissions === Permissions.Admin &&
|
|
||||||
this.renderNavLink('Admin', '/admin')}
|
|
||||||
{this.renderLoginButton()}
|
{this.renderLoginButton()}
|
||||||
|
|
||||||
{claims && claims.email && <div className="navbar__email">{claims.email}</div>}
|
{claims && claims.email && <div className="navbar__email">{claims.email}</div>}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ClipPlayerControl } from '../clip-player-control/clip-player-control';
|
||||||
import './sound-list.scss';
|
import './sound-list.scss';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
soundList: SoundType[];
|
soundList: SoundType[];
|
||||||
type: string;
|
type: 'sounds' | 'clips';
|
||||||
|
title: string;
|
||||||
onPlayDiscord?: (sound: SoundType) => void;
|
onPlayDiscord?: (sound: SoundType) => void;
|
||||||
showDiscordPlay?: boolean;
|
showDiscordPlay?: boolean;
|
||||||
}
|
}
|
||||||
@@ -46,13 +48,13 @@ export class SoundList extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { onPlayDiscord, showDiscordPlay, soundList, type } = this.props;
|
const { showDiscordPlay, soundList, title, type } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card__header" style={{ display: 'flex' }}>
|
<div className="card__header" style={{ display: 'flex' }}>
|
||||||
<div>
|
<div>
|
||||||
<span>{type}</span>
|
<span>{title}</span>
|
||||||
<i className="fa fa fa-volume-up" aria-hidden="true" />
|
<i className="fa fa fa-volume-up" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1 }} />
|
<div style={{ flex: 1 }} />
|
||||||
@@ -63,43 +65,11 @@ export class SoundList extends React.Component<Props, State> {
|
|||||||
? soundList.map((sound: SoundType, index: number) => {
|
? soundList.map((sound: SoundType, index: number) => {
|
||||||
return (
|
return (
|
||||||
<div key={index} className="sound-list__item">
|
<div key={index} className="sound-list__item">
|
||||||
<div className="text-wrap">{(sound.prefix || '') + sound.name}</div>
|
<div className="text-wrap">
|
||||||
|
{(type === 'sounds' && sound.prefix ? sound.prefix : '') + sound.name}
|
||||||
|
</div>
|
||||||
|
|
||||||
{this.checkExtension(sound.extension) && this.state.showAudioControls[index] ? (
|
<ClipPlayerControl showDiscordPlay={showDiscordPlay} sound={sound} type={type} />
|
||||||
<audio
|
|
||||||
controls
|
|
||||||
src={`/public/${type.toLowerCase()}/` + sound.name + '.' + sound.extension}
|
|
||||||
itemType={'audio/' + sound.extension}
|
|
||||||
style={{ width: '100px' }}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
<a
|
|
||||||
href={`/public/${type.toLowerCase()}/` + sound.name + '.' + sound.extension}
|
|
||||||
download
|
|
||||||
title="Download"
|
|
||||||
className="fa fa-download link"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
title="Play in browser"
|
|
||||||
className="fa fa-play link"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ paddingLeft: '15px' }}
|
|
||||||
onClick={() => this.handlePlayAudioInBrowser(sound, type)}
|
|
||||||
/>
|
|
||||||
{showDiscordPlay &&
|
|
||||||
onPlayDiscord && (
|
|
||||||
<i
|
|
||||||
title="Play in discord"
|
|
||||||
className="fa fa-play-circle link fa-lg"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ paddingLeft: '10px' }}
|
|
||||||
onClick={() => onPlayDiscord!(sound)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import * as _ from 'lodash';
|
|
||||||
import { DateTime } from 'luxon';
|
|
||||||
import React from 'react';
|
|
||||||
import { ISound } from '../../model';
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
sounds: ISound[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UploadHistory = ({ sounds }: IProps) => {
|
|
||||||
const sortedSounds = _.orderBy(sounds, 'created_at', 'desc');
|
|
||||||
return (
|
|
||||||
<div className="card">
|
|
||||||
<div className="card__header">Upload History</div>
|
|
||||||
<table className="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Date</th>
|
|
||||||
<th>Sound</th>
|
|
||||||
<th className="hide-tiny">Ext</th>
|
|
||||||
<th>Username</th>
|
|
||||||
<th className="hide-tiny">Email</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{sortedSounds.map((s: ISound, i) => {
|
|
||||||
const formattedDate = DateTime.fromISO(s.created_at).toLocaleString();
|
|
||||||
return (
|
|
||||||
<tr key={i}>
|
|
||||||
<td title={formattedDate}>{formattedDate}</td>
|
|
||||||
<td title={s.name}>{s.name}</td>
|
|
||||||
<td className="hide-tiny" title={s.extension}>
|
|
||||||
{s.extension}
|
|
||||||
</td>
|
|
||||||
<td title={s.user.username}>{s.user.username}</td>
|
|
||||||
<td className="hide-tiny" title={s.user.email}>
|
|
||||||
{s.user.email}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -2,4 +2,5 @@ export * from './claims';
|
|||||||
export * from './permissions';
|
export * from './permissions';
|
||||||
export * from './sound';
|
export * from './sound';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
|
export * from './user-event-log';
|
||||||
export * from './video-archive';
|
export * from './video-archive';
|
||||||
|
|||||||
11
client/app/model/user-event-log.ts
Normal file
11
client/app/model/user-event-log.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { IUser } from './user';
|
||||||
|
|
||||||
|
export interface IUserEventLog {
|
||||||
|
content: string;
|
||||||
|
created_at: string;
|
||||||
|
deleted_at?: string;
|
||||||
|
id: number;
|
||||||
|
updated_at: string;
|
||||||
|
user: IUser;
|
||||||
|
user_id: string;
|
||||||
|
}
|
||||||
@@ -1,11 +1,59 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { IUserEventLog } from '../../model';
|
||||||
|
import { UserEventLogService } from '../../services';
|
||||||
|
|
||||||
interface IProps {}
|
interface IProps {}
|
||||||
|
|
||||||
interface IState {}
|
interface IState {
|
||||||
|
userEventLogs: IUserEventLog[];
|
||||||
|
}
|
||||||
|
|
||||||
export class Admin extends React.Component<IProps, IState> {
|
export class Admin extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
userEventLogs: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
UserEventLogService.getUserEventLogs().then(userEventLogs => {
|
||||||
|
this.setState({
|
||||||
|
userEventLogs,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderUserEventLogs() {
|
||||||
|
return this.state.userEventLogs.map(({ id, user, content, created_at }, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{id}</td>
|
||||||
|
<td>{created_at}</td>
|
||||||
|
<td>{user.username}</td>
|
||||||
|
<td>{content}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div className="content">TODO:</div>;
|
return (
|
||||||
|
<div className="content">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card__header">User Event Log</div>
|
||||||
|
<table className="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>User</th>
|
||||||
|
<th>Content</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>{this.renderUserEventLogs()}</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class Clips extends React.Component<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<SoundList soundList={this.state.clipList} type="Clips" />
|
<SoundList soundList={this.state.clipList} type="clips" title="Clips" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ export * from './not-found/not-found';
|
|||||||
export * from './oauth/oauth';
|
export * from './oauth/oauth';
|
||||||
export * from './soundboard/soundboard';
|
export * from './soundboard/soundboard';
|
||||||
export * from './stats/stats';
|
export * from './stats/stats';
|
||||||
|
export * from './upload-history/upload-history';
|
||||||
export * from './video-archive/video-archive';
|
export * from './video-archive/video-archive';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SoundList, SoundType, Uploader } from '../../components';
|
import { SoundList, SoundType, Uploader } from '../../components';
|
||||||
import { Permissions } from '../../model';
|
|
||||||
import { axios, SoundService } from '../../services';
|
import { axios, SoundService } from '../../services';
|
||||||
import { AppStore } from '../../stores';
|
import { AppStore } from '../../stores';
|
||||||
import './soundboard.scss';
|
import './soundboard.scss';
|
||||||
@@ -73,9 +72,10 @@ export class Soundboard extends React.Component<Props, State> {
|
|||||||
<Uploader onComplete={this.onUploadComplete} />
|
<Uploader onComplete={this.onUploadComplete} />
|
||||||
<SoundList
|
<SoundList
|
||||||
soundList={soundList}
|
soundList={soundList}
|
||||||
type="Sounds"
|
title="Sounds"
|
||||||
|
type="sounds"
|
||||||
onPlayDiscord={this.onPlayDiscord}
|
onPlayDiscord={this.onPlayDiscord}
|
||||||
showDiscordPlay={appStore!.claims && appStore!.claims!.permissions >= Permissions.Mod}
|
showDiscordPlay={appStore!.hasModPermissions()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { chain, map } from 'lodash';
|
import { chain, map } from 'lodash';
|
||||||
import { inject, observer } from 'mobx-react';
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { HorizontalBar } from 'react-chartjs-2';
|
import { HorizontalBar } from 'react-chartjs-2';
|
||||||
import { UploadHistory } from '../../components';
|
|
||||||
import { ISound } from '../../model';
|
import { ISound } from '../../model';
|
||||||
import { axios, SoundService } from '../../services';
|
import { axios, SoundService } from '../../services';
|
||||||
import { AppStore } from '../../stores';
|
|
||||||
import './stats.scss';
|
import './stats.scss';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {}
|
||||||
appStore: AppStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
data: {
|
data: {
|
||||||
@@ -24,8 +19,6 @@ interface IState {
|
|||||||
* a page to show discord chat statistics
|
* a page to show discord chat statistics
|
||||||
* currently keeps track of number messages that contain external links
|
* currently keeps track of number messages that contain external links
|
||||||
*/
|
*/
|
||||||
@inject('appStore')
|
|
||||||
@observer
|
|
||||||
export class Stats extends Component<IProps, IState> {
|
export class Stats extends Component<IProps, IState> {
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -74,15 +67,12 @@ export class Stats extends Component<IProps, IState> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const { claims } = this.props.appStore;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card__header">Posts containing links</div>
|
<div className="card__header">Posts containing links</div>
|
||||||
<HorizontalBar data={data} />
|
<HorizontalBar data={data} />
|
||||||
</div>
|
</div>
|
||||||
{claims && <UploadHistory sounds={this.state.sounds} />}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
81
client/app/pages/upload-history/upload-history.tsx
Normal file
81
client/app/pages/upload-history/upload-history.tsx
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import orderBy from 'lodash/orderBy';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import React from 'react';
|
||||||
|
import { ClipPlayerControl } from '../../components/clip-player-control/clip-player-control';
|
||||||
|
import { ISound } from '../../model';
|
||||||
|
import { SoundService } from '../../services';
|
||||||
|
import { AppStore } from '../../stores';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
appStore: AppStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
sounds: ISound[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@inject('appStore')
|
||||||
|
@observer
|
||||||
|
export class UploadHistory extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
sounds: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
SoundService.getSounds().then(sounds => {
|
||||||
|
this.setState({ sounds });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderUploadHistory = (sounds: ISound[], showDiscordPlay: boolean) => {
|
||||||
|
const sortedSounds = orderBy(sounds, 'created_at', 'desc');
|
||||||
|
return (
|
||||||
|
<div className="card">
|
||||||
|
<div className="card__header">Upload History</div>
|
||||||
|
<table className="table table--ellipsis">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className="hide-small">Date</th>
|
||||||
|
<th>Sound</th>
|
||||||
|
<th className="hide-small">Ext</th>
|
||||||
|
<th>User</th>
|
||||||
|
<th className="hide-small">Email</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{sortedSounds.map((s: ISound, i) => {
|
||||||
|
const formattedDate = DateTime.fromISO(s.created_at).toLocaleString();
|
||||||
|
return (
|
||||||
|
<tr key={i}>
|
||||||
|
<td className="hide-small" title={formattedDate}>
|
||||||
|
{formattedDate}
|
||||||
|
</td>
|
||||||
|
<td title={s.name}>{s.name}</td>
|
||||||
|
<td className="hide-small" title={s.extension}>
|
||||||
|
{s.extension}
|
||||||
|
</td>
|
||||||
|
<td title={s.user.username}>{s.user.username}</td>
|
||||||
|
<td className="hide-small" title={s.user.email}>
|
||||||
|
{s.user.email}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ClipPlayerControl showDiscordPlay={showDiscordPlay} sound={s} type="sounds"></ClipPlayerControl>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
public render() {
|
||||||
|
const { hasModPermissions } = this.props.appStore;
|
||||||
|
const { sounds } = this.state;
|
||||||
|
return <div className="content">{this.renderUploadHistory(sounds, hasModPermissions())}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,10 +32,19 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex--center {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.flex--v-center {
|
.flex--v-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex--h-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@include tinyScreen {
|
@include tinyScreen {
|
||||||
@@ -77,3 +86,9 @@ body {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide-small {
|
||||||
|
@include smallScreen {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,13 @@
|
|||||||
thead {
|
thead {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
padding: 10px 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table--ellipsis {
|
||||||
td,
|
td,
|
||||||
th {
|
th {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export * from './axios.service';
|
|||||||
export * from './oauth.service';
|
export * from './oauth.service';
|
||||||
export * from './sound.service';
|
export * from './sound.service';
|
||||||
export * from './storage.service';
|
export * from './storage.service';
|
||||||
|
export * from './user-event-log.service';
|
||||||
|
|||||||
9
client/app/services/user-event-log.service.ts
Normal file
9
client/app/services/user-event-log.service.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { IUserEventLog } from '../model';
|
||||||
|
import { axios } from './axios.service';
|
||||||
|
|
||||||
|
export class UserEventLogService {
|
||||||
|
public static async getUserEventLogs(): Promise<IUserEventLog[]> {
|
||||||
|
const resp = await axios.get('/api/user-event-log');
|
||||||
|
return resp.data.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import jwt_decode from 'jwt-decode';
|
import jwt_decode from 'jwt-decode';
|
||||||
import { action, observable } from 'mobx';
|
import { action, observable } from 'mobx';
|
||||||
import { IClaims } from '../model';
|
import { IClaims, Permissions } from '../model';
|
||||||
import { axios, StorageService } from '../services';
|
import { axios, StorageService } from '../services';
|
||||||
import { Util } from '../util';
|
import { Util } from '../util';
|
||||||
|
|
||||||
@@ -40,4 +40,12 @@ export class AppStore {
|
|||||||
public toggleNavbar = () => {
|
public toggleNavbar = () => {
|
||||||
this.navbarOpen = !this.navbarOpen;
|
this.navbarOpen = !this.navbarOpen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public hasModPermissions = (): boolean => {
|
||||||
|
return !!this.claims && this.claims.permissions >= Permissions.Mod;
|
||||||
|
};
|
||||||
|
|
||||||
|
public hasAdminPermissions = (): boolean => {
|
||||||
|
return !!this.claims && this.claims.permissions >= Permissions.Admin;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const Wrapper = inject('appStore')(
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Header onButtonClick={appStore.toggleNavbar} />
|
<Header onButtonClick={appStore.toggleNavbar} />
|
||||||
<Navbar claims={appStore.claims} open={appStore.navbarOpen} onNavClick={onNavClick} />
|
<Navbar appStore={appStore} onNavClick={onNavClick} />
|
||||||
<div className={'wrapper ' + openClass}>{children}</div>
|
<div className={'wrapper ' + openClass}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
24
client/package-lock.json
generated
24
client/package-lock.json
generated
@@ -20,9 +20,9 @@
|
|||||||
"integrity": "sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A=="
|
"integrity": "sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A=="
|
||||||
},
|
},
|
||||||
"@types/lodash": {
|
"@types/lodash": {
|
||||||
"version": "4.14.110",
|
"version": "4.14.137",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.110.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.137.tgz",
|
||||||
"integrity": "sha512-iXYLa6olt4tnsCA+ZXeP6eEW3tk1SulWeYyP/yooWfAtXjozqXgtX4+XUtMuOCfYjKGz3F34++qUc3Q+TJuIIw=="
|
"integrity": "sha512-g4rNK5SRKloO+sUGbuO7aPtwbwzMgjK+bm9BBhLD7jGUiGR7zhwYEhSln/ihgYQBeIJ5j7xjyaYzrWTcu3UotQ=="
|
||||||
},
|
},
|
||||||
"@types/luxon": {
|
"@types/luxon": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
@@ -5405,9 +5405,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.10",
|
"version": "4.17.15",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||||
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
|
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||||
},
|
},
|
||||||
"lodash.assign": {
|
"lodash.assign": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
@@ -6237,9 +6237,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"normalize.css": {
|
"normalize.css": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
|
||||||
"integrity": "sha512-iXcbM3NWr0XkNyfiSBsoPezi+0V92P9nj84yVV1/UZxRUrGczgX/X91KMAGM0omWLY2+2Q1gKD/XRn4gQRDB2A=="
|
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
|
||||||
},
|
},
|
||||||
"npm-run-path": {
|
"npm-run-path": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
@@ -7983,9 +7983,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-chartjs-2": {
|
"react-chartjs-2": {
|
||||||
"version": "2.7.2",
|
"version": "2.7.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.7.6.tgz",
|
||||||
"integrity": "sha512-ncTSOZjlI9j3aXGbsiXEoCtb6oS5nixYe9wLWK+3af1aq7K/vcFkzA9faA5Z/q+fgMDWLEa078cWAyzymxvvYg==",
|
"integrity": "sha512-xDr0jhgt/o26atftXxTVsepz+QYZI2GNKBYpxtLvYgwffLUm18a9n562reUJAHvuwKsy2v+qMlK5HyjFtSW0mg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"prop-types": "^15.5.8"
|
"prop-types": "^15.5.8"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/chart.js": "^2.7.22",
|
"@types/chart.js": "^2.7.22",
|
||||||
"@types/jwt-decode": "^2.2.1",
|
"@types/jwt-decode": "^2.2.1",
|
||||||
"@types/lodash": "^4.14.110",
|
"@types/lodash": "^4.14.137",
|
||||||
"@types/luxon": "^1.2.2",
|
"@types/luxon": "^1.2.2",
|
||||||
"@types/node": "^10.3.4",
|
"@types/node": "^10.3.4",
|
||||||
"@types/nprogress": "0.0.29",
|
"@types/nprogress": "0.0.29",
|
||||||
@@ -39,18 +39,18 @@
|
|||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"jwt-decode": "^2.2.0",
|
"jwt-decode": "^2.2.0",
|
||||||
"lodash": "^4.17.10",
|
"lodash": "^4.17.15",
|
||||||
"luxon": "^1.3.3",
|
"luxon": "^1.3.3",
|
||||||
"mini-css-extract-plugin": "^0.4.2",
|
"mini-css-extract-plugin": "^0.4.2",
|
||||||
"mobx": "^5.0.3",
|
"mobx": "^5.0.3",
|
||||||
"mobx-react": "^5.2.5",
|
"mobx-react": "^5.2.5",
|
||||||
"node-sass": "^4.9.3",
|
"node-sass": "^4.9.3",
|
||||||
"normalize.css": "^8.0.0",
|
"normalize.css": "^8.0.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"postcss-loader": "^2.1.5",
|
"postcss-loader": "^2.1.5",
|
||||||
"query-string": "^6.1.0",
|
"query-string": "^6.1.0",
|
||||||
"react": "^16.4.1",
|
"react": "^16.4.1",
|
||||||
"react-chartjs-2": "^2.7.2",
|
"react-chartjs-2": "^2.7.6",
|
||||||
"react-dom": "^16.4.1",
|
"react-dom": "^16.4.1",
|
||||||
"react-dropzone": "^4.2.11",
|
"react-dropzone": "^4.2.11",
|
||||||
"react-router-dom": "^4.3.1",
|
"react-router-dom": "^4.3.1",
|
||||||
|
|||||||
92
server/Gopkg.lock
generated
92
server/Gopkg.lock
generated
@@ -2,226 +2,306 @@
|
|||||||
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:a62f6ed230a8cd138a9efbe718e7d0b0294f139266f5f55cd942769a9aac8de2"
|
||||||
name = "github.com/PuerkitoBio/goquery"
|
name = "github.com/PuerkitoBio/goquery"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "dc2ec5c7ca4d9aae063b79b9f581dd3ea6afd2b2"
|
revision = "dc2ec5c7ca4d9aae063b79b9f581dd3ea6afd2b2"
|
||||||
version = "v1.4.1"
|
version = "v1.4.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:66b3310cf22cdc96c35ef84ede4f7b9b370971c4025f394c89a2638729653b11"
|
||||||
name = "github.com/andybalholm/cascadia"
|
name = "github.com/andybalholm/cascadia"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "901648c87902174f774fac311d7f176f8647bdaa"
|
revision = "901648c87902174f774fac311d7f176f8647bdaa"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:4fd5ce7844c22e194005b9e12fee8adc70fb5ba0bbba9e1964d2e3d1f301d789"
|
||||||
name = "github.com/bwmarrin/discordgo"
|
name = "github.com/bwmarrin/discordgo"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "4a33b9bc7c56cfdb9bb244e33e83cb3941fe2bdc"
|
revision = "4a33b9bc7c56cfdb9bb244e33e83cb3941fe2bdc"
|
||||||
version = "v0.18.0"
|
version = "v0.18.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:36fe9527deed01d2a317617e59304eb2c4ce9f8a24115bcc5c2e37b3aee5bae4"
|
||||||
name = "github.com/gin-contrib/sse"
|
name = "github.com/gin-contrib/sse"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
|
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:d5083934eb25e45d17f72ffa86cae3814f4a9d6c073c4f16b64147169b245606"
|
||||||
name = "github.com/gin-gonic/gin"
|
name = "github.com/gin-gonic/gin"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"binding",
|
"binding",
|
||||||
"json",
|
"json",
|
||||||
"render"
|
"render",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "b869fe1415e4b9eb52f247441830d502aece2d4d"
|
revision = "b869fe1415e4b9eb52f247441830d502aece2d4d"
|
||||||
version = "v1.3.0"
|
version = "v1.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:602a78a9834f7b1f67186a69970dc0f5f6f9557ef52fd786586e5be14f5a6ed6"
|
||||||
name = "github.com/go-audio/audio"
|
name = "github.com/go-audio/audio"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "b697a35b5608fcf1c4f90a9d4f33d76bd70e8fe6"
|
revision = "b697a35b5608fcf1c4f90a9d4f33d76bd70e8fe6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:505ceb99060820f1c99a687795774a1df5a6fd4a3a5dbb4eb915bff3ac3a94d7"
|
||||||
name = "github.com/go-audio/wav"
|
name = "github.com/go-audio/wav"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "87c13ac40f038b0316963807a7d476544c7e9136"
|
revision = "87c13ac40f038b0316963807a7d476544c7e9136"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:c8ad4ba32ae8b71ef2bf5e1bad402aeb99ce77a1240f9b684db8b1ff5353e7ab"
|
||||||
name = "github.com/gobuffalo/packr"
|
name = "github.com/gobuffalo/packr"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "5a2cbb54c4e7d482e3f518c56f1f86f133d5204f"
|
revision = "5a2cbb54c4e7d482e3f518c56f1f86f133d5204f"
|
||||||
version = "v1.13.7"
|
version = "v1.13.7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
packages = ["proto"]
|
packages = ["proto"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
|
||||||
name = "github.com/gorilla/websocket"
|
name = "github.com/gorilla/websocket"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
|
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
|
||||||
version = "v1.4.0"
|
version = "v1.4.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "v2"
|
branch = "v2"
|
||||||
|
digest = "1:92ac5796b86f454e9b8a9f0f2ceba033747aa8d8fe1fda89b9ec6d6176a431b6"
|
||||||
name = "github.com/hraban/opus"
|
name = "github.com/hraban/opus"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "0f2e0b4fc6cd5710fddbb74ba2e5e02c1c1bc22b"
|
revision = "0f2e0b4fc6cd5710fddbb74ba2e5e02c1c1bc22b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:5c3444689562053b027ef3b96372e306adbe0d7d109b6cdd48d01eb80f8bab14"
|
||||||
name = "github.com/jinzhu/copier"
|
name = "github.com/jinzhu/copier"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "7e38e58719c33e0d44d585c4ab477a30f8cb82dd"
|
revision = "7e38e58719c33e0d44d585c4ab477a30f8cb82dd"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:2a21d36a5ab33e6e4ce82b3c7ba45c2330ca6e9af247382475e056b06395b8a9"
|
||||||
name = "github.com/jinzhu/gorm"
|
name = "github.com/jinzhu/gorm"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"dialects/sqlite"
|
"dialects/sqlite",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166"
|
revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166"
|
||||||
version = "v1.9.1"
|
version = "v1.9.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
|
||||||
name = "github.com/jinzhu/inflection"
|
name = "github.com/jinzhu/inflection"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "04140366298a54a039076d798123ffa108fff46c"
|
revision = "04140366298a54a039076d798123ffa108fff46c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:3e551bbb3a7c0ab2a2bf4660e7fcad16db089fdcfbb44b0199e62838038623ea"
|
||||||
name = "github.com/json-iterator/go"
|
name = "github.com/json-iterator/go"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
|
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
|
||||||
version = "v1.1.5"
|
version = "v1.1.5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
|
||||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
|
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:8c2ec3f7fa853d374b340831554f225ead9ab4cc6932256f0cffbfef8c78d9f5"
|
||||||
name = "github.com/mattetti/audio"
|
name = "github.com/mattetti/audio"
|
||||||
packages = ["riff"]
|
packages = ["riff"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "01576cde1f212c296c0b8ef5fa857169770c75b6"
|
revision = "01576cde1f212c296c0b8ef5fa857169770c75b6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
|
||||||
name = "github.com/mattn/go-isatty"
|
name = "github.com/mattn/go-isatty"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
|
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
|
||||||
version = "v0.0.4"
|
version = "v0.0.4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:3cafc6a5a1b8269605d9df4c6956d43d8011fc57f266ca6b9d04da6c09dee548"
|
||||||
name = "github.com/mattn/go-sqlite3"
|
name = "github.com/mattn/go-sqlite3"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
|
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
|
||||||
version = "v1.9.0"
|
version = "v1.9.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
|
||||||
name = "github.com/modern-go/concurrent"
|
name = "github.com/modern-go/concurrent"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
|
||||||
name = "github.com/modern-go/reflect2"
|
name = "github.com/modern-go/reflect2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
|
||||||
name = "github.com/pkg/errors"
|
name = "github.com/pkg/errors"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||||
version = "v0.8.0"
|
version = "v0.8.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:d10708438642755d6fd37c570b9d01cb5263e7e4248f813b079b031cdd7cf618"
|
||||||
name = "github.com/rylio/ytdl"
|
name = "github.com/rylio/ytdl"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "0227c2bacb82a434f2332d7d8c64093615c08a40"
|
revision = "0227c2bacb82a434f2332d7d8c64093615c08a40"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:dc2d85c13ac22c22a1f3170a41a8e1b897fa05134aaf533f16df44f66a25b4a1"
|
||||||
name = "github.com/sirupsen/logrus"
|
name = "github.com/sirupsen/logrus"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "a67f783a3814b8729bd2dac5780b5f78f8dbd64d"
|
revision = "a67f783a3814b8729bd2dac5780b5f78f8dbd64d"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:2cab41f59638fdb77dda96ab4f9b5860ef30f48967557254eba127e43c756f2e"
|
||||||
name = "github.com/tidwall/gjson"
|
name = "github.com/tidwall/gjson"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "1e3f6aeaa5bad08d777ea7807b279a07885dd8b2"
|
revision = "1e3f6aeaa5bad08d777ea7807b279a07885dd8b2"
|
||||||
version = "v1.1.3"
|
version = "v1.1.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:d3f968e2a2c9f8506ed44b01b605ade0176ba6cf73ff679073e77cfdef2c0d55"
|
||||||
name = "github.com/tidwall/match"
|
name = "github.com/tidwall/match"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "1731857f09b1f38450e2c12409748407822dc6be"
|
revision = "1731857f09b1f38450e2c12409748407822dc6be"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:03aa6e485e528acb119fb32901cf99582c380225fc7d5a02758e08b180cb56c3"
|
||||||
name = "github.com/ugorji/go"
|
name = "github.com/ugorji/go"
|
||||||
packages = ["codec"]
|
packages = ["codec"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab"
|
revision = "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab"
|
||||||
version = "v1.1.1"
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:207d2e280e7a43845b12d07437538d22d02dbd4c274b49f3940bb3dce2ed70d7"
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
packages = [
|
packages = [
|
||||||
"internal/subtle",
|
"internal/subtle",
|
||||||
"nacl/secretbox",
|
"nacl/secretbox",
|
||||||
"poly1305",
|
"poly1305",
|
||||||
"salsa20/salsa",
|
"salsa20/salsa",
|
||||||
"ssh/terminal"
|
"ssh/terminal",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "e3636079e1a4c1f337f212cc5cd2aca108f6c900"
|
revision = "e3636079e1a4c1f337f212cc5cd2aca108f6c900"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:1a1ecfa7b54ca3f7a0115ab5c578d7d6a5d8b605839c549e80260468c42f8be7"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = [
|
packages = [
|
||||||
"html",
|
"html",
|
||||||
"html/atom"
|
"html/atom",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "146acd28ed5894421fb5aac80ca93bc1b1f46f87"
|
revision = "146acd28ed5894421fb5aac80ca93bc1b1f46f87"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:850d28ab022512e2cd3cf511a77f363c29e22689b4031f2050871f5de47ae4a0"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = [
|
packages = [
|
||||||
"unix",
|
"unix",
|
||||||
"windows"
|
"windows",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "4497e2df6f9e69048a54498c7affbbec3294ad47"
|
revision = "4497e2df6f9e69048a54498c7affbbec3294ad47"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
|
||||||
name = "gopkg.in/dgrijalva/jwt-go.v3"
|
name = "gopkg.in/dgrijalva/jwt-go.v3"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||||
version = "v3.2.0"
|
version = "v3.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:cbc72c4c4886a918d6ab4b95e347ffe259846260f99ebdd8a198c2331cf2b2e9"
|
||||||
name = "gopkg.in/go-playground/validator.v8"
|
name = "gopkg.in/go-playground/validator.v8"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
|
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
|
||||||
version = "v8.18.2"
|
version = "v8.18.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||||
version = "v2.2.1"
|
version = "v2.2.1"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "21c5e86702fc917232102a89282f42f8a97d03b724ea1fcc8923e347a87347bd"
|
input-imports = [
|
||||||
|
"github.com/bwmarrin/discordgo",
|
||||||
|
"github.com/gin-gonic/gin",
|
||||||
|
"github.com/go-audio/audio",
|
||||||
|
"github.com/go-audio/wav",
|
||||||
|
"github.com/gobuffalo/packr",
|
||||||
|
"github.com/hraban/opus",
|
||||||
|
"github.com/jinzhu/copier",
|
||||||
|
"github.com/jinzhu/gorm",
|
||||||
|
"github.com/jinzhu/gorm/dialects/sqlite",
|
||||||
|
"github.com/rylio/ytdl",
|
||||||
|
"github.com/sirupsen/logrus",
|
||||||
|
"github.com/tidwall/gjson",
|
||||||
|
"gopkg.in/dgrijalva/jwt-go.v3",
|
||||||
|
]
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mgerb/go-discord-bot/server/db"
|
||||||
|
"github.com/mgerb/go-discord-bot/server/webserver/model"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"github.com/mgerb/go-discord-bot/server/config"
|
"github.com/mgerb/go-discord-bot/server/config"
|
||||||
"github.com/mgerb/go-discord-bot/server/util"
|
"github.com/mgerb/go-discord-bot/server/util"
|
||||||
@@ -104,10 +107,10 @@ func (conn *AudioConnection) handleMessage(m *discordgo.MessageCreate) {
|
|||||||
conn.clipAudio(m)
|
conn.clipAudio(m)
|
||||||
|
|
||||||
case "random":
|
case "random":
|
||||||
conn.PlayRandomAudio(m)
|
conn.PlayRandomAudio(m, nil)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
conn.PlayAudio(command, m)
|
conn.PlayAudio(command, m, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,25 +170,25 @@ func (conn *AudioConnection) summon(m *discordgo.MessageCreate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// play a random sound clip
|
// play a random sound clip
|
||||||
func (conn *AudioConnection) PlayRandomAudio(m *discordgo.MessageCreate) {
|
func (conn *AudioConnection) PlayRandomAudio(m *discordgo.MessageCreate, userID *string) {
|
||||||
files, _ := ioutil.ReadDir(config.Config.SoundsPath)
|
files, _ := ioutil.ReadDir(config.Config.SoundsPath)
|
||||||
if len(files) > 0 {
|
if len(files) > 0 {
|
||||||
randomIndex := rand.Intn(len(files))
|
randomIndex := rand.Intn(len(files))
|
||||||
arr := strings.Split(files[randomIndex].Name(), ".")
|
arr := strings.Split(files[randomIndex].Name(), ".")
|
||||||
if len(arr) > 0 && arr[0] != "" {
|
if len(arr) > 0 && arr[0] != "" {
|
||||||
conn.PlayAudio(arr[0], m)
|
conn.PlayAudio(arr[0], m, userID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayAudio - play audio in channel that user is in
|
// PlayAudio - play audio in channel that user is in
|
||||||
// if MessageCreate is null play in current channel
|
// if MessageCreate is null play in current channel
|
||||||
func (conn *AudioConnection) PlayAudio(soundName string, m *discordgo.MessageCreate) {
|
func (conn *AudioConnection) PlayAudio(soundName string, m *discordgo.MessageCreate, userID *string) {
|
||||||
|
|
||||||
// summon bot to channel if new message passed in
|
// summon bot to channel if new message passed in
|
||||||
if m != nil {
|
if m != nil {
|
||||||
conn.summon(m)
|
conn.summon(m)
|
||||||
} else if !conn.VoiceConnection.Ready {
|
} else if conn.VoiceConnection == nil || !conn.VoiceConnection.Ready {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +207,24 @@ func (conn *AudioConnection) PlayAudio(soundName string, m *discordgo.MessageCre
|
|||||||
select {
|
select {
|
||||||
case conn.SoundQueue <- soundName:
|
case conn.SoundQueue <- soundName:
|
||||||
|
|
||||||
|
var newUserID string
|
||||||
|
fromWebUI := false
|
||||||
|
|
||||||
|
// from discord
|
||||||
|
if m != nil && m.Author != nil {
|
||||||
|
newUserID = m.Author.ID
|
||||||
|
} else {
|
||||||
|
fromWebUI = true
|
||||||
|
newUserID = *userID
|
||||||
|
}
|
||||||
|
|
||||||
|
// log event when user plays sound clip
|
||||||
|
err := model.LogSoundPlayedEvent(db.GetConn(), newUserID, soundName, fromWebUI)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const (
|
|||||||
|
|
||||||
// CustomClaims -
|
// CustomClaims -
|
||||||
type CustomClaims struct {
|
type CustomClaims struct {
|
||||||
ID string `json:"id"`
|
UserID string `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Discriminator string `json:"discriminator"`
|
Discriminator string `json:"discriminator"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
var Migrations []interface{} = []interface{}{
|
// Migrations - list of database migrations
|
||||||
|
var Migrations = []interface{}{
|
||||||
&Message{},
|
&Message{},
|
||||||
&Attachment{},
|
&Attachment{},
|
||||||
&User{},
|
&User{},
|
||||||
&VideoArchive{},
|
&VideoArchive{},
|
||||||
&Sound{},
|
&Sound{},
|
||||||
|
&UserEventLog{},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ type Sound struct {
|
|||||||
User User `json:"user"`
|
User User `json:"user"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func SoundCreate(conn *gorm.DB, sound *Sound) error {
|
func SoundSave(conn *gorm.DB, sound *Sound) error {
|
||||||
return conn.Create(sound).Error
|
return conn.Create(sound).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func SoundList(conn *gorm.DB) ([]Sound, error) {
|
func SoundGet(conn *gorm.DB) ([]Sound, error) {
|
||||||
sound := []Sound{}
|
sound := []Sound{}
|
||||||
err := conn.Set("gorm:auto_preload", true).Find(&sound).Error
|
err := conn.Set("gorm:auto_preload", true).Find(&sound).Error
|
||||||
return sound, err
|
return sound, err
|
||||||
|
|||||||
51
server/webserver/model/user_event_log.go
Normal file
51
server/webserver/model/user_event_log.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserEventLog - logger for user events
|
||||||
|
type UserEventLog struct {
|
||||||
|
ID uint `gorm:"primary_key; auto_increment; not null" json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt *time.Time `json:"deleted_at"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
User User `json:"user"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserEventLogSave -
|
||||||
|
func UserEventLogSave(conn *gorm.DB, m *UserEventLog) error {
|
||||||
|
return conn.Save(m).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserEventLogGet - returns all messages - must use paging
|
||||||
|
func UserEventLogGet(conn *gorm.DB, page int) ([]*UserEventLog, error) {
|
||||||
|
userEventLog := []*UserEventLog{}
|
||||||
|
err := conn.Offset(page*100).Limit(100).Order("created_at desc", true).Preload("User").Find(&userEventLog).Error
|
||||||
|
return userEventLog, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogSoundPlayedEvent - log event when user plays sound clip
|
||||||
|
func LogSoundPlayedEvent(conn *gorm.DB, userID, soundName string, fromWebUI bool) error {
|
||||||
|
|
||||||
|
var content string
|
||||||
|
|
||||||
|
// from discord
|
||||||
|
if !fromWebUI {
|
||||||
|
content = "played sound clip: " + soundName
|
||||||
|
} else {
|
||||||
|
content = "played sound clip from web UI: " + soundName
|
||||||
|
}
|
||||||
|
|
||||||
|
// log play event
|
||||||
|
userEventLog := &UserEventLog{
|
||||||
|
UserID: userID,
|
||||||
|
Content: content,
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserEventLogSave(conn, userEventLog)
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ func AddSoundRoutes(group *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listSoundHandler(c *gin.Context) {
|
func listSoundHandler(c *gin.Context) {
|
||||||
archives, err := model.SoundList(db.GetConn())
|
archives, err := model.SoundGet(db.GetConn())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.InternalError(c, err)
|
response.InternalError(c, err)
|
||||||
@@ -36,6 +36,9 @@ func listSoundHandler(c *gin.Context) {
|
|||||||
func postSoundPlayHandler(c *gin.Context) {
|
func postSoundPlayHandler(c *gin.Context) {
|
||||||
connections := bothandlers.ActiveConnections
|
connections := bothandlers.ActiveConnections
|
||||||
|
|
||||||
|
oc, _ := c.Get("claims")
|
||||||
|
claims, _ := oc.(*middleware.CustomClaims)
|
||||||
|
|
||||||
params := struct {
|
params := struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}{}
|
}{}
|
||||||
@@ -47,9 +50,9 @@ func postSoundPlayHandler(c *gin.Context) {
|
|||||||
if len(connections) == 1 && params.Name != "" {
|
if len(connections) == 1 && params.Name != "" {
|
||||||
for _, con := range connections {
|
for _, con := range connections {
|
||||||
if params.Name == "random" {
|
if params.Name == "random" {
|
||||||
con.PlayRandomAudio(nil)
|
con.PlayRandomAudio(nil, &claims.UserID)
|
||||||
} else {
|
} else {
|
||||||
con.PlayAudio(params.Name, nil)
|
con.PlayAudio(params.Name, nil, &claims.UserID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +92,7 @@ func postSoundHandler(c *gin.Context) {
|
|||||||
log.Info(claims.Username, "uploaded", config.Config.SoundsPath+"/"+file.Filename)
|
log.Info(claims.Username, "uploaded", config.Config.SoundsPath+"/"+file.Filename)
|
||||||
|
|
||||||
// save who uploaded the clip into the database
|
// save who uploaded the clip into the database
|
||||||
uploadSaveDB(claims.ID, file.Filename)
|
uploadSaveDB(claims.UserID, file.Filename)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -106,7 +109,7 @@ func uploadSaveDB(userID, filename string) {
|
|||||||
extension := splitFilename[len(splitFilename)-1]
|
extension := splitFilename[len(splitFilename)-1]
|
||||||
name := strings.Join(splitFilename[:len(splitFilename)-1], ".")
|
name := strings.Join(splitFilename[:len(splitFilename)-1], ".")
|
||||||
|
|
||||||
model.SoundCreate(db.GetConn(), &model.Sound{
|
model.SoundSave(db.GetConn(), &model.Sound{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Name: name,
|
Name: name,
|
||||||
Extension: extension,
|
Extension: extension,
|
||||||
|
|||||||
33
server/webserver/routes/user_event_log.go
Normal file
33
server/webserver/routes/user_event_log.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/mgerb/go-discord-bot/server/db"
|
||||||
|
"github.com/mgerb/go-discord-bot/server/webserver/middleware"
|
||||||
|
"github.com/mgerb/go-discord-bot/server/webserver/model"
|
||||||
|
"github.com/mgerb/go-discord-bot/server/webserver/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddUserEventLogRoutes -
|
||||||
|
func AddUserEventLogRoutes(group *gin.RouterGroup) {
|
||||||
|
group.GET("/user-event-log", middleware.AuthorizedJWT(), middleware.AuthPermissions(middleware.PermAdmin), listEventLogHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listEventLogHandler(c *gin.Context) {
|
||||||
|
|
||||||
|
page, err := strconv.Atoi(c.Query("page"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
page = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
userEventLogs, err := model.UserEventLogGet(db.GetConn(), page)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
response.InternalError(c, err)
|
||||||
|
} else {
|
||||||
|
response.Success(c, userEventLogs)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ func getRouter() *gin.Engine {
|
|||||||
routes.AddConfigRoutes(api)
|
routes.AddConfigRoutes(api)
|
||||||
routes.AddSoundRoutes(api)
|
routes.AddSoundRoutes(api)
|
||||||
routes.AddVideoArchiveRoutes(api)
|
routes.AddVideoArchiveRoutes(api)
|
||||||
|
routes.AddUserEventLogRoutes(api)
|
||||||
|
|
||||||
router.NoRoute(func(c *gin.Context) {
|
router.NoRoute(func(c *gin.Context) {
|
||||||
if strings.HasPrefix(c.Request.URL.String(), "/api/") {
|
if strings.HasPrefix(c.Request.URL.String(), "/api/") {
|
||||||
|
|||||||
Reference in New Issue
Block a user