From 86a222fb985e99c0eeb6af473fbb675b557c6331 Mon Sep 17 00:00:00 2001 From: Katalina / stardust Date: Sat, 6 Jan 2018 17:40:52 -0600 Subject: [PATCH] sync --- .vscode/settings.json | 3 ++ Server/api/auth.js | 23 ++++++++++- Server/api/servers.js | 10 +++-- Server/index.js | 4 ++ Server/services/discord.js | 3 +- Server/services/presentation.js | 6 +-- UI/src/actions/index.js | 36 +++++++++++++++++ UI/src/components/add-server/index.js | 34 +++++++++++++++- UI/src/components/add-server/styles.sass | 29 ++++++++++++++ UI/src/components/demos/roleypoly.js | 12 ++++++ UI/src/components/demos/typing.js | 29 ++++++++++++++ UI/src/components/demos/typing.sass | 48 +++++++++++++++++++++++ UI/src/components/oauth-bot-flow/index.js | 27 +++++++++++++ UI/src/components/oauth-flow/index.js | 2 +- UI/src/components/role-editor/index.js | 2 +- UI/src/components/wrapper/index.js | 7 +++- UI/src/components/wrapper/wrapper.sass | 11 ++++++ UI/src/generic.sass | 15 ++++++- UI/src/pages/Landing.js | 34 ++-------------- UI/src/router/index.js | 2 + 20 files changed, 291 insertions(+), 46 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 UI/src/components/add-server/styles.sass create mode 100644 UI/src/components/demos/roleypoly.js create mode 100644 UI/src/components/demos/typing.js create mode 100644 UI/src/components/demos/typing.sass create mode 100644 UI/src/components/oauth-bot-flow/index.js 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. 🌈 💖
+
+
+
+ Authorize via Discord +
} } 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
- +
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 { +