-
-
{this.state.mediacentername}
-
Home
-
Random
- Video
+ if (this.state.password === true) {
+ return (
+
{
+ refreshAPIToken((error) => {
+ if (error !== '') {
+ console.log("wrong password!!!");
+ } else {
+ this.setState({password: false});
+ }
+ }, password);
+ }}/>
+ );
+ } else if (this.state.password === false) {
+ return (
+
+
+
+
{this.state.mediacentername}
+
Home
+
Random
+ Video
-
Categories
-
Settings
+
Categories
+
Settings
+
+ {this.routing()}
- {this.routing()}
-
- {this.state.onapierror ? this.ApiError() : null}
-
- );
+ {this.state.onapierror ? this.ApiError() : null}
+
+ );
+ } else {
+ return (<>still loading...>);
+ }
}
routing(): JSX.Element {
diff --git a/src/pages/AuthenticationPage/AuthenticationPage.module.css b/src/pages/AuthenticationPage/AuthenticationPage.module.css
new file mode 100644
index 0000000..1fce23a
--- /dev/null
+++ b/src/pages/AuthenticationPage/AuthenticationPage.module.css
@@ -0,0 +1,52 @@
+.main {
+ background-color: #00b3ff;
+ margin-left: calc(50% - 125px);
+ margin-top: 5%;
+ padding-bottom: 15px;
+ width: 250px;
+ text-align: center;
+ border-radius: 10px;
+}
+
+.loginText {
+ font-size: xx-large;
+ text-align: center;
+ margin-bottom: 15px;
+ font-weight: bolder;
+}
+
+.openmediacenterlabel {
+ margin-top: 5%;
+ text-align: center;
+ font-size: xxx-large;
+ font-weight: bold;
+ text-transform: capitalize;
+ color: white;
+}
+
+.input {
+ margin-left: 10px;
+ margin-right: 10px;
+ width: calc(100% - 20px);
+ background: transparent;
+ border-width: 0 0 1px 0;
+ color: #505050;
+ border-color: #505050;
+ text-align: center;
+ margin-bottom: 25px;
+ font-size: larger;
+}
+
+::placeholder {
+ color: #505050;
+ opacity: 1;
+}
+
+*:focus {
+ outline: none;
+}
+
+.input:focus {
+ color: black;
+ border-color: black;
+}
\ No newline at end of file
diff --git a/src/pages/AuthenticationPage/AuthenticationPage.test.js b/src/pages/AuthenticationPage/AuthenticationPage.test.js
new file mode 100644
index 0000000..0b6675c
--- /dev/null
+++ b/src/pages/AuthenticationPage/AuthenticationPage.test.js
@@ -0,0 +1,21 @@
+import React from 'react';
+import AuthenticationPage from './AuthenticationPage';
+import {shallow} from 'enzyme';
+
+describe('
', function () {
+ it('renders without crashing ', function () {
+ const wrapper = shallow(
{}}/>);
+ wrapper.unmount();
+ });
+
+ it('test button click', function () {
+ let pass;
+ const func = jest.fn((pwd) => {pass = pwd});
+ const wrapper = shallow();
+ wrapper.setState({pwdText: 'testpwd'});
+ wrapper.find('Button').simulate('click');
+
+ expect(func).toHaveBeenCalledTimes(1);
+ expect(pass).toBe('testpwd');
+ });
+});
diff --git a/src/pages/AuthenticationPage/AuthenticationPage.tsx b/src/pages/AuthenticationPage/AuthenticationPage.tsx
new file mode 100644
index 0000000..abe2dc3
--- /dev/null
+++ b/src/pages/AuthenticationPage/AuthenticationPage.tsx
@@ -0,0 +1,46 @@
+import React from "react";
+import {Button} from "../../elements/GPElements/Button";
+import style from './AuthenticationPage.module.css'
+
+interface state {
+ pwdText: string
+}
+
+interface props {
+ submit: (password: string) => void
+}
+
+class AuthenticationPage extends React.Component {
+ constructor(props: props) {
+ super(props);
+
+ this.state = {
+ pwdText: ''
+ }
+ }
+
+ render(): JSX.Element {
+ return (
+ <>
+ OpenMediaCenter
+
+
Login
+
+ this.setState({pwdText: ch.target.value})}
+ value={this.state.pwdText}/>
+
+
+
+
+ >
+ );
+ }
+}
+
+export default AuthenticationPage;
\ No newline at end of file
diff --git a/src/setupTests.js b/src/setupTests.js
index 2135359..0ebb3a3 100644
--- a/src/setupTests.js
+++ b/src/setupTests.js
@@ -37,6 +37,7 @@ global.prepareFailingFetchApi = () => {
global.callAPIMock = (resonse) => {
const helpers = require('./utils/Api');
helpers.callAPI = jest.fn().mockImplementation((_, __, func1) => {func1(resonse);});
+ helpers.callApiUnsafe = jest.fn().mockImplementation((_, __, func1) => {func1(resonse);});
};
// code to run before each test
diff --git a/src/types/ApiTypes.ts b/src/types/ApiTypes.ts
index 51fd3e4..1895a44 100644
--- a/src/types/ApiTypes.ts
+++ b/src/types/ApiTypes.ts
@@ -33,7 +33,7 @@ export namespace SettingsTypes {
export interface initialApiCallData {
DarkMode: boolean;
Password: boolean;
- Mediacenter_name: string;
+ MediacenterName: string;
VideoPath: string;
}
diff --git a/src/utils/Api.ts b/src/utils/Api.ts
index bb72ef3..c0ae974 100644
--- a/src/utils/Api.ts
+++ b/src/utils/Api.ts
@@ -47,13 +47,14 @@ interface ApiBaseRequest {
let apiToken = ''
// a callback que to be called after api token refresh
-let callQue: (() => void)[] = []
+let callQue: ((error: string) => void)[] = []
// flag to check wheter a api refresh is currently pending
let refreshInProcess = false;
// store the expire seconds of token
let expireSeconds = -1;
interface APIToken {
+ error?: string;
access_token: string;
expires_in: number;
scope: string;
@@ -63,8 +64,9 @@ interface APIToken {
/**
* refresh the api token or use that one in cookie if still valid
* @param callback to be called after successful refresh
+ * @param password
*/
-export function refreshAPIToken(callback: () => void): void {
+export function refreshAPIToken(callback: (error: string) => void, password?: string): void {
callQue.push(callback);
// check if already is a token refresh is in process
@@ -76,30 +78,26 @@ export function refreshAPIToken(callback: () => void): void {
refreshInProcess = true;
}
- // check if a cookie with token is available
- const token = getTokenCookie();
- if (token !== null) {
- // check if token is at least valid for the next minute
- if (token.expire > (new Date().getTime() / 1000) + 60) {
- apiToken = token.token;
- expireSeconds = token.expire;
- callback();
- console.log("token still valid...")
- callFuncQue();
- return;
- }
+ if (apiTokenValid()) {
+ console.log("token still valid...")
+ callFuncQue('');
+ return;
}
const formData = new FormData();
formData.append("grant_type", "client_credentials");
formData.append("client_id", "openmediacenter");
- formData.append("client_secret", 'openmediacenter');
+ formData.append("client_secret", password ? password : 'openmediacenter');
formData.append("scope", 'all');
fetch(getBackendDomain() + '/token', {method: 'POST', body: formData})
.then((response) => response.json()
.then((result: APIToken) => {
+ if (result.error) {
+ callFuncQue(result.error);
+ return;
+ }
console.log(result)
// set api token
apiToken = result.access_token;
@@ -107,17 +105,32 @@ export function refreshAPIToken(callback: () => void): void {
expireSeconds = (new Date().getTime() / 1000) + result.expires_in;
setTokenCookie(apiToken, expireSeconds);
// call all handlers and release flag
- callFuncQue();
+ callFuncQue('');
}));
}
+export function apiTokenValid(): boolean {
+ // check if a cookie with token is available
+ const token = getTokenCookie();
+ if (token !== null) {
+ // check if token is at least valid for the next minute
+ if (token.expire > (new Date().getTime() / 1000) + 60) {
+ apiToken = token.token;
+ expireSeconds = token.expire;
+
+ return true;
+ }
+ }
+ return false;
+}
+
/**
* call all qued callbacks
*/
-function callFuncQue(): void {
+function callFuncQue(error: string): void {
// call all pending handlers
callQue.map(func => {
- return func();
+ return func(error);
})
// reset pending que
callQue = []
@@ -221,6 +234,25 @@ export function callAPI(apinode: APINode,
})
}
+/**
+ * make a public unsafe api call (without token) -- use as rare as possible only for initialization (eg. check if pwd is neccessary)
+ * @param apinode
+ * @param fd
+ * @param callback
+ */
+export function callApiUnsafe(apinode: APINode, fd: ApiBaseRequest, callback: (_: T) => void, errorcallback?: (_: string) => void): void {
+ fetch(getAPIDomain() + apinode, {method: 'POST', body: JSON.stringify(fd),}).then((response) => {
+ if (response.status !== 200) {
+ console.log('Error: ' + response.statusText);
+ // todo place error popup here
+ } else {
+ response.json().then((result: T) => {
+ callback(result);
+ })
+ }
+ }).catch(reason => errorcallback ? errorcallback(reason) : {})
+}
+
/**
* A backend api call
* @param apinode which api backend handler to call
@@ -249,5 +281,6 @@ export enum APINode {
Settings = 'settings',
Tags = 'tags',
Actor = 'actor',
- Video = 'video'
+ Video = 'video',
+ Init = 'init'
}
diff --git a/src/utils/GlobalInfos.ts b/src/utils/GlobalInfos.ts
index 0416d27..8c9a7c4 100644
--- a/src/utils/GlobalInfos.ts
+++ b/src/utils/GlobalInfos.ts
@@ -23,6 +23,9 @@ class StaticInfos {
*/
enableDarkTheme(enable = true): void {
this.darktheme = enable;
+ this.handlers.map(func => {
+ return func();
+ })
}
/**
@@ -33,6 +36,11 @@ class StaticInfos {
return this.isDarkTheme() ? darktheme : lighttheme;
}
+ handlers: (() => void)[] = [];
+ onThemeChange(func: () => void): void {
+ this.handlers.push(func);
+ }
+
/**
* set the current videopath
* @param vidpath videopath with beginning and ending slash