* no unauthorized init

* more dynamic Preview element
This commit is contained in:
lukas 2021-04-16 21:12:56 +02:00
parent 57a7a9a827
commit fdcecb0a75
14 changed files with 142 additions and 108 deletions

View File

@ -15,7 +15,6 @@ const (
TagNode = iota
SettingsNode = iota
ActorNode = iota
InitNode = iota
)
type actionStruct struct {
@ -42,9 +41,6 @@ func ServerInit() {
http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(settingsHandler))
http.Handle(APIPREFIX+"/actor", oauth.ValidateToken(actorHandler))
// initialization api calls to check if password is neccessaray
http.Handle(APIPREFIX+"/init", http.HandlerFunc(initHandler))
// initialize oauth service and add corresponding auth routes
oauth.InitOAuth()
}
@ -85,10 +81,6 @@ func settingsHandler(rw http.ResponseWriter, req *http.Request) {
handlefunc(rw, req, SettingsNode)
}
func initHandler(rw http.ResponseWriter, req *http.Request) {
handlefunc(rw, req, InitNode)
}
func handlefunc(rw http.ResponseWriter, req *http.Request, node int) {
// only allow post requests
if req.Method != "POST" {

View File

@ -1,39 +0,0 @@
package api
import (
"encoding/json"
"openmediacenter/apiGo/database/settings"
"regexp"
"strings"
)
func AddInitHandlers() {
passwordNeeded()
}
func passwordNeeded() {
AddHandler("loadInitialData", InitNode, nil, func() []byte {
sett := settings.LoadSettings()
type InitialDataTypeResponse struct {
DarkMode bool
Pasword bool
MediacenterName string
VideoPath string
}
regexMatchUrl := regexp.MustCompile("^http(|s):\\/\\/([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}:[0-9]{1,5}")
videoUrl := regexMatchUrl.FindString(sett.VideoPath)
serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl)
res := InitialDataTypeResponse{
DarkMode: sett.DarkMode,
Pasword: sett.Pasword != "-1",
MediacenterName: sett.Mediacenter_name,
VideoPath: serverVideoPath,
}
str, _ := json.Marshal(res)
return str
})
}

View File

@ -1,9 +1,13 @@
package api
import (
"encoding/json"
"openmediacenter/apiGo/api/types"
"openmediacenter/apiGo/database"
"openmediacenter/apiGo/database/settings"
"openmediacenter/apiGo/videoparser"
"regexp"
"strings"
)
func AddSettingsHandlers() {
@ -17,6 +21,30 @@ func getSettingsFromDB() {
result := database.GetSettings()
return jsonify(result)
})
AddHandler("loadInitialData", SettingsNode, nil, func() []byte {
sett := settings.LoadSettings()
type InitialDataTypeResponse struct {
DarkMode bool
Pasword bool
MediacenterName string
VideoPath string
}
regexMatchUrl := regexp.MustCompile("^http(|s):\\/\\/([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}\\.([0-9]){1,3}:[0-9]{1,5}")
videoUrl := regexMatchUrl.FindString(sett.VideoPath)
serverVideoPath := strings.TrimPrefix(sett.VideoPath, videoUrl)
res := InitialDataTypeResponse{
DarkMode: sett.DarkMode,
Pasword: sett.Pasword != "-1",
MediacenterName: sett.Mediacenter_name,
VideoPath: serverVideoPath,
}
str, _ := json.Marshal(res)
return str
})
}
func saveSettingsToDB() {

View File

@ -30,7 +30,6 @@ func main() {
api.AddSettingsHandlers()
api.AddTagHandlers()
api.AddActorsHandlers()
api.AddInitHandlers()
// add the static files
static.ServeStaticFiles()

View File

@ -9,7 +9,7 @@ import style from './App.module.css';
import SettingsPage from './pages/SettingsPage/SettingsPage';
import CategoryPage from './pages/CategoryPage/CategoryPage';
import {APINode, apiTokenValid, callApiUnsafe, refreshAPIToken} from './utils/Api';
import {APINode, apiTokenValid, callAPI, refreshAPIToken} from './utils/Api';
import {BrowserRouter as Router, NavLink, Route, Switch} from 'react-router-dom';
import Player from './pages/Player/Player';
@ -75,7 +75,7 @@ class App extends React.Component<{}, state> {
initialAPICall(): void {
// this is the first api call so if it fails we know there is no connection to backend
callApiUnsafe(APINode.Init, {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => {
callAPI(APINode.Settings, {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => {
// set theme
GlobalInfos.enableDarkTheme(result.DarkMode);
@ -99,7 +99,15 @@ class App extends React.Component<{}, state> {
if (this.state.password === true) {
// render authentication page if auth is neccessary
return <AuthenticationPage onSuccessLogin={(): void => this.setState({password: false})} />;
return (
<AuthenticationPage
onSuccessLogin={(): void => {
this.setState({password: false});
// reinit general infos
this.initialAPICall();
}}
/>
);
} else if (this.state.password === false) {
return (
<Router>

View File

@ -9,7 +9,6 @@ interface Props<T> {
interface state<T> {
loadeditems: T[];
selectionnr: number;
}
/**
@ -24,8 +23,7 @@ class DynamicContentContainer<T> extends React.Component<Props<T>, state<T>> {
super(props);
this.state = {
loadeditems: [],
selectionnr: 0
loadeditems: []
};
}
@ -35,6 +33,22 @@ class DynamicContentContainer<T> extends React.Component<Props<T>, state<T>> {
this.loadPreviewBlock(this.props.initialLoadNr ? this.props.initialLoadNr : 16);
}
componentDidUpdate(prevProps: Props<T>): void {
// when source props change force update!
if (prevProps.data.length !== this.props.data.length) {
this.clean();
this.loadPreviewBlock(this.props.initialLoadNr ? this.props.initialLoadNr : 16);
}
}
/**
* clear all elements rendered...
*/
clean(): void {
this.loadindex = 0;
this.setState({loadeditems: []});
}
render(): JSX.Element {
return (
<div className={style.maincontent}>

View File

@ -3,17 +3,18 @@ import style from './Preview.module.css';
import {Spinner} from 'react-bootstrap';
import {Link} from 'react-router-dom';
import GlobalInfos from '../../utils/GlobalInfos';
import {APINode, callAPIPlain} from '../../utils/Api';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faPhotoVideo} from '@fortawesome/free-solid-svg-icons';
interface PreviewProps {
name: string;
movieId: number;
picLoader: (callback: (pic: string) => void) => void;
linkPath?: string;
onClick?: () => void;
}
interface PreviewState {
previewpicture: string | null;
picLoaded: boolean | null;
}
/**
@ -21,30 +22,43 @@ interface PreviewState {
* floating side by side
*/
class Preview extends React.Component<PreviewProps, PreviewState> {
// store the picture to display
pic?: string;
constructor(props: PreviewProps) {
super(props);
this.state = {
previewpicture: null
picLoaded: null
};
}
componentDidMount(): void {
callAPIPlain(APINode.Video, {action: 'readThumbnail', movieid: this.props.movieId}, (result) => {
this.props.picLoader((result) => {
this.pic = result;
this.setState({
previewpicture: result
picLoaded: result !== ''
});
});
}
render(): JSX.Element {
if (this.props.linkPath !== undefined) {
return <Link to={this.props.linkPath}>{this.content()}</Link>;
} else {
return this.content();
}
}
content(): JSX.Element {
const themeStyle = GlobalInfos.getThemeStyle();
return (
<Link to={'/player/' + this.props.movieId}>
<div className={style.videopreview + ' ' + themeStyle.secbackground + ' ' + themeStyle.preview}>
<div
className={style.videopreview + ' ' + themeStyle.secbackground + ' ' + themeStyle.preview}
onClick={this.props.onClick}>
<div className={style.previewtitle + ' ' + themeStyle.lighttextcolor}>{this.props.name}</div>
<div className={style.previewpic}>
{this.state.previewpicture === '' ? (
{this.state.picLoaded === false ? (
<FontAwesomeIcon
style={{
color: 'white',
@ -53,17 +67,16 @@ class Preview extends React.Component<PreviewProps, PreviewState> {
icon={faPhotoVideo}
size='5x'
/>
) : this.state.previewpicture === null ? (
) : this.state.picLoaded === null ? (
<span className={style.loadAnimation}>
<Spinner animation='border' />
</span>
) : (
<img className={style.previewimage} src={this.state.previewpicture} alt='Pic loading.' />
<img className={style.previewimage} src={this.pic} alt='Pic loading.' />
)}
</div>
<div className={style.previewbottom} />
</div>
</Link>
);
}
}

View File

@ -2,6 +2,7 @@ import React from 'react';
import Preview from '../Preview/Preview';
import {VideoTypes} from '../../types/ApiTypes';
import DynamicContentContainer from '../DynamicContentContainer/DynamicContentContainer';
import {APINode, callAPIPlain} from '../../utils/Api';
interface Props {
data: VideoTypes.VideoUnloadedType[];
@ -11,7 +12,23 @@ interface Props {
const VideoContainer = (props: Props): JSX.Element => {
return (
<DynamicContentContainer
renderElement={(el): JSX.Element => <Preview key={el.MovieId} name={el.MovieName} movieId={el.MovieId} />}
renderElement={(el): JSX.Element => (
<Preview
key={el.MovieId}
picLoader={(callback: (pic: string) => void): void => {
callAPIPlain(
APINode.Video,
{
action: 'readThumbnail',
movieid: el.MovieId
},
(result) => callback(result)
);
}}
name={el.MovieName}
linkPath={'/player/' + el.MovieId}
/>
)}
data={props.data}>
{props.children}
</DynamicContentContainer>

View File

@ -4,9 +4,10 @@ import {ActorType} from '../../types/VideoTypes';
import ActorTile from '../../elements/ActorTile/ActorTile';
import PageTitle from '../../elements/PageTitle/PageTitle';
import SideBar from '../../elements/SideBar/SideBar';
import style from './ActorOverviewPage.module.css';
// import style from './ActorOverviewPage.module.css';
import {Button} from '../../elements/GPElements/Button';
import NewActorPopup from '../../elements/Popups/NewActorPopup/NewActorPopup';
import DynamicContentContainer from '../../elements/DynamicContentContainer/DynamicContentContainer';
interface Props {}
@ -36,11 +37,12 @@ class ActorOverviewPage extends React.Component<Props, state> {
<SideBar>
<Button title='Add Actor' onClick={(): void => this.setState({NActorPopupVisible: true})} />
</SideBar>
<div className={style.container}>
{this.state.actors.map((el) => (
<ActorTile key={el.ActorId} actor={el} />
))}
</div>
<DynamicContentContainer
renderElement={(el): JSX.Element => <ActorTile key={el.ActorId} actor={el} />}
data={this.state.actors}
initialLoadNr={36}
/>
{this.state.NActorPopupVisible ? (
<NewActorPopup
onHide={(): void => {

View File

@ -48,7 +48,7 @@ export class ActorPage extends React.Component<Props, state> {
</div>
<SideBarTitle>Attention: This is an early preview!</SideBarTitle>
</SideBar>
{this.state.data.length !== 0 ? <VideoContainer data={this.state.data} /> : <div>No Data found!</div>}
<VideoContainer data={this.state.data} />
</>
);
}

View File

@ -53,7 +53,6 @@ class TagView extends React.Component<Props, TagViewState> {
Add a new Tag!
</button>
</SideBar>
{this.state.loadedtags.length !== 0 ? (
<DynamicContentContainer
data={this.state.loadedtags}
renderElement={(m): JSX.Element => (
@ -63,9 +62,6 @@ class TagView extends React.Component<Props, TagViewState> {
)}
initialLoadNr={20}
/>
) : (
'loading'
)}
{this.handlePopups()}
</>
);

View File

@ -157,7 +157,7 @@ export class HomePage extends React.Component<Props, state> {
}}
/>
</SideBar>
{this.state.data.length !== 0 ? <VideoContainer data={this.state.data} /> : <div>No Data found!</div>}
<VideoContainer data={this.state.data} />
<div className={style.rightinfo} />
</Route>
</Switch>

View File

@ -1,8 +1,13 @@
import React from 'react';
import Preview from '../../elements/Preview/Preview';
class TVShowPage extends React.Component {
render(): JSX.Element {
return <>TvShowPage</>;
return (
<>
<Preview name='myTestItem' picLoader={(callback): void => callback('')} />
</>
);
}
}

View File

@ -279,6 +279,5 @@ export enum APINode {
Settings = 'settings',
Tags = 'tags',
Actor = 'actor',
Video = 'video',
Init = 'init'
Video = 'video'
}