mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-04-25 04:09:12 +00:00
sync
This commit is contained in:
parent
7dd7c170b4
commit
86a222fb98
20 changed files with 291 additions and 46 deletions
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
|
@ -49,10 +49,31 @@ module.exports = (R, $) => {
|
|||
})
|
||||
|
||||
R.get('/api/auth/redirect', ctx => {
|
||||
ctx.body = { url: $.discord.getAuthUrl() }
|
||||
const url = $.discord.getAuthUrl()
|
||||
if (ctx.query.url === '✔️') {
|
||||
ctx.body = { url }
|
||||
return
|
||||
}
|
||||
|
||||
ctx.redirect(url)
|
||||
})
|
||||
|
||||
R.post('/api/auth/logout', ctx => {
|
||||
ctx.session = null
|
||||
})
|
||||
|
||||
R.get('/api/oauth/bot', ctx => {
|
||||
const url = $.discord.getBotJoinUrl()
|
||||
if (ctx.query.url === '✔️') {
|
||||
ctx.body = { url }
|
||||
return
|
||||
}
|
||||
|
||||
ctx.redirect(url)
|
||||
})
|
||||
|
||||
|
||||
R.get('/api/oauth/bot/callback', ctx => {
|
||||
console.log(ctx.request)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -67,9 +67,13 @@ module.exports = (R, $) => {
|
|||
gm = await gm.addRoles(added.filter(pred))
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (removed.length > 0) {
|
||||
gm = await gm.removeRoles(removed.filter(pred))
|
||||
gm.removeRoles(removed.filter(pred))
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
// console.log('role patch', { added, removed, allowedRoles, addedFiltered: added.filterNot(pred), removedFiltered: removed.filterNot(pred) })
|
||||
|
||||
ctx.body = { ok: true }
|
||||
})
|
||||
|
|
|
@ -18,6 +18,10 @@ Array.prototype.areduce = async function (predicate, acc = []) { // eslint-disab
|
|||
return acc
|
||||
}
|
||||
|
||||
Array.prototype.filterNot = Array.prototype.filterNot || function (predicate) {
|
||||
return this.filter(v => !predicate(v))
|
||||
}
|
||||
|
||||
// Create the server and socket.io server
|
||||
const server = http.createServer(app.callback())
|
||||
const io = _io(server, { transports: ['websocket'], path: '/api/socket.io', wsEngine: 'uws' })
|
||||
|
|
|
@ -137,7 +137,7 @@ class DiscordService extends Service {
|
|||
// returns the bot join url with MANAGE_ROLES permission
|
||||
// MANAGE_ROLES is the only permission we really need.
|
||||
getBotJoinUrl () {
|
||||
return `https://discordapp.com/oauth2/authorize?client_id=${this.clientId}&scope=bot&permissions=268435456&redirect_uri=${this.botCallback}`
|
||||
return `https://discordapp.com/oauth2/authorize?client_id=${this.clientId}&scope=bot&permissions=268435456`
|
||||
}
|
||||
|
||||
mentionResponse (message) {
|
||||
|
@ -215,6 +215,7 @@ class DiscordService extends Service {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = DiscordService
|
||||
|
|
|
@ -25,12 +25,12 @@ class PresentationService extends Service {
|
|||
async presentableServers (collection, userId) {
|
||||
return collection.array().areduce(async (acc, server) => {
|
||||
const gm = server.members.get(userId)
|
||||
acc.push(await this.presentableServer(server, gm))
|
||||
acc.push(await this.presentableServer(server, gm, { incRoles: false }))
|
||||
return acc
|
||||
})
|
||||
}
|
||||
|
||||
async presentableServer (server, gm) {
|
||||
async presentableServer (server, gm, { incRoles = true } = {}) {
|
||||
const sd = await this.ctx.server.get(server.id)
|
||||
|
||||
return {
|
||||
|
@ -45,7 +45,7 @@ class PresentationService extends Service {
|
|||
ownerID: server.ownerID,
|
||||
icon: server.icon
|
||||
},
|
||||
roles: (await this.rolesByServer(server, sd)).map(r => ({ ...r, selected: gm.roles.has(r.id) })),
|
||||
roles: (incRoles) ? (await this.rolesByServer(server, sd)).map(r => ({ ...r, selected: gm.roles.has(r.id) })) : [],
|
||||
message: sd.message,
|
||||
categories: sd.categories,
|
||||
perms: this.discord.getPermissions(gm)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import superagent from 'superagent'
|
||||
import { push } from 'react-router-redux'
|
||||
|
||||
export const fetchServers = async dispatch => {
|
||||
const rsp = await superagent.get('/api/servers')
|
||||
|
@ -46,3 +47,38 @@ export const userLogout = async dispatch => {
|
|||
|
||||
window.location.href = '/'
|
||||
}
|
||||
|
||||
export const startServerPolling = dispatch => {
|
||||
return poll(window.__APP_STORE__.dispatch, window.__APP_STORE__.getState) // let's not cheat... :c
|
||||
}
|
||||
|
||||
const poll = (dispatch, getState) => {
|
||||
const { servers } = getState()
|
||||
let stop = false
|
||||
const stopPolling = () => { stop = true }
|
||||
const pollFunc = async () => {
|
||||
if (stop) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await fetchServers(dispatch)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
setTimeout(pollFunc, 5000)
|
||||
}
|
||||
|
||||
const newServers = getState().servers
|
||||
if (servers.size >= newServers.size) {
|
||||
setTimeout(pollFunc, 5000)
|
||||
} else {
|
||||
const old = servers.keySeq().toSet()
|
||||
const upd = newServers.keySeq().toSet()
|
||||
const newSrv = upd.subtract(old)
|
||||
stopPolling()
|
||||
dispatch(push(`/s/${newSrv.toJS()[0]}/edit`))
|
||||
}
|
||||
}
|
||||
|
||||
pollFunc()
|
||||
return stopPolling
|
||||
}
|
||||
|
|
|
@ -1,9 +1,39 @@
|
|||
import React, { Component } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import TypingDemo from '../demos/typing'
|
||||
import RoleypolyDemo from '../demos/roleypoly'
|
||||
import * as Actions from '../../actions'
|
||||
import './styles.sass'
|
||||
import discordLogo from '../../pages/images/discord-logo.svg'
|
||||
|
||||
export default class AddServer extends Component {
|
||||
render () {
|
||||
return <div className="inner">
|
||||
polling = null
|
||||
|
||||
componentDidMount () {
|
||||
this.pollingStop = Actions.startServerPolling(this.props.dispatch)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.pollingStop != null) {
|
||||
this.pollingStop()
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div className="inner add-server">
|
||||
<h2>What is Roleypoly?</h2>
|
||||
<p className="add-server__header">
|
||||
Roleypoly is a helper bot to help server members assign themselves roles on Discord.
|
||||
</p>
|
||||
<div className="add-server__grid">
|
||||
<div><TypingDemo /></div>
|
||||
<div className="text">Could you easily remember 250 role names? You'd use images or bot commands to tell everyone what they can assign. This kinda limits how <i>many</i> roles you can reasonably have. And don't even start with emojis. <span alt="" role="img">💢</span></div>
|
||||
<div className="text right">Just click. <span role="img">🌈 💖</span></div>
|
||||
<div className="add-server__darkbg"><RoleypolyDemo /></div>
|
||||
</div>
|
||||
<div className="add-server__header">
|
||||
<a href="/oauth/bot/flow" target="_blank" className="uk-button rp-button discord"><img src={discordLogo} className="rp-button-logo" alt=""/> Authorize via Discord</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
29
UI/src/components/add-server/styles.sass
Normal file
29
UI/src/components/add-server/styles.sass
Normal file
|
@ -0,0 +1,29 @@
|
|||
.add-server
|
||||
text-align: center
|
||||
.paper
|
||||
background-color: hsla(0,0%,100%,0.05)
|
||||
padding: 30px
|
||||
|
||||
.text
|
||||
font-size: 0.9rem
|
||||
text-align: left
|
||||
|
||||
&.right
|
||||
text-align: right
|
||||
font-size: 1.1em
|
||||
|
||||
&__header
|
||||
margin: 45px 0
|
||||
|
||||
&__grid
|
||||
display: grid
|
||||
grid-template-columns: 1fr 1fr
|
||||
grid-template-rows: 1fr 1fr
|
||||
grid-gap: 10px
|
||||
|
||||
>div
|
||||
align-self: center
|
||||
|
||||
&__darkbg
|
||||
background-color: var(--c-1)
|
||||
padding: 20px
|
12
UI/src/components/demos/roleypoly.js
Normal file
12
UI/src/components/demos/roleypoly.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import React from 'react'
|
||||
import RoleDemo from '../role/demo'
|
||||
|
||||
const RoleypolyDemo = () => <div className="demo__roleypoly">
|
||||
<RoleDemo name="a cute role ♡" color="#3EC1BF" />
|
||||
<RoleDemo name="a vanity role ♡" color="#F7335B" />
|
||||
<RoleDemo name="a brave role ♡" color="#A8D0B8" />
|
||||
<RoleDemo name="a proud role ♡" color="#5C8B88" />
|
||||
<RoleDemo name="a wonderful role ♡" color="#D6B3C7" />
|
||||
</div>
|
||||
|
||||
export default RoleypolyDemo
|
29
UI/src/components/demos/typing.js
Normal file
29
UI/src/components/demos/typing.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import React from 'react'
|
||||
import moment from 'moment'
|
||||
import Typist from 'react-typist'
|
||||
import './typing.sass'
|
||||
|
||||
const Typing = () => <div className="demo__discord rp-discord">
|
||||
<div className="discord__chat">
|
||||
<span className="timestamp">{moment().format('LT')}</span>
|
||||
<span className="username">Kata カタ</span>
|
||||
<span className="text">Hey, I want some roles!</span>
|
||||
</div>
|
||||
<div className="discord__textarea">
|
||||
<Typist cursor={{ blink: true }}>
|
||||
<span>.iam a cute role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a vanity role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a brave role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a proud role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a wonderful role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>i have too many roles.</span>
|
||||
</Typist>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
export default Typing
|
48
UI/src/components/demos/typing.sass
Normal file
48
UI/src/components/demos/typing.sass
Normal file
|
@ -0,0 +1,48 @@
|
|||
.demo__discord
|
||||
--not-quite-black: #23272A
|
||||
--dark-but-not-black: #2C2F33
|
||||
--greyple: #99AAB5
|
||||
--blurple: var(--c-discord)
|
||||
|
||||
background-color: var(--dark-but-not-black)
|
||||
padding: 10px
|
||||
text-align: left
|
||||
color: var(--c-white)
|
||||
|
||||
.Typist .Cursor
|
||||
display: inline-block
|
||||
color: transparent
|
||||
border-left: 1px solid var(--c-white)
|
||||
user-select: none
|
||||
|
||||
&--blinking
|
||||
opacity: 1
|
||||
animation: blink 2s ease-in-out infinite
|
||||
|
||||
@keyframes blink
|
||||
0%
|
||||
opacity: 1
|
||||
50%
|
||||
opacity: 0
|
||||
100%
|
||||
opacity: 1
|
||||
|
||||
.discord
|
||||
&__chat
|
||||
padding: 10px 0
|
||||
|
||||
span
|
||||
display: inline-block
|
||||
margin-left: 5px
|
||||
|
||||
.timestamp
|
||||
font-size: 0.7em
|
||||
color: hsla(0,0%,100%,.2)
|
||||
|
||||
.username
|
||||
font-weight: bold
|
||||
|
||||
&__textarea
|
||||
background-color: hsla(218,5%,47%,.3)
|
||||
border-radius: 5px
|
||||
padding: 10px
|
27
UI/src/components/oauth-bot-flow/index.js
Normal file
27
UI/src/components/oauth-bot-flow/index.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import React, { Component } from 'react'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
import superagent from 'superagent'
|
||||
import { connect } from 'react-redux'
|
||||
import { push } from 'react-router-redux'
|
||||
import { fetchServers } from '../../actions'
|
||||
|
||||
@connect()
|
||||
class OauthCallback extends Component {
|
||||
state = {
|
||||
notReady: true,
|
||||
message: 'chotto matte kudasai...',
|
||||
url: null
|
||||
}
|
||||
|
||||
async componentDidMount () {
|
||||
const { body: { url } } = await superagent.get('/api/oauth/bot?url=✔️')
|
||||
this.setState({ url, notReady: false })
|
||||
window.location.href = url
|
||||
}
|
||||
|
||||
render () {
|
||||
return (this.state.notReady) ? this.state.message : <a style={{zIndex: 10000}} href={this.state.url}>Something oopsed, click me to get to where you meant.</a>
|
||||
}
|
||||
}
|
||||
|
||||
export default OauthCallback
|
|
@ -12,7 +12,7 @@ class OauthCallback extends Component {
|
|||
}
|
||||
|
||||
async componentDidMount () {
|
||||
const { body: { url } } = await superagent.get('/api/auth/redirect')
|
||||
const { body: { url } } = await superagent.get('/api/auth/redirect?url=✔️')
|
||||
try {
|
||||
const rsp = await superagent.get('/api/auth/user')
|
||||
this.props.dispatch({
|
||||
|
|
|
@ -113,7 +113,7 @@ class RoleEditor extends Component {
|
|||
|
||||
render () {
|
||||
const { server } = this.props
|
||||
if (server.getIn(['server', 'perms', 'canManageRoles']) !== true) {
|
||||
if (server.getIn(['perms', 'canManageRoles']) !== true) {
|
||||
return <Redirect to={`/s/${server.get('id')}`} />
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@ import { Link } from 'react-router-dom'
|
|||
import Scrollbars from 'react-custom-scrollbars'
|
||||
import Logotype from '../logotype'
|
||||
import './wrapper.sass'
|
||||
import discordLogo from '../../pages/images/discord-logo.svg'
|
||||
|
||||
class Wrapper extends Component {
|
||||
render () {
|
||||
return <div className='wrapper'>
|
||||
<Scrollbars autoHeight autoHeightMax='100vh'>
|
||||
<Scrollbars autoHeight autoHeightMax='calc(100vh + 2px)'>
|
||||
<div className='wrapper__background' />
|
||||
<div className='wrapper__container'>
|
||||
<nav uk-navbar='' className='uk-navbar-transparent wrapper__nav'>
|
||||
|
@ -18,7 +19,9 @@ class Wrapper extends Component {
|
|||
</div>
|
||||
<div className='uk-navbar-right'>
|
||||
<ul className='uk-navbar-nav'>
|
||||
<li><Link to='/start'>Get Started</Link></li>
|
||||
<li><div className='wrapper__nav__button'>
|
||||
<a href="/oauth/bot/flow" target="_blank" className="uk-button rp-button discord-alt"><img src={discordLogo} className="rp-button-logo" alt=""/> Add Roleypoly</a>
|
||||
</div></li>
|
||||
<li><a href='https://discord.gg/PWQUVsd'>Support Discord</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -21,4 +21,15 @@
|
|||
padding: 0 20px
|
||||
z-index: 1000
|
||||
|
||||
&__button
|
||||
box-sizing: border-box
|
||||
height: 82px
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
|
||||
&>.rp-button
|
||||
padding-left: 15px
|
||||
padding-right: 15px
|
||||
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
border-radius: 2px
|
||||
transition: transform 0.2s ease-out, box-shadow 0.2s ease-out
|
||||
position: relative
|
||||
box-sizing: border-box
|
||||
transform: translateZ(0)
|
||||
|
||||
&::after
|
||||
content: ""
|
||||
|
@ -13,17 +15,18 @@
|
|||
left: 0
|
||||
background-color: rgba(0,0,0,0.1)
|
||||
border-radius: 2px
|
||||
transform: translateZ(0)
|
||||
opacity: 0
|
||||
transition: opacity 0.15s ease-in-out
|
||||
|
||||
&:hover
|
||||
transform: translateY(-1px)
|
||||
transform: translateZ(0) translateY(-1px)
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.3)
|
||||
&::after
|
||||
opacity: 0.7
|
||||
|
||||
&:active
|
||||
transform: translateY(0px)
|
||||
transform: translateZ(0) translateY(0px)
|
||||
box-shadow: none
|
||||
&::after
|
||||
opacity: 1
|
||||
|
@ -40,6 +43,14 @@
|
|||
background-color: var(--c-discord)
|
||||
color: var(--c-white)
|
||||
|
||||
&.discord-alt
|
||||
background-color: transparent
|
||||
color: var(--c-white)
|
||||
border: 1px solid var(--c-discord)
|
||||
&::after
|
||||
background-color: hsla(0,0%,100%,0.05)
|
||||
transition: opacity 0.3s ease-in-out
|
||||
|
||||
&-logo
|
||||
height: 1.6rem
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ import Typist from 'react-typist'
|
|||
import moment from 'moment'
|
||||
import './landing.sass'
|
||||
import discordLogo from './images/discord-logo.svg'
|
||||
import RoleDemo from '../components/role/demo'
|
||||
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">
|
||||
|
@ -20,39 +21,12 @@ const Landing = ({ root = false }) =>
|
|||
<section uk-grid="">
|
||||
{/* Typist */}
|
||||
<div className="uk-width-1-2">
|
||||
<div className="landing__discord rp-discord">
|
||||
<div className="discord__chat">
|
||||
<span className="timestamp">{moment().format('LT')}</span>
|
||||
<span className="username">Kata カタ</span>
|
||||
<span className="text">Hey, I want some roles!</span>
|
||||
</div>
|
||||
<div className="discord__textarea">
|
||||
<Typist cursor={{ blink: true }}>
|
||||
<span>.iam a cute role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a vanity role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a brave role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a proud role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>.iam a wonderful role ♡</span>
|
||||
<Typist.Backspace count={30} delay={1500} />
|
||||
<span>i have too many roles.</span>
|
||||
</Typist>
|
||||
</div>
|
||||
</div>
|
||||
<TypingDemo />
|
||||
<p className="subtext">Why are we stuck in the stupid ages?</p>
|
||||
</div>
|
||||
{/* role side */}
|
||||
<div className="uk-width-1-2">
|
||||
<div className="landing__roleypoly">
|
||||
<RoleDemo name="a cute role ♡" color="#3EC1BF" />
|
||||
<RoleDemo name="a vanity role ♡" color="#F7335B" />
|
||||
<RoleDemo name="a brave role ♡" color="#A8D0B8" />
|
||||
<RoleDemo name="a proud role ♡" color="#5C8B88" />
|
||||
<RoleDemo name="a wonderful role ♡" color="#D6B3C7" />
|
||||
</div>
|
||||
<RoleypolyDemo />
|
||||
<p className="subtext">It's 2018. We can do better.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { withRouter } from 'react-router'
|
|||
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 } from '../pages'
|
||||
|
||||
const aaa = (props) => (<div>{ JSON.stringify(props) }</div>)
|
||||
|
@ -25,6 +26,7 @@ export default class AppRouter extends Component {
|
|||
|
||||
<Route path='/oauth/callback' component={OauthCallback} />
|
||||
<Route path='/oauth/flow' component={OauthFlow} />
|
||||
<Route path='/oauth/bot/flow' component={OauthBotFlow} />
|
||||
<Route path="/p/landing" exact component={Landing} />
|
||||
<Route path='/p' component={Pages} />
|
||||
<Route path='/help' component={Pages} />
|
||||
|
|
Loading…
Add table
Reference in a new issue