Compare commits
5 Commits
v0.1.1
...
passwordfi
Author | SHA1 | Date | |
---|---|---|---|
8c9f3aecd8 | |||
c4098a8d3d | |||
043750170b | |||
23a1fdca75 | |||
72c68d8a7c |
17
api/settings.php
Normal file
17
api/settings.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
require 'Database.php';
|
||||
|
||||
$conn = Database::getInstance()->getConnection();
|
||||
|
||||
|
||||
if (isset($_POST['action'])) {
|
||||
$action = $_POST['action'];
|
||||
switch ($action) {
|
||||
case "isPasswordNeeded":
|
||||
echo '{"password": true}';
|
||||
break;
|
||||
case "checkPassword":
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
34
src/App.js
34
src/App.js
@ -7,11 +7,13 @@ import RandomPage from "./pages/RandomPage/RandomPage";
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import SettingsPage from "./pages/SettingsPage/SettingsPage";
|
||||
import CategoryPage from "./pages/CategoryPage/CategoryPage";
|
||||
import {Spinner} from "react-bootstrap";
|
||||
import LoginPage from "./pages/LoginPage/LoginPage";
|
||||
|
||||
class App extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {page: "default"};
|
||||
this.state = {page: "unverified"};
|
||||
|
||||
// bind this to the method for being able to call methods such as this.setstate
|
||||
this.showVideo = this.showVideo.bind(this);
|
||||
@ -42,12 +44,42 @@ class App extends React.Component {
|
||||
} else if (this.state.page === "lastpage") {
|
||||
// return back to last page
|
||||
page = this.mypage;
|
||||
} else if (this.state.page === "loginpage") {
|
||||
// return back to last page
|
||||
page = <LoginPage/>;
|
||||
} else if (this.state.page === "unverified") {
|
||||
// return back to last page
|
||||
page =
|
||||
<div className='loadSpinner'>
|
||||
<Spinner style={{marginLeft: "40px", marginBottom: "20px"}} animation="border" role="status">
|
||||
<span className="sr-only">Loading...</span>
|
||||
</Spinner>
|
||||
<div>Content loading...</div>
|
||||
</div>;
|
||||
} else {
|
||||
page = <div>unimplemented yet!</div>;
|
||||
}
|
||||
return (page);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const updateRequest = new FormData();
|
||||
updateRequest.append("action", "isPasswordNeeded");
|
||||
|
||||
fetch('/api/settings.php', {method: 'POST', body: updateRequest})
|
||||
.then((response) => response.json()
|
||||
.then((result) => {
|
||||
if (result.password === false) {
|
||||
this.setState({page: "default"});
|
||||
} else {
|
||||
this.setState({page: "loginpage"});
|
||||
}
|
||||
}))
|
||||
.catch(() => {
|
||||
console.log("no connection to backend");
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="App">
|
||||
|
@ -17,4 +17,62 @@ describe('<App/>', function () {
|
||||
const wrapper = shallow(<App/>);
|
||||
expect(wrapper.find('nav').find('li')).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('simulate video view change ', function () {
|
||||
const wrapper = shallow(<App/>);
|
||||
|
||||
wrapper.instance().showVideo(<div id='testit'></div>);
|
||||
|
||||
expect(wrapper.find("#testit")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('test hide video again', function () {
|
||||
const wrapper = shallow(<App/>);
|
||||
|
||||
wrapper.instance().showVideo(<div id='testit'></div>);
|
||||
|
||||
expect(wrapper.find("#testit")).toHaveLength(1);
|
||||
|
||||
wrapper.instance().hideVideo();
|
||||
|
||||
expect(wrapper.find("HomePage")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('test fallback to last loaded page', function () {
|
||||
const wrapper = shallow(<App/>);
|
||||
|
||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Random Video" && t.type() === "div").simulate("click");
|
||||
|
||||
wrapper.instance().showVideo(<div id='testit'></div>);
|
||||
|
||||
expect(wrapper.find("#testit")).toHaveLength(1);
|
||||
|
||||
wrapper.instance().hideVideo();
|
||||
|
||||
expect(wrapper.find("RandomPage")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('test home click', function () {
|
||||
const wrapper = shallow(<App/>);
|
||||
wrapper.setState({page: "wrongvalue"});
|
||||
expect(wrapper.find("HomePage")).toHaveLength(0);
|
||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Home" && t.type() === "div").simulate("click");
|
||||
expect(wrapper.find("HomePage")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('test category click', function () {
|
||||
const wrapper = shallow(<App/>);
|
||||
|
||||
expect(wrapper.find("CategoryPage")).toHaveLength(0);
|
||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Categories" && t.type() === "div").simulate("click");
|
||||
expect(wrapper.find("CategoryPage")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('test settings click', function () {
|
||||
const wrapper = shallow(<App/>);
|
||||
|
||||
expect(wrapper.find("SettingsPage")).toHaveLength(0);
|
||||
wrapper.find(".nav-link").findWhere(t => t.text() === "Settings" && t.type() === "div").simulate("click");
|
||||
expect(wrapper.find("SettingsPage")).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
@ -10,3 +10,8 @@
|
||||
.nav-link:hover {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
.loadSpinner {
|
||||
margin-top: 200px;
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ describe('<CategoryPage/>', function () {
|
||||
let message;
|
||||
global.console.log = jest.fn((m) => {
|
||||
message = m;
|
||||
})
|
||||
});
|
||||
|
||||
const wrapper = shallow(<CategoryPage/>);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.searchform{
|
||||
.searchform {
|
||||
margin-top: 25px;
|
||||
float: right;
|
||||
}
|
||||
|
@ -124,16 +124,16 @@ class HomePage extends React.Component {
|
||||
<div className='pageheader'>
|
||||
<span className='pageheadertitle'>Home Page</span>
|
||||
<span className='pageheadersubtitle'>{this.state.tag} Videos - {this.state.selectionnr}</span>
|
||||
<form className="form-inline searchform" action="#">
|
||||
<form className="form-inline searchform" onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
this.searchVideos(this.keyword);
|
||||
}}>
|
||||
<input data-testid='searchtextfield' className="form-control mr-sm-2"
|
||||
type="text" placeholder="Search"
|
||||
onChange={(e) => {
|
||||
this.keyword = e.target.value
|
||||
}}/>
|
||||
<button data-testid='searchbtnsubmit' className="btn btn-success" type="submit" onClick={() => {
|
||||
this.searchVideos(this.keyword)
|
||||
}}>Search
|
||||
</button>
|
||||
<button data-testid='searchbtnsubmit' className="btn btn-success" type="submit">Search</button>
|
||||
</form>
|
||||
<hr/>
|
||||
</div>
|
||||
|
@ -11,6 +11,11 @@ function prepareFetchApi(response) {
|
||||
return (jest.fn().mockImplementation(() => mockFetchPromise));
|
||||
}
|
||||
|
||||
function prepareFailingFetchApi() {
|
||||
const mockFetchPromise = Promise.reject("myreason");
|
||||
return (jest.fn().mockImplementation(() => mockFetchPromise));
|
||||
}
|
||||
|
||||
describe('<HomePage/>', function () {
|
||||
it('renders without crashing ', function () {
|
||||
const wrapper = shallow(<HomePage/>);
|
||||
@ -58,11 +63,11 @@ describe('<HomePage/>', function () {
|
||||
});
|
||||
|
||||
it('test search field', done => {
|
||||
global.fetch = prepareFetchApi([{},{}]);
|
||||
global.fetch = prepareFetchApi([{}, {}]);
|
||||
|
||||
const wrapper = shallow(<HomePage/>);
|
||||
|
||||
wrapper.find('[data-testid="searchtextfield"]').simulate('change', { target: { value: 'testvalue' } });
|
||||
wrapper.find('[data-testid="searchtextfield"]').simulate('change', {target: {value: 'testvalue'}});
|
||||
wrapper.find('[data-testid="searchbtnsubmit"]').simulate("click");
|
||||
|
||||
process.nextTick(() => {
|
||||
@ -73,4 +78,43 @@ describe('<HomePage/>', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('test form submit', done => {
|
||||
global.fetch = prepareFetchApi([{}, {}]);
|
||||
|
||||
const wrapper = shallow(<HomePage/>);
|
||||
|
||||
const fakeEvent = {preventDefault: () => console.log('preventDefault')};
|
||||
wrapper.find(".searchform").simulate('submit', fakeEvent);
|
||||
|
||||
expect(wrapper.state().selectionnr).toBe(0);
|
||||
|
||||
process.nextTick(() => {
|
||||
// state to be set correctly with response
|
||||
expect(wrapper.state().selectionnr).toBe(2);
|
||||
|
||||
global.fetch.mockClear();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('test no backend connection behaviour', done => {
|
||||
// this test assumes a console.log within every connection fail
|
||||
global.fetch = prepareFailingFetchApi();
|
||||
|
||||
let count = 0;
|
||||
global.console.log = jest.fn((m) => {
|
||||
count++;
|
||||
});
|
||||
|
||||
const wrapper = shallow(<HomePage/>);
|
||||
|
||||
process.nextTick(() => {
|
||||
// state to be set correctly with response
|
||||
expect(global.fetch).toBeCalledTimes(2);
|
||||
|
||||
global.fetch.mockClear();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
60
src/pages/LoginPage/LoginPage.js
Normal file
60
src/pages/LoginPage/LoginPage.js
Normal file
@ -0,0 +1,60 @@
|
||||
import React from "react";
|
||||
import {Form} from "react-bootstrap";
|
||||
|
||||
class LoginPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<div className='pageheader'>
|
||||
<span className='pageheadertitle'>Login Page</span>
|
||||
<span className='pageheadersubtitle'>type correct password!</span>
|
||||
<hr/>
|
||||
</div>
|
||||
<div style={{marginLeft: "35%", width: "400px", marginTop: "100px"}}>
|
||||
<Form.Group>
|
||||
<Form.Label>Password</Form.Label>
|
||||
<Form.Control id='passfield' type="password" placeholder="Enter Password" onChange={(v) => {
|
||||
this.password = v.target.value
|
||||
}}/>
|
||||
<Form.Text className="text-muted">
|
||||
You can disable/enable this feature on settingspage.
|
||||
</Form.Text>
|
||||
<hr/>
|
||||
<button className='btn btn-success' type='submit' onClick={() => this.checkPassword()}>Submit
|
||||
</button>
|
||||
</Form.Group>
|
||||
</div>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
checkPassword() {
|
||||
const updateRequest = new FormData();
|
||||
updateRequest.append("action", "checkPassword");
|
||||
updateRequest.append("password", this.state.password);
|
||||
|
||||
fetch('/api/settings.php', {method: 'POST', body: updateRequest})
|
||||
.then((response) => response.json()
|
||||
.then((result) => {
|
||||
if (result.correct) {
|
||||
// todo 2020-06-18: call a callback to return back to right page
|
||||
} else {
|
||||
// error popup
|
||||
}
|
||||
}))
|
||||
.catch(() => {
|
||||
console.log("no connection to backend");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default LoginPage;
|
@ -34,7 +34,10 @@ class SettingsPage extends React.Component {
|
||||
if (this.myinterval) {
|
||||
clearInterval(this.myinterval);
|
||||
}
|
||||
// todo 2020-06-18: maybe not start on mount
|
||||
this.myinterval = setInterval(this.updateStatus, 1000);
|
||||
|
||||
// todo 2020-06-18: fetch path data here
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
Reference in New Issue
Block a user