fix redirects, fix server syncs on join

This commit is contained in:
Katalina / stardust 2018-01-17 23:12:11 -06:00
parent 032831aff1
commit f7238ab091
14 changed files with 132 additions and 101 deletions

View file

@ -7,7 +7,7 @@ module.exports = (R, $) => {
ctx.body = presentable
} catch (e) {
console.error(e.trace)
console.error(e.trace || e.stack)
}
})
@ -29,6 +29,23 @@ module.exports = (R, $) => {
ctx.body = server
})
R.get('/api/server/:id/slug', async (ctx) => {
const { userId } = ctx.session
const { id } = ctx.params
const srv = $.discord.client.guilds.get(id)
console.log(srv)
if (srv == null) {
ctx.body = { err: 'not found' }
ctx.status = 404
return
}
ctx.body = await $.P.serverSlug(srv)
})
R.patch('/api/server/:id', async (ctx) => {
const { userId } = ctx.session
const { id } = ctx.params

View file

@ -34,6 +34,7 @@ class DiscordService extends Service {
if (this.isBot) {
this.log.info('this roleypoly is a bot')
this.client.on('message', this.handleMessage.bind(this))
this.client.on('guildCreate', this.handleJoin.bind(this))
}
for (let server of this.client.guilds.array()) {
@ -216,6 +217,10 @@ class DiscordService extends Service {
}
}
async handleJoin (guild) {
await this.ctx.server.ensure(guild)
}
}
module.exports = DiscordService

View file

@ -10,6 +10,15 @@ class PresentationService extends Service {
this.cache = LRU({ max: 500, maxAge: 100 * 60 * 5 })
}
serverSlug (server) {
return {
id: server.id,
name: server.name,
ownerID: server.ownerID,
icon: server.icon
}
}
async oldPresentableServers (collection, userId) {
let servers = []
@ -39,12 +48,7 @@ class PresentationService extends Service {
nickname: gm.nickname,
color: gm.displayHexColor
},
server: {
id: server.id,
name: server.name,
ownerID: server.ownerID,
icon: server.icon
},
server: this.serverSlug(server),
roles: (incRoles) ? (await this.rolesByServer(server, sd)).map(r => ({ ...r, selected: gm.roles.has(r.id) })) : [],
message: sd.message,
categories: sd.categories,

View file

@ -33,6 +33,7 @@
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"homepage": "https://rp.kat.cafe",
"proxy": {
"/api": {
"target": "http://localhost:6769"

View file

@ -39,7 +39,10 @@ export const userInit = async dispatch => {
}
export const userLogout = async dispatch => {
await superagent.post('/api/auth/logout')
try {
await superagent.post('/api/auth/logout')
} catch (e) {
}
dispatch({
type: Symbol.for('reset user')

View file

@ -10,7 +10,9 @@ export default class AddServer extends Component {
polling = null
componentDidMount () {
this.pollingStop = Actions.startServerPolling(this.props.dispatch)
if (this.props.match.params.server !== undefined) {
this.pollingStop = Actions.startServerPolling(this.props.dispatch)
}
}
componentWillUnmount () {

View file

@ -8,18 +8,26 @@ import { fetchServers } from '../../actions'
class OauthCallback extends Component {
state = {
notReady: true,
message: 'chotto matte kudasai...'
message: 'chotto matte kudasai...',
redirect: '/s'
}
async componentDidMount () {
// handle stuff in the url
const sp = new URLSearchParams(this.props.location.search)
const token = sp.get('code')
if (token === '' || token == null) {
this.setState({ message: 'token missing, what are you trying to do?!' })
return
}
const stateToken = sp.get('state')
const state = JSON.parse(window.sessionStorage.getItem('state') || 'null')
if (state !== null && state.state === stateToken && state.redirect != undefined) {
this.setState({ redirect: state.redirect })
}
this.props.history.replace(this.props.location.pathname)
@ -35,7 +43,7 @@ class OauthCallback extends Component {
this.props.dispatch(fetchServers)
} catch (e) {
counter++
if (counter > 12) {
if (counter > 100) {
this.setState({ message: "i couldn't log you in. :c" })
} else {
setTimeout(() => { retry() }, 250)
@ -61,7 +69,7 @@ class OauthCallback extends Component {
}
render () {
return (this.state.notReady) ? this.state.message : <Redirect to='/s' />
return (this.state.notReady) ? this.state.message : <Redirect to={this.state.redirect} replace />
}
}

View file

@ -2,8 +2,9 @@ import React, { Component } from 'react'
import { Redirect } from 'react-router-dom'
import superagent from 'superagent'
import { connect } from 'react-redux'
import uuidv4 from 'uuid/v4'
import { fetchServers } from '../../actions'
import { URL } from 'url';
@connect()
class OauthCallback extends Component {
@ -39,11 +40,15 @@ class OauthCallback extends Component {
}
async componentDidMount () {
const state = uuidv4()
const oUrl = new URL(window.location.href)
if (oUrl.searchParams.has('r')) {
this.setState({ redirect: oUrl.searchParams.get('r') })
}
window.sessionStorage.setItem('state', JSON.stringify({ state, redirect: oUrl.searchParams.get('r') }))
try {
await this.setupUser()
@ -53,9 +58,7 @@ class OauthCallback extends Component {
const { body: { url } } = await superagent.get('/api/auth/redirect?url=✔️')
const nUrl = new URL(url)
if (oUrl.searchParams.has('r')) {
nUrl.searchParams.set('r', oUrl.searchParams.get('r'))
}
nUrl.searchParams.set('state', state)
window.location.href = nUrl.toString()
}

View file

@ -0,0 +1,47 @@
import React, { Component } from 'react'
import { Link, Redirect } from 'react-router-dom'
import superagent from 'superagent'
import discordLogo from '../../pages/images/discord-logo.svg'
export default class ServerLanding extends Component {
state = {
server: null,
exit: false
}
async componentWillMount () {
console.log(this.props)
try {
const rsp = await superagent.get(`/api/server/${this.props.match.params.server}/slug`)
this.setState({ server: rsp.body })
} catch (e) {
this.setState({ exit: true })
return
}
}
render () {
if (this.state.exit === true) {
return <Redirect to="/" />
}
if (this.state.server === null) {
return null //SPINNER
}
return <div className="landing uk-width-1-1 uk-text-center">
<div className="uk-container">
<section>
<h1>Hey there.</h1>
<h4>{this.state.server.name} uses Roleypoly to manage self-assignable roles.</h4>
<h5><span role="img">💖</span></h5>
</section>
<section>
<Link to={`/oauth/flow?r=${window.location.pathname}`} className="uk-button rp-button discord"><img src={discordLogo} className="rp-button-logo"/> Sign in with Discord</Link>
</section>
</div>
</div>
}
}

View file

@ -9,6 +9,7 @@ import Navigation from './Navigation'
import RolePicker from '../role-picker'
import RoleEditor from '../role-editor'
import AddServer from '../add-server'
import Error404 from '../../pages/Error404'
// import mockData from './mockData'
@ -23,6 +24,8 @@ const mapState = ({ servers, user, appState }) => {
@connect(mapState)
class Servers extends Component {
get defaultPath () {
console.log(this.props.servers.toJS())
const first = this.props.servers.first()
if (first != null) {
return first.get('id')
@ -35,18 +38,15 @@ class Servers extends Component {
return <div className="servers">
<Navigation className="servers__nav" servers={this.props.servers} user={this.props.user} />
<div className='servers__content'>
<Switch>
<Route path='/s/' exact render={() => <Redirect to={`/s/${this.defaultPath}`} />} />
<Route path='/s/:server/edit' component={RoleEditor} />
<Route path='/s/:server' render={() =>
<Scrollbars className={`fade-element ${(this.props.fade) ? 'fade' : ''}`} autoHeight autoHeightMax='calc(100vh - 80px)'>
<Switch>
<Route path='/s/add' component={AddServer} exact />
<Route path='/s/:server' component={RolePicker} exact />
</Switch>
</Scrollbars>
} />
</Switch>
<Scrollbars className={`fade-element ${(this.props.fade) ? 'fade' : ''}`} autoHeight autoHeightMax='calc(100vh - 80px)'>
<Switch>
<Route path='/s/add' component={AddServer} exact />
<Route path='/s/:server/edit' component={RoleEditor} />
<Route path='/s/:server' component={RolePicker} />
<Route path='/s' exact render={() => <Redirect to={`/s/${this.defaultPath}`} />} />
<Route component={Error404} />
</Switch>
</Scrollbars>
</div>
</div>
}

View file

@ -1,35 +1,14 @@
import React, { Component, Fragment } from 'react'
import { Link } from 'react-router-dom'
import Scrollbars from 'react-custom-scrollbars'
import Typist from 'react-typist'
import moment from 'moment'
import React from 'react'
import './landing.sass'
import discordLogo from './images/discord-logo.svg'
import RoleypolyDemo from '../components/demos/roleypoly'
import TypingDemo from '../components/demos/typing'
const Landing = ({ root = false }) =>
const Error404 = ({ root = false }) =>
<div className="landing uk-width-1-1 uk-text-center">
<div className="uk-container">
<section>
<h1>Self-assignable Discord roles for humans.</h1>
<h4>Ditch bot commands once and for all.</h4>
</section>
<section>
<Link to="/oauth/flow" className="uk-button rp-button discord"><img src={discordLogo} className="rp-button-logo"/> Sign in with Discord</Link>
</section>
<section uk-grid="">
{/* Typist */}
<div className="uk-width-1-2">
<TypingDemo />
<p className="subtext">Why are we stuck in the stupid ages?</p>
</div>
{/* role side */}
<div className="uk-width-1-2">
<RoleypolyDemo />
<p className="subtext">It's 2018. We can do better.</p>
</div>
<h1><span role="img">💔</span> g-gomen nasai</h1>
<h4>I'm not sure what page you were looking for <span role="img">😢</span></h4>
</section>
</div>
</div>
export default Landing
export default Error404

View file

@ -1,35 +0,0 @@
import React, { Component, Fragment } from 'react'
import { Link } from 'react-router-dom'
import Scrollbars from 'react-custom-scrollbars'
import Typist from 'react-typist'
import moment from 'moment'
import './landing.sass'
import discordLogo from './images/discord-logo.svg'
import RoleypolyDemo from '../components/demos/roleypoly'
import TypingDemo from '../components/demos/typing'
const Landing = ({ root = false }) =>
<div className="landing uk-width-1-1 uk-text-center">
<div className="uk-container">
<section>
<h1>Self-assignable Discord roles for humans.</h1>
<h4>Ditch bot commands once and for all.</h4>
</section>
<section>
<Link to="/oauth/flow" className="uk-button rp-button discord"><img src={discordLogo} className="rp-button-logo"/> Sign in with Discord</Link>
</section>
<section uk-grid="">
{/* Typist */}
<div className="uk-width-1-2">
<TypingDemo />
<p className="subtext">Why are we stuck in the stupid ages?</p>
</div>
{/* role side */}
<div className="uk-width-1-2">
<RoleypolyDemo />
<p className="subtext">It's 2018. We can do better.</p>
</div>
</section>
</div>
</div>
export default Landing

View file

@ -6,7 +6,6 @@ import './pages.sass'
import WhyNoRoles from './WhyNoRoles'
import Error404 from './Error404'
export { default as Landing } from './Landing'
export { default as ServerLanding } from './ServerLanding'
export { default as Error404 } from './Error404'
const Pages = (props) => {

View file

@ -7,7 +7,8 @@ import Servers from '../components/servers'
import OauthCallback from '../components/oauth-callback'
import OauthFlow from '../components/oauth-flow'
import OauthBotFlow from '../components/oauth-bot-flow'
import Pages, { Landing, Error404, ServerLanding } from '../pages'
import Pages, { Landing, Error404 } from '../pages'
import ServerLanding from '../components/servers/ServerLanding'
const aaa = (props) => (<div>{ JSON.stringify(props) }</div>)
@ -22,18 +23,15 @@ export default class AppRouter extends Component {
}
return <Switch>
{ (isLoggedIn)
{ (isLoggedIn === true)
// YES LOGGED IN
? <Fragment>
<Route path='/s' component={Servers} />
<Route path='/root' component={aaa} />
</Fragment>
? <Route path='/s' component={Servers} />
// NOT LOGGED IN
: <Fragment>
<Route path='/s' component={ServerLanding} />
</Fragment>
: [<Route path='/s/:server' key={1} component={ServerLanding} />, <Route path='/s' key={2} render={() => <Redirect to="/" />} />]
}
{/* GENERAL ROUTES */}