Pulling avatar information of authors from discord (#19)

Pulling avatar information of authors from discord
This commit is contained in:
Jean-Philippe Sirois
2019-07-29 04:16:31 -04:00
committed by GitHub
16 changed files with 193 additions and 25 deletions
+2
View File
@@ -1,3 +1,5 @@
users.json
# Logs
logs
*.log
+5 -4
View File
@@ -1,11 +1,13 @@
<a href="https://discord.gg/programming">
<img src="https://img.shields.io/discord/244230771232079873?color=%23dc1529&label=The%20Programmers%20Hangout" />
</a>
</a>
<a href="https://discord.gg/programming">
<img src="https://cdn.discordapp.com/banners/244230771232079873/ab1a9d5657892f173d5dd752b21d318f.jpg?size=1024" />
</a>
# TPH Website
The official website for [The Programmer's Hangout](https://discord.gg/programming).
## Contributing
@@ -40,7 +42,7 @@ Gatsby will take care of most of this process by creating a new page and positio
5. Run through the [setup steps](#setup) if possible to make sure your changes look ok.
6. Create a pull request.
#### Frontmatter
#### Frontmatter
Frontmatter the optional metadata attached to every markdown file, like the list of authors or the creation date of the file. It is essentially just yaml syntax inside `---` delimiters within a markdown file. If you're not familiar with yaml you can find some refreshers [here](https://learnxinyminutes.com/docs/yaml/)
@@ -49,7 +51,7 @@ An example frontmatter might look like this
```md
---
authors:
- "@Xetera"
- "Xetera#0001"
title: "Working with Lists in Elixir"
created_at: 2020/01/30
external_resources:
@@ -62,4 +64,3 @@ some content here
```
You can look at other resources like [this one](/src/content/docs/javascript/promises/intro.md) for reference when creating your own. We use [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) as the date format to confuse both Americans and Europeans an equal amount.
+33 -13
View File
@@ -1,28 +1,40 @@
const { graphql } = require("gatsby")
const { createFilePath } = require("gatsby-source-filesystem")
const helper = require("./scripts/buildHelpers")
const path = require(`path`)
const fs = require("fs")
const usersEndpoint = id => `https://discordapp.com/api/guilds/${id}/members`
const requiredArticleFrontmatter = ["authors", "date"]
const fetchUsers = () => {
// Fetch user data from discord using bot token here
let users = []
try {
users = JSON.parse(fs.readFileSync("./users.json", "utf-8"))
console.log("(◕◡◕✿) Users list loaded!")
} catch (e) {
console.log("(◕‸ ◕✿) Users list not present, skipping user resolution...")
}
const validateResourceArticle = node => {
const missingField = requiredArticleFrontmatter.find(
required => node.frontmatter[required]
)
if (missingField) {
console.error(
`Article ${node.fileAbsolutePath} is missing field '${missingField}'`
)
process.exit(1)
}
}
const createDocs = async ({ createPage, graphql }) => {
const languageDocs = path.resolve(`src/templates/languagePost.tsx`)
const result = await graphql(`
{
query FetchDocs {
allFile(filter: { sourceInstanceName: { eq: "docs" } }) {
edges {
node {
relativePath
childMarkdownRemark {
frontmatter {
author
date
}
}
}
}
}
@@ -47,11 +59,19 @@ const createDocs = async ({ createPage, graphql }) => {
exports.onCreateNode = async ({ node, getNode, actions }) => {
const { createPage, createNodeField } = actions
if (node.internal.type === "MarkdownRemark") {
const slug = createFilePath({ node, getNode, basePath: "src/content/docs" })
const { frontmatter } = node
const isDoc = Boolean(!frontmatter.path)
if (!isDoc) {
return
}
const authors = helper.resolveAuthors(users, frontmatter.authors)
createNodeField({
node,
name: "slug",
value: slug,
name: "authors",
value: authors,
})
}
}
+34
View File
@@ -5323,6 +5323,25 @@
}
}
},
"discord.js": {
"version": "11.5.1",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.5.1.tgz",
"integrity": "sha512-tGhV5xaZXE3Z+4uXJb3hYM6gQ1NmnSxp9PClcsSAYFVRzH6AJH74040mO3afPDMWEAlj8XsoPXXTJHTxesqcGw==",
"requires": {
"long": "^4.0.0",
"prism-media": "^0.0.3",
"snekfetch": "^3.6.4",
"tweetnacl": "^1.0.0",
"ws": "^6.0.0"
},
"dependencies": {
"tweetnacl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz",
"integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A=="
}
}
},
"dns-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
@@ -10942,6 +10961,11 @@
"resolved": "https://registry.npmjs.org/lokijs/-/lokijs-1.5.7.tgz",
"integrity": "sha512-2SqUV6JH4f15Z5/7LVsyadSUwHhZppxhujgy/VhVqiRYMGt5oaocb7fV/3JGjHJ6rTuEIajnpTLGRz9cJW/c3g=="
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"longest": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
@@ -13580,6 +13604,11 @@
"utila": "~0.4"
}
},
"prism-media": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz",
"integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ=="
},
"prismjs": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz",
@@ -15428,6 +15457,11 @@
}
}
},
"snekfetch": {
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz",
"integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw=="
},
"socket.io": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz",
+3 -1
View File
@@ -8,6 +8,7 @@
"@types/ramda": "^0.26.18",
"axios": "^0.19.0",
"babel-plugin-styled-components": "^1.10.6",
"discord.js": "^11.5.1",
"gatsby": "^2.13.39",
"gatsby-image": "^2.2.6",
"gatsby-plugin-manifest": "^2.2.4",
@@ -58,7 +59,8 @@
"start": "npm run develop",
"serve": "gatsby serve",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"",
"codegen": "graphql-codegen --config codegen.yml"
"codegen": "graphql-codegen --config codegen.yml",
"fetch-users": "node ./scripts/fetchUsers.js"
},
"repository": {
"type": "git",
+32
View File
@@ -0,0 +1,32 @@
const DEFAULT_AVATAR_MODULO = 5
module.exports = {
splitHash(identifier) {
const hashLocation = identifier.lastIndexOf("#")
if (hashLocation === -1) {
throw Error(`Invalid name format ${identifier}`)
}
const name = identifier.slice(0, hashLocation)
const hash = identifier.slice(hashLocation + 1)
return [name, hash]
},
getDefaultAvatar(hash) {
const avatar = hash % DEFAULT_AVATAR_MODULO
return `https://cdn.discordapp.com/embed/avatars/${avatar}.png`
},
resolveAuthor(users, author) {
const target = users.find(user => user.identifier === author)
const [name, hash] = this.splitHash(author)
const avatar = target ? target.avatar : this.getDefaultAvatar(hash)
return {
name,
hash,
avatar,
}
},
resolveAuthors(users, authors) {
return authors.map(author => this.resolveAuthor(users, author))
},
}
+44
View File
@@ -0,0 +1,44 @@
// This script will be ran periodically through CI
// don't touch it
const Discord = require("discord.js")
const fs = require("fs")
const { Readable, Writable } = require("stream")
const client = new Discord.Client()
const { BOT_TOKEN } = process.env
const TPH = "244230771232079873"
const DESTINATION = "./users.json"
if (!BOT_TOKEN) {
throw Error("Missing BOT_TOKEN environment variable")
}
const writeS = (content, dest) => {
const source = new Readable()
source.push(JSON.stringify(content))
source.push(null)
return source.pipe(dest)
}
client.once("ready", async () => {
console.log("Bot ready, fetching user list...")
const tph = client.guilds.get(TPH)
if (!tph) {
throw Error("Bot is not in TPH, cannot fetch users")
}
const guild = await tph.fetchMembers()
const memberInfo = guild.members.map(member => ({
identifier: `${member.user.username}#${member.user.discriminator}`,
avatar: member.user.displayAvatarURL,
}))
const wrs = fs.createWriteStream(DESTINATION)
console.log(`Fetched ${memberInfo.length} users, writing to ${DESTINATION}`)
writeS(memberInfo, wrs).on("finish", () => {
console.log("Finished writing list")
process.exit(0)
})
})
console.log("Attempting to log in...")
client.login(process.env.BOT_TOKEN)
+14
View File
@@ -0,0 +1,14 @@
import React from "react"
function DiscordButton({
lined = false,
children,
}: React.PropsWithChildren<{ lined: boolean }>) {
return (
<button>
<div>{children}</div>
</button>
)
}
export default DiscordButton
+2 -1
View File
@@ -45,7 +45,8 @@ const ALL_DOCS = graphql`
relativePath
childMarkdownRemark {
frontmatter {
author
authors
title
date
}
}
@@ -0,0 +1,10 @@
---
authors:
- "Xetera#0001"
created_at: 2019/07/27
title: Callbacks
---
# Callbacks are everywhere
If you've been doing javascript for any amount of time you'll have noticed that callbacks appear in just about every single piece of code.
@@ -1,6 +1,6 @@
---
authors:
- "@veksen"
- "veksen#1060"
created_at: "2019/07/27"
---
@@ -1,6 +1,6 @@
---
authors:
- "@Xetera"
- "Xetera#0001"
created_at: 2019/07/26
updated_at: 2019/07/26
title: Introduction to Promises
@@ -1,6 +1,6 @@
---
authors:
- "@Xetera"
- "Xetera#0001"
created_at: "2019/07/26"
---
@@ -1,6 +1,6 @@
---
authors:
- "@supergrecko"
- "supergrecko#3434"
created_at: "2019/07/27"
---
+2 -1
View File
@@ -1,5 +1,6 @@
---
author: "@Xetera"
authors:
- "Xetera#0001"
date: 2019/06/26
---
+8 -1
View File
@@ -22,8 +22,15 @@ export const query = graphql`
file(relativePath: { eq: $file }) {
post: childMarkdownRemark {
html
fields {
authors {
name
hash
avatar
}
}
frontmatter {
authors
date
title
}
}