diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..ed94f44
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "git.ignoreLimitWarning": true
+}
\ No newline at end of file
diff --git a/Server/api/auth.js b/Server/api/auth.js
index 2f77cd9..a426ef5 100644
--- a/Server/api/auth.js
+++ b/Server/api/auth.js
@@ -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)
+ })
}
diff --git a/Server/api/servers.js b/Server/api/servers.js
index fe0aa0d..5da9905 100644
--- a/Server/api/servers.js
+++ b/Server/api/servers.js
@@ -67,9 +67,13 @@ module.exports = (R, $) => {
gm = await gm.addRoles(added.filter(pred))
}
- if (removed.length > 0) {
- gm = await gm.removeRoles(removed.filter(pred))
- }
+ setTimeout(() => {
+ if (removed.length > 0) {
+ 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 }
})
diff --git a/Server/index.js b/Server/index.js
index a1540c9..a016847 100644
--- a/Server/index.js
+++ b/Server/index.js
@@ -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' })
diff --git a/Server/services/discord.js b/Server/services/discord.js
index 45ced28..f12ae59 100644
--- a/Server/services/discord.js
+++ b/Server/services/discord.js
@@ -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
diff --git a/Server/services/presentation.js b/Server/services/presentation.js
index 7d80c96..e150511 100644
--- a/Server/services/presentation.js
+++ b/Server/services/presentation.js
@@ -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)
diff --git a/UI/src/actions/index.js b/UI/src/actions/index.js
index 0a767d8..b277194 100644
--- a/UI/src/actions/index.js
+++ b/UI/src/actions/index.js
@@ -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
+}
diff --git a/UI/src/components/add-server/index.js b/UI/src/components/add-server/index.js
index a383a79..97355e3 100644
--- a/UI/src/components/add-server/index.js
+++ b/UI/src/components/add-server/index.js
@@ -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 {
+ polling = null
+
+ componentDidMount () {
+ this.pollingStop = Actions.startServerPolling(this.props.dispatch)
+ }
+
+ componentWillUnmount () {
+ if (this.pollingStop != null) {
+ this.pollingStop()
+ }
+ }
+
render () {
- return
-
+ return
+
What is Roleypoly?
+
+ Roleypoly is a helper bot to help server members assign themselves roles on Discord.
+
+
+
+
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 many roles you can reasonably have. And don't even start with emojis. 💢
+
Just click. 🌈 💖
+
+
+
}
}
diff --git a/UI/src/components/add-server/styles.sass b/UI/src/components/add-server/styles.sass
new file mode 100644
index 0000000..2a5b1a6
--- /dev/null
+++ b/UI/src/components/add-server/styles.sass
@@ -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
\ No newline at end of file
diff --git a/UI/src/components/demos/roleypoly.js b/UI/src/components/demos/roleypoly.js
new file mode 100644
index 0000000..a58f58a
--- /dev/null
+++ b/UI/src/components/demos/roleypoly.js
@@ -0,0 +1,12 @@
+import React from 'react'
+import RoleDemo from '../role/demo'
+
+const RoleypolyDemo = () =>
+
+
+
+
+
+
+
+export default RoleypolyDemo
diff --git a/UI/src/components/demos/typing.js b/UI/src/components/demos/typing.js
new file mode 100644
index 0000000..d8778ab
--- /dev/null
+++ b/UI/src/components/demos/typing.js
@@ -0,0 +1,29 @@
+import React from 'react'
+import moment from 'moment'
+import Typist from 'react-typist'
+import './typing.sass'
+
+const Typing = () =>
+
+ {moment().format('LT')}
+ Kata カタ
+ Hey, I want some roles!
+
+
+
+ .iam a cute role ♡
+
+ .iam a vanity role ♡
+
+ .iam a brave role ♡
+
+ .iam a proud role ♡
+
+ .iam a wonderful role ♡
+
+ i have too many roles.
+
+
+
+
+export default Typing
diff --git a/UI/src/components/demos/typing.sass b/UI/src/components/demos/typing.sass
new file mode 100644
index 0000000..e0bdcc3
--- /dev/null
+++ b/UI/src/components/demos/typing.sass
@@ -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
\ No newline at end of file
diff --git a/UI/src/components/oauth-bot-flow/index.js b/UI/src/components/oauth-bot-flow/index.js
new file mode 100644
index 0000000..7786b01
--- /dev/null
+++ b/UI/src/components/oauth-bot-flow/index.js
@@ -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 :
Something oopsed, click me to get to where you meant.
+ }
+}
+
+export default OauthCallback
diff --git a/UI/src/components/oauth-flow/index.js b/UI/src/components/oauth-flow/index.js
index 217ff93..8214dab 100644
--- a/UI/src/components/oauth-flow/index.js
+++ b/UI/src/components/oauth-flow/index.js
@@ -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({
diff --git a/UI/src/components/role-editor/index.js b/UI/src/components/role-editor/index.js
index 9da0cd9..77f1640 100644
--- a/UI/src/components/role-editor/index.js
+++ b/UI/src/components/role-editor/index.js
@@ -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
}
diff --git a/UI/src/components/wrapper/index.js b/UI/src/components/wrapper/index.js
index e54998e..0636da2 100644
--- a/UI/src/components/wrapper/index.js
+++ b/UI/src/components/wrapper/index.js
@@ -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
-
+
@@ -18,7 +19,9 @@ class Wrapper extends Component {
diff --git a/UI/src/components/wrapper/wrapper.sass b/UI/src/components/wrapper/wrapper.sass
index 32628e8..63280e5 100644
--- a/UI/src/components/wrapper/wrapper.sass
+++ b/UI/src/components/wrapper/wrapper.sass
@@ -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
+
\ No newline at end of file
diff --git a/UI/src/generic.sass b/UI/src/generic.sass
index 43ea289..b6f23a3 100644
--- a/UI/src/generic.sass
+++ b/UI/src/generic.sass
@@ -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
diff --git a/UI/src/pages/Landing.js b/UI/src/pages/Landing.js
index 9828e46..2c2706b 100644
--- a/UI/src/pages/Landing.js
+++ b/UI/src/pages/Landing.js
@@ -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 }) =>
@@ -20,39 +21,12 @@ const Landing = ({ root = false }) =>
{/* Typist */}
-
-
- {moment().format('LT')}
- Kata カタ
- Hey, I want some roles!
-
-
-
- .iam a cute role ♡
-
- .iam a vanity role ♡
-
- .iam a brave role ♡
-
- .iam a proud role ♡
-
- .iam a wonderful role ♡
-
- i have too many roles.
-
-
-
+
Why are we stuck in the stupid ages?
{/* role side */}
-
-
-
-
-
-
-
+
It's 2018. We can do better.
diff --git a/UI/src/router/index.js b/UI/src/router/index.js
index 1d09866..f155134 100644
--- a/UI/src/router/index.js
+++ b/UI/src/router/index.js
@@ -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) => (
{ JSON.stringify(props) }
)
@@ -25,6 +26,7 @@ export default class AppRouter extends Component {
+