Дипломная работа: Социальная подкаст-платформа

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

}

}

const el = document.getElementById('root');

ReactDOM.render(<App/>, el);

Файл: Discasst\src\main\resources\static\app\components\Helper.js

export function getCookie(name) {

var matches = document.cookie.match(new RegExp(

"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"

));

return matches ? decodeURIComponent(matches[1]): undefined;

}

export function getFullCSRFParam() {

const token = getCookie('XSRF-TOKEN');

return `_csrf=${token}`;

}

export function saveCookie(cookieName, value) {

document.cookie = `${cookieName}=${value}; path=/`;

}

export function deleteCookie(cookieName) {

document.cookie = `${cookieName}=${""}; path=/; expires=-1`;

}

export function saveAllCookie(username, id, email, creationDate, name, bio) {

saveCookie("username", username);

saveCookie("userId", id);

saveCookie("userEmail", email);

saveCookie("userCreationDate", creationDate);

saveCookie("name", name);

saveCookie("bio", bio);

}

export function deleteAllCookie() {

deleteCookie("username");

deleteCookie("userId");

deleteCookie("userEmail");

deleteCookie("userCreationDate");

deleteCookie("name");

deleteCookie("bio");

deleteCookie("XSRF-TOKEN");

}

export function isUserSignedIn() {

let username = getCookie("username");

return (username !== "" && username !== undefined);

}

export const getGenres = () =>

fetch("/getAllGenres").then(response => response.json());

Файл: Discasst\src\main\resources\static\app\components\Navbar.js

const React = require('react');

import {deleteAllCookie, getCookie, getFullCSRFParam} from "./Helper";

export default class Navbar extends React.Component {

constructor(props) {

super(props);

this.state = {

isSignedIn: false

};

}

componentDidMount() {

this.isUserLogIn();

}

loginout = () => {

if (this.state.isSignedIn) {

deleteAllCookie();

this.props.history.push(`/signin?logout`);

}

else {

this.props.history.push(`/signin`);

}

};

toStats = () => {

this.props.history.push(`/statistics`);

};

toMyProfile = () => {

this.props.history.push(`/user/${getCookie("username")}`);

};

toFeed = () => {

this.props.history.push(`/feed`);

};

toNotifications = () => {

this.props.history.push(`/notifications`);

};

toHome = () => {

this.props.history.push(`/`);

};

toSignIn = () => {

this.props.history.push(`/signin`);

};

isUserLogIn() {

let username = getCookie("username");

if (username === "" || username === undefined) return false;

fetch(`/loginCheck?${getFullCSRFParam()}`, {

method: 'POST'

}).then((response) => {

if (response.status === 200 && !response.redirected) this.setState({isSignedIn: true});

});

}

onFilterSubmit = () => {

const filter = document.getElementById("topSearch").value;

this.props.history.push({

pathname: '/search',

state: {filterValue: filter}

})

};

render() {

return (

<div>

<nav className="navbar navbar-default" style={{backgroundColor: '#ffffff'}} role="navigation">

<div className="container-fluid centered">

<div className="navbar-header">

<a onClick={() => {

this.toHome()

}} className="navbar-brand" style={{height: '64px', display: 'flex', alignItems: 'center'}}>

<img src="/images/discasst.png" height='36'></img>

</a>

</div>

<div>

<ul className="nav navbar-nav"

style={{height: '64px', display: 'flex', alignItems: 'center'}}>

<li><a onClick={() => {

!this.state.isSignedIn ? this.toSignIn(): this.toFeed()

}}>

<span className="glyphicon glyphicon-align-justify"></span> Feed</a>

</li>

<li><a onClick={() => {

!this.state.isSignedIn ? this.toSignIn(): this.toMyProfile()

}}>

<span className="glyphicon glyphicon-user"></span> My Profile</a>

</li>

<li><a onClick={() => {

this.toStats()

}}>

<span className="glyphicon glyphicon-stats"></span></a>

</li>

</ul>

{!this.props.isSearchOff && <ul className="nav navbar-nav navbar-center">

<li>

<a>

<form onSubmit={this.onFilterSubmit}>

<div className="input-group" style={{width: '300px'}}>

<input id="topSearch" type="text" className="form-control"/>

<span className="input-group-btn">

<button className="btn btn-info" type="button"

onClick={this.onFilterSubmit}

>

<span className="glyphicon glyphicon-search"></span>

</button>

</span>

</div>

</form>

</a>

</li>

</ul>}

<ul className="nav navbar-nav navbar-right">

<li>

<a><button className="btn btn-info" type="button" onClick={this.loginout}>

<span

className="glyphicon glyphicon-log-out"></span> {this.state.isSignedIn ? "Sign Out": "Sign In"}

</button></a>

</li>

</ul>

</div>

</div>

</nav>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\feedPage\FeedPage.js

import Navbar from '../Navbar';

import PodcastPageContent from "../podcastPage/PodcastPageContent";

const React = require('react');

export default class FeedPage extends React.Component {

constructor(props) {

super(props);

this.state = {};

}

render() {

return (

<div>

<Navbar history={this.props.history}/>

<div className="container-fluid">

<div style={{display: "flex",}}>

<div style={{width: "25%"}}>

</div>

<div style={{width: "50%", textAlign: "center"}}>

<PodcastPageContent

history={this.props.history}

feed={true}

/>

</div>

<div style={{width: "25%"}}>

</div>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\login\RegisterPage.js

const React = require('react');

import {getFullCSRFParam} from "../Helper";

var errorEnum = {

NONE: "",

UNKNOWN: "Unknown error. Try again.",

USERNAME_TAKEN: "This login is already taken.",

LONG_USERNAME: "Login is too long (max length: 16).",

LONG_NAME: "Name is too long (max length: 16).",

WRONG_NAME: "Wrong name (allowed characters: a-Z, а-Я, 0-9, ' ').",

WRONG_USERNAME: "Wrong login (allowed characters: a-Z, 0-9, _).",

WRONG_EMAIL: "Wrong email (exemple: abc-42@xyz.com).",

WRONG_PASS: "Wrong password (allowed characters: a-Z, а-Я, 0-9).",

WRONG_PASS_LENGTH: "Password length must be 4-20 characters.",

WRONG_PASS_REPEAT: "Passwords don't match.",

};

export default class RegisterPage extends React.Component {

constructor(props) {

super(props);

this.state = {

password: '',

username: '',

name: '',

email: '',

success: false,

error: errorEnum.NONE

};

}

componentDidMount() {

$('form').submit(false);

}

onChangeUsername(event) {

this.setState({username: event.target.value});

}

onChangePass(event) {

this.setState({password: event.target.value});

}

onChangeName(event) {

this.setState({name: event.target.value});

}

onChangeEmail(event) {

this.setState({email: event.target.value});

}

register() {

if (!this.fullCheckPass()) return;

fetch(`/addUser?` +

`username=${this.state.username}` + `&` +

`password=${this.state.password}` + `&` +

`name=${this.state.name}` + `&` +

`email=${this.state.email}` + `&` +

getFullCSRFParam(), {

method: 'POST'

}).then((response) => {

let status = response.headers.get("newUserStatus");

if (status === "ok") {

this.setState({success: true, error: errorEnum.NONE});

setTimeout(() => {

this.props.history.push(`/signin`);

}, 1500)

}

else if (status === "usernameError") {

this.setState({success: false, error: errorEnum.USERNAME_TAKEN});

document.getElementById("login").focus();

}

else this.setState({success: false, error: errorEnum.UNKNOWN});

});

}

fullCheckPass() {

this.setState({error: errorEnum.NONE});

if (!this.validUsername()) return false;

if (!this.validName()) return false;

if (!this.validPassword()) return false;

if (!this.validEmail()) return false;

return true;

}

validUsername() {

var usernameRegex = /^[a-zA-Z0-9_]+$/;

var login = this.state.username;

if (login.length > 16) {

this.setState({error: errorEnum.LONG_USERNAME});

document.getElementById("login").focus();

return false;

}

var res = login.match(usernameRegex);

if (res === null) {

this.setState({error: errorEnum.WRONG_USERNAME});

document.getElementById("login").focus();

return false;

}

return true;

}

validPassword() {

var passRegex = /^[a-zA-Zа-яА-Я0-9]+$/;

var pass = this.state.password;

if (pass.length > 20 || pass.length < 4) {

this.setState({error: errorEnum.WRONG_PASS_LENGTH});

document.getElementById("pass").focus();

return false;

}

var res = pass.match(passRegex);

if (res === null) {

this.setState({error: errorEnum.WRONG_PASS});

document.getElementById("pass").focus();

return false;

}

return true;

}

validName() {

var nameRegex = /^[a-zA-Zа-яА-Я0-9 ]+$/;

var name = this.state.name;

if (name.length > 16) {

this.setState({error: errorEnum.LONG_NAME});

document.getElementById("name").focus();

return false;

}

var res = name.match(nameRegex);

if (res === null) {

this.setState({error: errorEnum.WRONG_NAME});

document.getElementById("name").focus();

return false;

}

return true;

}

validEmail() {

var emailRegex = /^[a-z0-9-\\.]+@[a-z-]+.[a-z]+$/;

var email = this.state.email;

var res = email.match(emailRegex);

if (res === null) {

this.setState({error: errorEnum.WRONG_EMAIL});

document.getElementById("email").focus();

return false;

}

return true;

}

render() {

const tss = this.state.success;

const tse = this.state.error;

return (

<div className="center-block main-center" style={{maxWidth: 500}}>

<hr className="hr100"/>

<div className="panel panel-info">

<div className="panel-body center-block" style={{maxWidth: 400}}>

<form onSubmit={this.register.bind(this)} className="form-signin">

<hr className="hr10"/>

<div className="input-group">

<span className="input-group-addon">Login</span>

<input id="login" className="form-control" required autoFocus

onChange={this.onChangeUsername.bind(this)}/>

</div>

<hr className="hr15"/>

<div className="input-group">

<span className="input-group-addon">Password</span>

<input id="pass" type="password" className="form-control" required

onChange={this.onChangePass.bind(this)}/>

</div>

<hr className="hr15"/>

<div className="input-group">

<span className="input-group-addon">Name</span>

<input id="name" className="form-control" required

onChange={this.onChangeName.bind(this)}/>

</div>

<hr className="hr15"/>

<div className="input-group">

<span className="input-group-addon">Email</span>

<input id="email" className="form-control" required

onChange={this.onChangeEmail.bind(this)}/>

</div>

<hr className="hr15"/>

{!tss && <button type="submit" className="btn btn-lg btn-info btn-block">Register</button>}

{tss && <button type="button" className="btn btn-lg btn-info btn-block"

disabled>Register</button>}

<hr className="hr10"/>

{tss &&

<div className="alert alert-success text-center">You successfully registered. Go to Sign

in...</div>}

{tse === errorEnum.USERNAME_TAKEN &&

<div className="alert alert-danger text-center">{errorEnum.USERNAME_TAKEN}</div>}

{tse === errorEnum.UNKNOWN &&

<div className="alert alert-danger text-center">{errorEnum.UNKNOWN}</div>}

{tse === errorEnum.LONG_USERNAME &&

<div className="alert alert-danger text-center">{errorEnum.LONG_USERNAME}</div>}

{tse === errorEnum.WRONG_USERNAME &&

<div className="alert alert-danger text-center">{errorEnum.WRONG_USERNAME}</div>}

{tse === errorEnum.LONG_NAME &&

<div className="alert alert-danger text-center">{errorEnum.LONG_NAME}</div>}

{tse === errorEnum.WRONG_NAME &&

<div className="alert alert-danger text-center">{errorEnum.WRONG_NAME}</div>}

{tse === errorEnum.WRONG_EMAIL &&

<div className="alert alert-danger text-center">{errorEnum.WRONG_EMAIL}</div>}

{tse === errorEnum.WRONG_PASS &&

<div className="alert alert-danger text-center">{errorEnum.WRONG_PASS}</div>}

{tse === errorEnum.WRONG_PASS_REPEAT &&

<div className="alert alert-danger text-center">{errorEnum.WRONG_PASS_REPEAT}</div>}

{tse === errorEnum.WRONG_PASS_LENGTH &&

<div className="alert alert-danger text-center">{errorEnum.WRONG_PASS_LENGTH}</div>}

</form>

</div>

</div>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\login\SigninPage.js

const React = require('react');

import {getFullCSRFParam, saveAllCookie} from "../Helper";

export default class SigninPage extends React.Component {

constructor(props) {

super(props);

this.state = {

password: '',

username: '',

logout: false,

error: false

};

}

refreshPageParams(url) {

this.setState({

logout: false,

error: false

});

if (url.searchParams.get("error") !== null) this.setState({error: true});

if (url.searchParams.get("logout") !== null) this.setState({logout: true});

if (!this.state.error && !this.state.logout) return false;

}

componentDidMount() {

let url = new URL(window.location.href);

this.refreshPageParams(url);

$('form').submit(false);

}

signin() {

fetch(`/perform_login?` +

`username=${this.state.username}` + `&` +

`password=${this.state.password}` + `&` +

getFullCSRFParam(), {

method: 'POST'

}).then((response) => {

if (!this.refreshPageParams(new URL(response.url))) {

if (!this.state.error)

this.loadUserInfoFromServerAndRedirect();

}

});

}

onChangePass(event) {

this.setState({password: event.target.value});

}

onChangeUsername(event) {

this.setState({username: event.target.value});

}

loadUserInfoFromServerAndRedirect() {

$.getJSON(`/getUserInfo?username=${this.state.username}`, (data) => {

saveAllCookie(data.username, data.id, data.email, data.creationDate, data.name, data.bio)

}).then(() => {

this.props.history.push('/');

});

}

toRegiser = () => {

this.props.history.push('/register');

};

render() {

return (

<div className="center-block main-center signin-css">

<form onSubmit={this.signin.bind(this)} className="form-signin center-block" style={{maxWidth: 320}}>

<hr className="hr100"/>

<hr className="hr60"/>

<img src="/images/discasst.png" type="image" alt="" width="260" className="center-block"></img>

<hr className="hr15"/>

<input type="username" className="form-control form-control-signin-css" placeholder="Username"

required id='signinUser'

autoFocus onChange={this.onChangeUsername.bind(this)}></input>

<input type="password" className="form-control form-control-signin-css" placeholder="Password"

required id='signinPass'

onChange={this.onChangePass.bind(this)}></input>

<br/>

<button type="submit" className="btn btn-lg btn-info btn-block">Sign In</button>

<br/>

<button type="button" className="btn btn-lg btn-info btn-block" onClick={() => {

this.toRegiser()

}}>Sign Up

</button>

<br/>

{this.state.logout &&

<div className="alert alert-info text-center">You signed out successfully.</div>}

{this.state.error &&

<div className="alert alert-danger text-center">Invalid Username or Password.</div>}

</form>

</div>

)

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\ EpisodePanel.js

import React from 'react';

import ReactDisqusComments from 'react-disqus-comments';

export default class EpisodePanel extends React.Component {

constructor() {

super();

this.state = {

isCommentsOn: false

}

}

closeComments = () => {

this.setState({isCommentsOn: false});

};

render() {

return (

<div className="container-fluid">

<div className="panel panel-info" style={{marginBottom: 10}}>

<div className="panel-body" style={{maxWidth: '100%'}}>

<h4 style={{marginTop: 0}}>{this.props.episode.name}</h4>

<h5 style={{color: '#acacac', marginBottom: 0}}>{this.props.episode.date}</h5>

<hr style={{marginTop: 10}}/>

<iframe width="100%" height="63" src={`${this.props.episode.podsterLink}/embed/15?link=0&ap=0`}

frameborder="0" allowtransparency="true"></iframe>

<p className="text-justify">{this.props.episode.description}

</p>

<button

onClick={() => {

if (!this.state.isCommentsOn) this.props.closeAllComments();

this.setState({isCommentsOn: !this.state.isCommentsOn});

}}

type="button"

className="btn btn-info btn-md pull-right "

>

{this.state.isCommentsOn ? 'Свернуть комментарии': 'Обсудить'}

</button>

{this.state.isCommentsOn &&

<ReactDisqusComments

shortname={'discasst'}

identifier={'http://discasst.com/#!/episode/' + this.props.episode.id}

title={this.props.episode.name}

url={'http://discasst.com/#!/episode/' + this.props.episode.id}

onNewComment={() => {

}}

id={this.props.episode.id}

/>

}

</div>

</div>

</div>

);

}

}

Файл: Discasst\src\main\resources\static\app\components\podcastPage\ PodcastList.js

import React from 'react';

import EpisodePanel from './EpisodePanel';

import WelcomePanel from './tweets/WelcomePanel';

import {getCookie} from '../Helper';

export default class PodcastList extends React.Component {

constructor() {

super();

this.state = {

episodes: [],

pageSize: 5,

loading: false,

currPage: 0,

allPages: false,

};

}

componentDidMount() {

this.getEpisodes(0);

const that = this;

window.onscroll = () => {

if (!that.state.allPages && !that.state.loading) {

//(document.body.scrollHeight - window.scrollY - document.body.offsetHeight) <= 100

if ((window.innerHeight + window.scrollY) >= (document.body.offsetHeight - 100)) {

let nextPage = that.state.currPage + 1;

console.log("End of page, load next page: " + nextPage);

that.setState({currPage: nextPage, loading: true});

that.getEpisodes(nextPage);

}

}

};

}

getEpisodes(page) {

$.ajax({

url: `${this.props.feed ? "/getEpisodesInFeedByUserIdInPage": "/getEpisodesByPodcastIdInPage"}?id=${this.props.feed ? getCookie('userId'): this.props.podcastId}&page=${page}&size=${this.state.pageSize}`,

type: 'get',

contentType: 'application/json',

success: (response) => {

this.setState(

{

allPages: response.last,

loading: false,

episodes: this.state.episodes.concat(response.content)

}

);

},

error: (jqXhr, textStatus, errorThrown) => {

console.log(errorThrown + " " + textStatus);

}

});

}

closeAllComments = () => {

this.state.episodes.map((ep) => {

this.refs['episode' + ep.id].closeComments();