diff --git a/index.js b/index.js index 343d61806..a13213fe4 100644 --- a/index.js +++ b/index.js @@ -2,19 +2,64 @@ require('dotenv').config() const { ApolloServer, UserInputError, AuthenticationError, gql } = require('apollo-server-express') const mongoose = require('mongoose') const express = require('express') +const session = require('express-session') +const bodyParser = require('body-parser') +const cookieParser = require('cookie-parser') +const uuid = require('node-uuid') const axios = require('axios') const cors = require('cors') +const passport = require('passport') +const DiscordStrategy = require('passport-discord').Strategy const Placement = require('./models/placement') const Player = require('./models/player') const Maplist = require('./models/maplist') const Link = require('./models/link') -//const User = require('./models/user') +const User = require('./models/user') const jwt = require('jsonwebtoken') const path = require('path') mongoose.set('useFindAndModify', false) mongoose.set('useCreateIndex', true) +passport.use(new DiscordStrategy({ + clientID: process.env.CLIENT_ID, + clientSecret: process.env.CLIENT_SECRET, + callbackURL: 'http://localhost:3001/auth/discord/callback', + scope: ['identify', 'connections'] +}, +function(accessToken, refreshToken, profile, cb) { + const userToSave = { + username: profile.username, + discriminator: profile.discriminator, + avatar: profile.avatar, + discord_id: profile.id + } + for (var i = 0; i < profile.connections.length; i++) { + const connection = profile.connections[i] + if (connection.visibility === 1 && connection.verified) { + if (connection.type === 'twitch') { + userToSave.twitch_name = connection.name + } else if (connection.type === 'twitter') { + userToSave.twitter_name = connection.name + } + } + } + + User.updateOne({discord_id: userToSave.discord_id}, userToSave, {upsert: true}, function(err, user) { + return cb(err, userToSave) + }) +})) + +passport.serializeUser(function(user, done) { + done(null, user.discord_id) +}) + +passport.deserializeUser(function(discord_id, done) { + User.findOne({discord_id}, function(err, user) { + done(err, user) + }) +}) + let rotationData = {timestamp: 0} console.log('connecting to MongoDB') @@ -28,12 +73,6 @@ mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, dbName: "prod }) const typeDefs = gql` - type User { - id: ID! - username: String! - passwordHash: String! - } - type Player { id: ID! name: String! @@ -105,6 +144,15 @@ const typeDefs = gql` type: LinkType! } + type User { + username: String! + discriminator: String! + avatar: String + discord_id: String! + twitch_name: String! + twitter_name: String! + } + type Token { value: String! } @@ -128,6 +176,7 @@ const typeDefs = gql` maplists: [Maplist!]! rotationData: String links: [Link!]! + user: User } type Mutation { @@ -424,11 +473,15 @@ const resolvers = { links: (root, args) => { return Link .find({}) + .sort({ "title": "asc" }) .catch(e => { throw new UserInputError(e.message, { invalidArgs: args, }) }) + }, + user: (root, args, ctx) => { + return ctx.user } } } @@ -436,28 +489,46 @@ const resolvers = { const server = new ApolloServer({ typeDefs, resolvers, - context: async ({ req }) => { - const auth = req ? req.headers.authorization : null - if (auth && auth.toLowerCase().startsWith('bearer ')) { - const decodedToken = jwt.verify( - auth.substring(7), process.env.JWT_SECRET - ) - const currentUser = await User.findById(decodedToken.id) - return { currentUser } - } + context: ({ req }) => { + return { user: req.user } } }) const app = express() -app.use(cors()) -server.applyMiddleware({ app }) +app.use(cors()) app.use(express.static('build')) +//app.use(cookieParser(process.env.SESSION_SECRET)) probably not needed but will remove later +//app.use(bodyParser.urlencoded({ extended: false })) + +app.use(session({ + secret: process.env.SESSION_SECRET, + resave: false, + saveUninitialized: false + })) + +app.use(passport.initialize()) +app.use(passport.session()) + +app.get('/auth/discord', passport.authenticate('discord')) + +app.get('/auth/discord/callback', passport.authenticate('discord', { + failureRedirect: '/404' +}), function(req, res) { + res.redirect('/u/' + req.user.discord_id) // Successful auth +}) + +app.get('/logout', function(req, res){ + req.logout() + res.redirect('/') +}) app.get('*', (req, res) => { res.sendFile(path.resolve(__dirname, 'build', 'index.html')) }) +server.applyMiddleware({ app }) + const PORT = process.env.PORT || 3001 app.listen({ port: PORT }, () => { console.log(`Server running on http://localhost:${PORT}${server.graphqlPath}`) diff --git a/models/user.js b/models/user.js new file mode 100644 index 000000000..2343a3c2c --- /dev/null +++ b/models/user.js @@ -0,0 +1,12 @@ +const mongoose = require('mongoose') + +const userSchema = new mongoose.Schema({ + username: {type: String, required: true}, + discriminator: {type: String, required: true}, + avatar: {type: String}, + discord_id: {type: String, required: true}, + twitch_name: {type: String}, + twitter_name: {type: String} +}) + +module.exports = mongoose.model('User', userSchema) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fc115aa36..3d070e994 100644 --- a/package-lock.json +++ b/package-lock.json @@ -120,9 +120,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.4.tgz", - "integrity": "sha512-x/8h6FHm14rPWnW2HP5likD/rsqJ3t/77OWx2PLxym0hXbeBWQmcPyHmwX+CtCQpjIfgrUdEoDFcLPwPZWiqzQ==", + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.6.tgz", + "integrity": "sha512-8wr3CA/EMybyb6/V8qvTRKiNkPmgUA26uA9XWD6hlA0yFDuqi4r2L0C2B0U2HAYltJamoYJszlkaWM31vrKsHg==", "requires": { "@types/node": "*", "@types/range-parser": "*" @@ -315,6 +315,27 @@ "express": "^4.0.0", "graphql-subscriptions": "^1.0.0", "graphql-tools": "^4.0.0" + }, + "dependencies": { + "apollo-server-express": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.4.8.tgz", + "integrity": "sha512-i60l32mfVe33jnKDPNYgUKUKu4Al0xEm2HLOSMgtJ9Wbpe/MbOx5X8M5F27fnHYdM+G5XfAErsakAyRGnQJ48Q==", + "requires": { + "@apollographql/graphql-playground-html": "^1.6.6", + "@types/accepts": "^1.3.5", + "@types/body-parser": "1.17.0", + "@types/cors": "^2.8.4", + "@types/express": "4.16.1", + "accepts": "^1.3.5", + "apollo-server-core": "2.4.8", + "body-parser": "^1.18.3", + "cors": "^2.8.4", + "graphql-subscriptions": "^1.0.0", + "graphql-tools": "^4.0.0", + "type-is": "^1.6.16" + } + } } }, "apollo-server-caching": { @@ -367,9 +388,9 @@ "integrity": "sha512-wY/YE3iJVMYC+WYIf8QODBjIP4jhI+oc7kiYo9mrz7LdYPKAgxr/he+NteGcqn/0Ea9K5/ZFTGJDbEstSMeP8g==" }, "apollo-server-express": { - "version": "2.4.8", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.4.8.tgz", - "integrity": "sha512-i60l32mfVe33jnKDPNYgUKUKu4Al0xEm2HLOSMgtJ9Wbpe/MbOx5X8M5F27fnHYdM+G5XfAErsakAyRGnQJ48Q==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.5.0.tgz", + "integrity": "sha512-2gd3VWIqji2jyDYMTTqKzVU4/znjEjugtLUmPgVl5SoBvJSMTsO7VgJv+roBubZGDK8jXXUEXr2a33RtIeHe4g==", "requires": { "@apollographql/graphql-playground-html": "^1.6.6", "@types/accepts": "^1.3.5", @@ -377,12 +398,173 @@ "@types/cors": "^2.8.4", "@types/express": "4.16.1", "accepts": "^1.3.5", - "apollo-server-core": "2.4.8", + "apollo-server-core": "2.5.0", "body-parser": "^1.18.3", "cors": "^2.8.4", "graphql-subscriptions": "^1.0.0", "graphql-tools": "^4.0.0", "type-is": "^1.6.16" + }, + "dependencies": { + "@apollographql/apollo-tools": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.3.7.tgz", + "integrity": "sha512-+ertvzAwzkYmuUtT8zH3Zi6jPdyxZwOgnYaZHY7iLnMVJDhQKWlkyjLMF8wyzlPiEdDImVUMm5lOIBZo7LkGlg==", + "requires": { + "apollo-env": "0.5.1" + } + }, + "apollo-cache-control": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.6.0.tgz", + "integrity": "sha512-66aCF6MHe0/FdD3knphwTv6CCIdb1ZxrMsiRpxP474qqyYVe2jAwBu6aJBn4emffZHZ7i6gp9dY6cPHThjnbKA==", + "requires": { + "apollo-server-env": "2.3.0", + "graphql-extensions": "0.6.0" + } + }, + "apollo-datasource": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.4.0.tgz", + "integrity": "sha512-6QkgnLYwQrW0qv+yXIf617DojJbGmza2XJXUlgnzrGGhxzfAynzEjaLyYkc8rYS1m82vjrl9EOmLHTcnVkvZAQ==", + "requires": { + "apollo-server-caching": "0.4.0", + "apollo-server-env": "2.3.0" + } + }, + "apollo-engine-reporting": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-1.1.0.tgz", + "integrity": "sha512-Dj0BwgcluHL0QVUaquhAoYoLX9Z4DRP/n2REcIwO8d2iy52r+1wN5QqZLx97dEFh7CjhNjTWeysJzc8XMWKa1Q==", + "requires": { + "apollo-engine-reporting-protobuf": "0.3.0", + "apollo-graphql": "^0.2.1-alpha.1", + "apollo-server-core": "2.5.0", + "apollo-server-env": "2.3.0", + "async-retry": "^1.2.1", + "graphql-extensions": "0.6.0" + } + }, + "apollo-engine-reporting-protobuf": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting-protobuf/-/apollo-engine-reporting-protobuf-0.3.0.tgz", + "integrity": "sha512-PYowpx/E+TJT/8nKpp3JmJuKh3x1SZcxDF6Cquj0soV205TUpFFCZQMi91i5ACiEp2AkYvM/GDBIrw+rfIwzTg==", + "requires": { + "protobufjs": "^6.8.6" + } + }, + "apollo-env": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.5.1.tgz", + "integrity": "sha512-fndST2xojgSdH02k5hxk1cbqA9Ti8RX4YzzBoAB4oIe1Puhq7+YlhXGXfXB5Y4XN0al8dLg+5nAkyjNAR2qZTw==", + "requires": { + "core-js": "^3.0.1", + "node-fetch": "^2.2.0", + "sha.js": "^2.4.11" + } + }, + "apollo-graphql": { + "version": "0.2.1-register.1", + "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.2.1-register.1.tgz", + "integrity": "sha512-Z2LOuvYomC9CN9K+mpFVcVQu6Ml5PIJlV+YOkGzFq73xeqWg1InxHqI3eEdCEhxTJq6H8rlWT8ATrMS+4sIhqw==", + "requires": { + "apollo-env": "0.4.1-register.1", + "lodash.sortby": "^4.7.0" + }, + "dependencies": { + "apollo-env": { + "version": "0.4.1-register.1", + "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.4.1-register.1.tgz", + "integrity": "sha512-fg1US7YZ6yW1N0tFq8g4HpCR3eJZmI+rIiHDiknYN9D1MTjvwYdmXYhi7VaPvQ21hV5nMRvfBUMqYXjP+6FsGQ==", + "requires": { + "core-js": "3.0.0-beta.13", + "node-fetch": "^2.2.0", + "sha.js": "^2.4.11" + } + }, + "core-js": { + "version": "3.0.0-beta.13", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.0-beta.13.tgz", + "integrity": "sha512-16Q43c/3LT9NyePUJKL8nRIQgYWjcBhjJSMWg96PVSxoS0PeE0NHitPI3opBrs9MGGHjte1KoEVr9W63YKlTXQ==" + } + } + }, + "apollo-server-caching": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.4.0.tgz", + "integrity": "sha512-GTOZdbLhrSOKYNWMYgaqX5cVNSMT0bGUTZKV8/tYlyYmsB6ey7l6iId3Q7UpHS6F6OR2lstz5XaKZ+T3fDfPzQ==", + "requires": { + "lru-cache": "^5.0.0" + } + }, + "apollo-server-core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.5.0.tgz", + "integrity": "sha512-7hyQ/Rt0hC38bUfxMQmLNHDBIGEBykFWo9EO0W+3o/cno/SqBKd1KKichrABVv+v+SCvZAUutX6gYS5l3G+ULQ==", + "requires": { + "@apollographql/apollo-tools": "^0.3.6-alpha.1", + "@apollographql/graphql-playground-html": "^1.6.6", + "@types/ws": "^6.0.0", + "apollo-cache-control": "0.6.0", + "apollo-datasource": "0.4.0", + "apollo-engine-reporting": "1.1.0", + "apollo-server-caching": "0.4.0", + "apollo-server-env": "2.3.0", + "apollo-server-errors": "2.3.0", + "apollo-server-plugin-base": "0.4.0", + "apollo-tracing": "0.6.0", + "fast-json-stable-stringify": "^2.0.0", + "graphql-extensions": "0.6.0", + "graphql-subscriptions": "^1.0.0", + "graphql-tag": "^2.9.2", + "graphql-tools": "^4.0.0", + "graphql-upload": "^8.0.2", + "sha.js": "^2.4.11", + "subscriptions-transport-ws": "^0.9.11", + "ws": "^6.0.0" + } + }, + "apollo-server-env": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-2.3.0.tgz", + "integrity": "sha512-WIwlkCM/gir0CkoYWPMTCH8uGCCKB/aM074U1bKayvkFOBVO2VgG5x2kgsfkyF05IMQq2/GOTsKhNY7RnUEhTA==", + "requires": { + "node-fetch": "^2.1.2", + "util.promisify": "^1.0.0" + } + }, + "apollo-server-errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.3.0.tgz", + "integrity": "sha512-rUvzwMo2ZQgzzPh2kcJyfbRSfVKRMhfIlhY7BzUfM4x6ZT0aijlgsf714Ll3Mbf5Fxii32kD0A/DmKsTecpccw==" + }, + "apollo-server-plugin-base": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.4.0.tgz", + "integrity": "sha512-iD7ARNtwnvHGd1EMPK0CuodM8d8hgDvFwTfIDzJY04QIQ6/KrBFaWhnCXJsy+HMb47GovwBbq67IK6eb2WJgBg==" + }, + "apollo-tracing": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.6.0.tgz", + "integrity": "sha512-OpYPHVBgcQ/HT2WLXJQWwhilzR1rrl01tZeMU2N7yinsp/oyKngF5aUSMtuvX1k/T3abilQo+w10oAQlBCGdPA==", + "requires": { + "apollo-server-env": "2.3.0", + "graphql-extensions": "0.6.0" + } + }, + "core-js": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.3.tgz", + "integrity": "sha512-PWZ+ZfuaKf178BIAg+CRsljwjIMRV8MY00CbZczkR6Zk5LfkSkjGoaab3+bqRQWVITNZxQB7TFYz+CFcyuamvA==" + }, + "graphql-extensions": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.6.0.tgz", + "integrity": "sha512-SshzmbD68fHXRv2q3St29olMOxHDLQ5e9TOh+Tz2BYxinrfhjFaPNcEefiK/vF295wW827Y58bdO11Xmhf8J+Q==", + "requires": { + "@apollographql/apollo-tools": "^0.3.6-alpha.1" + } + } } }, "apollo-server-plugin-base": { @@ -410,19 +592,19 @@ } }, "apollo-utilities": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.2.1.tgz", - "integrity": "sha512-Zv8Udp9XTSFiN8oyXOjf6PMHepD4yxxReLsl6dPUy5Ths7jti3nmlBzZUOxuTWRwZn0MoclqL7RQ5UEJN8MAxg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.0.tgz", + "integrity": "sha512-wQjV+FdWcTWmWUFlChG5rS0vHKy5OsXC6XlV9STRstQq6VbXANwHy6DHnTEQAfLXWAbNcPgBu+nBUpR3dFhwrA==", "requires": { "fast-json-stable-stringify": "^2.0.0", - "ts-invariant": "^0.2.1", + "ts-invariant": "^0.4.0", "tslib": "^1.9.3" }, "dependencies": { "ts-invariant": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.2.1.tgz", - "integrity": "sha512-Z/JSxzVmhTo50I+LKagEISFJW3pvPCqsMWLamCTX8Kr3N5aMrnGOqcflbe5hLUzwjvgPfnLzQtHZv0yWQ+FIHg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.2.tgz", + "integrity": "sha512-PTAAn8lJPEdRBJJEs4ig6MVZWfO12yrFzV7YaPslmyhG7+4MA279y4BXT3f72gXeVl0mC1aAWq2rMX4eKTWU/Q==", "requires": { "tslib": "^1.9.3" } @@ -572,6 +754,11 @@ } } }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -674,6 +861,11 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz", "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg==" }, + "btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -853,6 +1045,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, + "cookie-parser": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", + "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6" + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1293,6 +1494,41 @@ } } }, + "express-session": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.1.tgz", + "integrity": "sha512-pWvUL8Tl5jUy1MLH7DhgUlpoKeVPUTe+y6WQD9YhcN0C5qAhsh4a8feVjiUXo3TFhIy191YGZ4tewW9edbl2xQ==", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.2", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -2847,9 +3083,14 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "node-fetch": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz", - "integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" }, "nodemon": { "version": "1.19.0", @@ -2893,6 +3134,11 @@ "path-key": "^2.0.0" } }, + "oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2974,6 +3220,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -3003,6 +3254,45 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, + "passport": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", + "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-discord": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/passport-discord/-/passport-discord-0.1.3.tgz", + "integrity": "sha512-o8+KiQrV63DCJvYVceyVJgyFhHxqOPlcxaiB8Hlrrm0uq83KfQOMPUcXal0pao5Qx8ZeOH/RBJEbJV9aB0F/hw==", + "requires": { + "passport-oauth2": "^1.2.0" + } + }, + "passport-oauth2": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.5.0.tgz", + "integrity": "sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==", + "requires": { + "base64url": "3.x.x", + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x", + "utils-merge": "1.x.x" + } + }, + "passport-oauth2-refresh": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/passport-oauth2-refresh/-/passport-oauth2-refresh-1.1.0.tgz", + "integrity": "sha512-UsmDntTlEKj8GAME/u6hvgTgq/WC/1lh9wGKs7QEf5/e+pBo9dnphJ1qLfmwFck21lz3wHHHiPFJrihLkFSaXg==" + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -3032,6 +3322,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -3109,6 +3404,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", @@ -3788,6 +4088,19 @@ "mime-types": "~2.1.24" } }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" + }, "undefsafe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", diff --git a/package.json b/package.json index b498b3ebb..07f05ff9f 100644 --- a/package.json +++ b/package.json @@ -11,14 +11,23 @@ "license": "ISC", "dependencies": { "apollo-server": "^2.4.8", - "apollo-server-express": "^2.4.8", + "apollo-server-express": "^2.5.0", "axios": "^0.18.0", + "body-parser": "^1.19.0", + "btoa": "^1.2.1", + "cookie-parser": "^1.4.4", "cors": "^2.8.5", "dotenv": "^7.0.0", + "express-session": "^1.16.1", "graphql": "^14.2.1", "jsonwebtoken": "^8.5.1", "mongoose": "^5.5.5", - "mongoose-unique-validator": "^2.0.3" + "mongoose-unique-validator": "^2.0.3", + "node-fetch": "^2.6.0", + "node-uuid": "^1.4.8", + "passport": "^0.4.0", + "passport-discord": "^0.1.3", + "passport-oauth2-refresh": "^1.1.0" }, "devDependencies": { "nodemon": "^1.19.0" diff --git a/react-ui/src/components/Misc/Links.js b/react-ui/src/components/Misc/Links.js index bfc784531..ca83ebf26 100644 --- a/react-ui/src/components/Misc/Links.js +++ b/react-ui/src/components/Misc/Links.js @@ -30,7 +30,7 @@ const Links = ({ setMenuSelection }) => { return null } return ( - + {l.title} {l.description} @@ -40,7 +40,7 @@ const Links = ({ setMenuSelection }) => { })} -
+
Guides @@ -51,7 +51,7 @@ const Links = ({ setMenuSelection }) => { return null } return ( - + {l.title} {l.description} @@ -61,7 +61,7 @@ const Links = ({ setMenuSelection }) => { })}
-
+
Misc @@ -72,7 +72,7 @@ const Links = ({ setMenuSelection }) => { return null } return ( - + {l.title} {l.description} diff --git a/react-ui/src/components/Misc/MainMenu.js b/react-ui/src/components/Misc/MainMenu.js index 33fb68e5e..3e4367877 100644 --- a/react-ui/src/components/Misc/MainMenu.js +++ b/react-ui/src/components/Misc/MainMenu.js @@ -1,10 +1,58 @@ import React, { useState } from 'react' -import { Menu, Segment } from 'semantic-ui-react' +import { Menu, Segment, Button, Icon, Image, Popup } from 'semantic-ui-react' +import { useQuery } from 'react-apollo-hooks' +import { userLean } from '../../graphql/queries/userLean' import { withRouter } from 'react-router-dom' import { memCakes } from '../../utils/lists' const MainMenu = withRouter(({ history, menuSelection, setMenuSelection }) => { const [memCakePic, setMemCakePic] = useState(memCakes[Math.floor(Math.random()*memCakes.length)]) + const { data, error, loading } = useQuery(userLean) + + const logIn = () => { + if (loading) { + return null + } + + if (!data.user || error) { + return ( + + + + + + ) + } + + const user = data.user + + return ( +
+ + {user.username} + + + } + > + + + + + + +
+ ) + } + return ( @@ -14,10 +62,7 @@ const MainMenu = withRouter(({ history, menuSelection, setMenuSelection }) => { { - history.push('/maps') - setMenuSelection('maplists') - }} + onClick={() => { history.push('/maps') }} /> { { history.push('links') }} + onClick={() => { history.push('/links') }} /> + + {logIn()} + ) diff --git a/react-ui/src/components/Tools/MapListGenerator.js b/react-ui/src/components/Tools/MapListGenerator.js index 33c7378e6..182f3d4e1 100644 --- a/react-ui/src/components/Tools/MapListGenerator.js +++ b/react-ui/src/components/Tools/MapListGenerator.js @@ -15,8 +15,8 @@ const MapListGenerator = ({ setMenuSelection }) => { const [ amountToGenerate, setAmountToGenerate ] = useState(12) const [ generatedMaps, setGeneratedMaps ] = useState([]) const [ generationType, setGenerationType] = useState('rotate') - const [copySuccess, setCopySuccess] = useState(''); - const textAreaRef = useRef(null); + const [copySuccess, setCopySuccess] = useState('') + const textAreaRef = useRef(null) useEffect(() => { if (loading) { diff --git a/react-ui/src/components/Tools/Rotations.js b/react-ui/src/components/Tools/Rotations.js index b02471094..43cb775d0 100644 --- a/react-ui/src/components/Tools/Rotations.js +++ b/react-ui/src/components/Tools/Rotations.js @@ -218,11 +218,23 @@ const Rotations = ({ setMenuSelection }) => { const seconds = timeUntil % 3600 % 60 let header = 'Current' if (hours >= 2) { - header = `In ${hours} hours ${minutes} minutes (${new Date(r.start_time * 1000).toLocaleString('en-GB')})` + if (minutes === 1) { + header = `In ${hours} hours ${minutes} minute (${new Date(r.start_time * 1000).toLocaleString('en-GB')})` + } else { + header = `In ${hours} hours ${minutes} minutes (${new Date(r.start_time * 1000).toLocaleString('en-GB')})` + } } else if (hours > 0) { - header = `In ${hours} hours ${minutes} minutes ${seconds} seconds` + if (minutes === 1) { + header = `In ${hours} hour ${minutes} minute ${seconds} seconds` + } else { + header = `In ${hours} hour ${minutes} minutes ${seconds} seconds` + } } else if (minutes > 0) { - header = `In ${minutes} minutes ${seconds} seconds` + if (minutes === 1) { + header = `In ${hours} hour ${minutes} minute ${seconds} seconds` + } else { + header = `In ${minutes} minutes ${seconds} seconds` + } } return (
diff --git a/react-ui/src/graphql/queries/userLean.js b/react-ui/src/graphql/queries/userLean.js new file mode 100644 index 000000000..039883f51 --- /dev/null +++ b/react-ui/src/graphql/queries/userLean.js @@ -0,0 +1,11 @@ +import { gql } from 'apollo-boost' + +export const userLean = gql` +{ + user { + username + avatar + discord_id + } +} +` \ No newline at end of file