mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-08 08:34:20 +02:00
🔧 use .env instead of json config files
This commit is contained in:
parent
f88dbc36d2
commit
24db804c7f
18
.env.example
Normal file
18
.env.example
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
## Google Cloud Platform Service Account
|
||||||
|
GCP_SERVICE_ACCOUNT_PRIVATE_KEY=
|
||||||
|
GCP_SERVICE_ACCOUNT_CLIENT_ID=
|
||||||
|
GCP_SERVICE_ACCOUNT_CLIENT_EMAIL=
|
||||||
|
GSHEET_ID=
|
||||||
|
|
||||||
|
## Discord
|
||||||
|
DISCORD_TOKEN=
|
||||||
|
DISCORD_CLIENTID=
|
||||||
|
DISCORD_GUILDID=
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
FORCE_ORANGE_PUBLIC_VAPID_KEY=
|
||||||
|
FORCE_ORANGE_PRIVATE_VAPID_KEY=
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
PORT=8080
|
||||||
|
API_URL=http://fo.parisestludique.fr/api
|
@ -60,5 +60,6 @@ module.exports = {
|
|||||||
__LOCAL__: false,
|
__LOCAL__: false,
|
||||||
__REGISTER_DISCORD_COMMANDS__: false,
|
__REGISTER_DISCORD_COMMANDS__: false,
|
||||||
__TEST__: false,
|
__TEST__: false,
|
||||||
|
API_URL: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ module.exports = {
|
|||||||
__LOCAL__: false,
|
__LOCAL__: false,
|
||||||
__REGISTER_DISCORD_COMMANDS__: false,
|
__REGISTER_DISCORD_COMMANDS__: false,
|
||||||
__TEST__: true,
|
__TEST__: true,
|
||||||
|
API_URL: "http://localhost:3000",
|
||||||
},
|
},
|
||||||
maxConcurrency: 50,
|
maxConcurrency: 50,
|
||||||
maxWorkers: 1,
|
maxWorkers: 1,
|
||||||
|
11
package.json
11
package.json
@ -39,12 +39,12 @@
|
|||||||
"npm": ">=6"
|
"npm": ">=6"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "yarn dev:build && nodemon ./public/server",
|
"dev": "yarn dev:build && nodemon -r dotenv/config ./public/server",
|
||||||
"ser": "yarn dev:build && node ./public/server",
|
"ser": "yarn dev:build && node -r dotenv/config ./public/server",
|
||||||
"dev:build": "cross-env NODE_ENV=development webpack --config ./webpack/server.config.ts",
|
"dev:build": "cross-env NODE_ENV=development webpack --config ./webpack/server.config.ts",
|
||||||
"local-start": "cross-env LOCAL=true yarn build && node ./public/server",
|
"local-start": "cross-env LOCAL=true yarn build && node -r dotenv/config ./public/server",
|
||||||
"discord-register": "cross-env REGISTER_DISCORD_COMMANDS=true yarn build && node ./public/server",
|
"discord-register": "cross-env REGISTER_DISCORD_COMMANDS=true yarn build && node -r dotenv/config ./public/server",
|
||||||
"start": "node ./public/server",
|
"start": "node -r dotenv/config ./public/server",
|
||||||
"build": "run-s build:*",
|
"build": "run-s build:*",
|
||||||
"build:server": "cross-env NODE_ENV=production webpack --config ./webpack/server.config.ts",
|
"build:server": "cross-env NODE_ENV=production webpack --config ./webpack/server.config.ts",
|
||||||
"build:client": "cross-env NODE_ENV=production webpack --config ./webpack/client.config.ts",
|
"build:client": "cross-env NODE_ENV=production webpack --config ./webpack/client.config.ts",
|
||||||
@ -174,6 +174,7 @@
|
|||||||
"compression-webpack-plugin": "^8.0.1",
|
"compression-webpack-plugin": "^8.0.1",
|
||||||
"css-loader": "^5.2.6",
|
"css-loader": "^5.2.6",
|
||||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
"eslint": "^7.14.0",
|
"eslint": "^7.14.0",
|
||||||
"eslint-config-airbnb": "^18.2.1",
|
"eslint-config-airbnb": "^18.2.1",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
@ -2,7 +2,6 @@ import { RouteConfig, renderRoutes } from "react-router-config"
|
|||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet"
|
||||||
import { ToastContainer } from "react-toastify"
|
import { ToastContainer } from "react-toastify"
|
||||||
|
|
||||||
import config from "../config"
|
|
||||||
// Import your global styles here
|
// Import your global styles here
|
||||||
import "normalize.css/normalize.css"
|
import "normalize.css/normalize.css"
|
||||||
import "react-toastify/dist/ReactToastify.css"
|
import "react-toastify/dist/ReactToastify.css"
|
||||||
@ -24,9 +23,22 @@ const App = ({ route, location }: Route): JSX.Element => {
|
|||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
|
|
||||||
|
const appInfo = {
|
||||||
|
htmlAttributes: { lang: "en" },
|
||||||
|
title: "Force Orange",
|
||||||
|
description: "Le site des bénévoles",
|
||||||
|
titleTemplate: "Force Orange - %s",
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
name: "description",
|
||||||
|
content: "The best react universal starter boilerplate in the world.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Helmet {...config.APP}>
|
<Helmet {...appInfo}>
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
|
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
|
||||||
@ -36,9 +48,9 @@ const App = ({ route, location }: Route): JSX.Element => {
|
|||||||
<div className={styles.logo} />
|
<div className={styles.logo} />
|
||||||
<div>
|
<div>
|
||||||
<h1 className={styles.siteName}>
|
<h1 className={styles.siteName}>
|
||||||
<a href="/">{config.APP.title}</a>
|
<a href="/">{appInfo.title}</a>
|
||||||
</h1>
|
</h1>
|
||||||
<div className={styles.siteDescription}>{config.APP.description}</div>
|
<div className={styles.siteDescription}>{appInfo.description}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.menuWrapper}>
|
<div className={styles.menuWrapper}>
|
||||||
<MainMenu />
|
<MainMenu />
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
export default {
|
|
||||||
HOST: "localhost",
|
|
||||||
PORT: 3000,
|
|
||||||
API_URL: "http://localhost:3000",
|
|
||||||
GOOGLE_SHEET_ID: "1g-GB1NHLtUAQnQkbyo_5Lv6GzJ58DeOsUTrHlIVi01M",
|
|
||||||
APP: {
|
|
||||||
htmlAttributes: { lang: "en" },
|
|
||||||
title: "Force Orange",
|
|
||||||
description: "Le site des bénévoles",
|
|
||||||
titleTemplate: "Force Orange - %s",
|
|
||||||
meta: [
|
|
||||||
{
|
|
||||||
name: "description",
|
|
||||||
content: "The best react universal starter boilerplate in the world.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
DEV_JWT_SECRET: "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!",
|
|
||||||
DEV_DISCORD_TOKEN: "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!",
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
import defaultConfig from "./default"
|
|
||||||
import prodConfig from "./prod"
|
|
||||||
|
|
||||||
export default __DEV__ ? defaultConfig : { ...defaultConfig, ...prodConfig }
|
|
@ -1,14 +0,0 @@
|
|||||||
import isNode from "detect-node"
|
|
||||||
|
|
||||||
const PROTOCOL = (typeof window !== "undefined" && window?.location?.protocol) || "http:"
|
|
||||||
const PORT = 4000 + (PROTOCOL === "https:" ? 2 : 0)
|
|
||||||
const API_URL =
|
|
||||||
__DEV__ || __LOCAL__ || isNode
|
|
||||||
? `${PROTOCOL}//localhost:${PORT}`
|
|
||||||
: `${PROTOCOL}//fo.parisestludique.fr`
|
|
||||||
|
|
||||||
export default {
|
|
||||||
PORT,
|
|
||||||
HOST: "0.0.0.0",
|
|
||||||
API_URL,
|
|
||||||
}
|
|
@ -13,8 +13,6 @@ import {
|
|||||||
User,
|
User,
|
||||||
PartialUser,
|
PartialUser,
|
||||||
} from "discord.js"
|
} from "discord.js"
|
||||||
import { promises as fs, constants } from "fs"
|
|
||||||
import path from "path"
|
|
||||||
|
|
||||||
import { translationVolunteer, Volunteer, VolunteerWithoutId } from "../services/volunteers"
|
import { translationVolunteer, Volunteer, VolunteerWithoutId } from "../services/volunteers"
|
||||||
import {
|
import {
|
||||||
@ -23,13 +21,8 @@ import {
|
|||||||
DiscordRoleWithoutId,
|
DiscordRoleWithoutId,
|
||||||
} from "../services/discordRoles"
|
} from "../services/discordRoles"
|
||||||
import { getSheet } from "./gsheets/accessors"
|
import { getSheet } from "./gsheets/accessors"
|
||||||
import config from "../config"
|
|
||||||
|
|
||||||
let cachedToken: string
|
const { DISCORD_TOKEN, DISCORD_CLIENTID, DISCORD_GUILDID } = process.env
|
||||||
// let cachedClientId: string
|
|
||||||
let cachedGuildId: string
|
|
||||||
const CREDS_PATH = path.resolve(process.cwd(), "access/discordToken.json")
|
|
||||||
getCreds() // Necessary until we can make async express middleware
|
|
||||||
|
|
||||||
type Command = {
|
type Command = {
|
||||||
data: SlashCommandBuilder
|
data: SlashCommandBuilder
|
||||||
@ -52,19 +45,8 @@ const commands: Collection<string, Command> = new Collection()
|
|||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let hasDiscordAccessReturn: boolean | undefined
|
export function hasDiscordAccess(): boolean {
|
||||||
export async function hasDiscordAccess(): Promise<boolean> {
|
return Boolean(DISCORD_TOKEN && DISCORD_CLIENTID && DISCORD_GUILDID)
|
||||||
if (hasDiscordAccessReturn !== undefined) {
|
|
||||||
return hasDiscordAccessReturn
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line no-bitwise
|
|
||||||
await fs.access(CREDS_PATH, constants.R_OK | constants.W_OK)
|
|
||||||
hasDiscordAccessReturn = true
|
|
||||||
} catch {
|
|
||||||
hasDiscordAccessReturn = false
|
|
||||||
}
|
|
||||||
return hasDiscordAccessReturn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// export async function discordRegisterCommands(): Promise<void> {
|
// export async function discordRegisterCommands(): Promise<void> {
|
||||||
@ -72,7 +54,7 @@ export async function hasDiscordAccess(): Promise<boolean> {
|
|||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (!(await hasDiscordAccess())) {
|
// if (!(hasDiscordAccess())) {
|
||||||
// console.error(`Discord bot: no creds found, not running bot`)
|
// console.error(`Discord bot: no creds found, not running bot`)
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
@ -82,11 +64,11 @@ export async function hasDiscordAccess(): Promise<boolean> {
|
|||||||
// const commandsToRegister = []
|
// const commandsToRegister = []
|
||||||
// commandsToRegister.push(userCommand.data.toJSON())
|
// commandsToRegister.push(userCommand.data.toJSON())
|
||||||
|
|
||||||
// const rest = new REST({ version: '10' }).setToken(cachedToken)
|
// const rest = new REST({ version: '10' }).setToken(DISCORD_TOKEN)
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// await rest.put(
|
// await rest.put(
|
||||||
// Routes.applicationGuildCommands(cachedClientId, cachedGuildId),
|
// Routes.applicationGuildCommands(DISCORD_CLIENTID, DISCORD_GUILDID),
|
||||||
// { body: commandsToRegister },
|
// { body: commandsToRegister },
|
||||||
// )
|
// )
|
||||||
// } catch (error) {
|
// } catch (error) {
|
||||||
@ -102,11 +84,10 @@ export async function discordBot(): Promise<void> {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await hasDiscordAccess())) {
|
if (!hasDiscordAccess()) {
|
||||||
console.error(`Discord bot: no creds found, not running bot`)
|
console.error(`Discord bot: no creds found, not running bot`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await getCreds()
|
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
intents: [
|
intents: [
|
||||||
@ -158,7 +139,7 @@ export async function discordBot(): Promise<void> {
|
|||||||
await setRolesFromEmoji(client, user, reaction, "remove")
|
await setRolesFromEmoji(client, user, reaction, "remove")
|
||||||
})
|
})
|
||||||
|
|
||||||
client.login(cachedToken)
|
client.login(DISCORD_TOKEN)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Discord error", error)
|
console.error("Discord error", error)
|
||||||
}
|
}
|
||||||
@ -205,6 +186,8 @@ async function setBotReactions(client: Client) {
|
|||||||
|
|
||||||
async function setAllRoles(client: Client) {
|
async function setAllRoles(client: Client) {
|
||||||
try {
|
try {
|
||||||
|
if (!DISCORD_GUILDID) return
|
||||||
|
|
||||||
const volunteerSheet = await getSheet<VolunteerWithoutId, Volunteer>(
|
const volunteerSheet = await getSheet<VolunteerWithoutId, Volunteer>(
|
||||||
"Volunteers",
|
"Volunteers",
|
||||||
new Volunteer(),
|
new Volunteer(),
|
||||||
@ -216,8 +199,7 @@ async function setAllRoles(client: Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const volunteerByDiscordId = _.mapKeys(volunteerList, (v) => v.discordId.toString())
|
const volunteerByDiscordId = _.mapKeys(volunteerList, (v) => v.discordId.toString())
|
||||||
|
const guild = await client.guilds.fetch(DISCORD_GUILDID)
|
||||||
const guild = await client.guilds.fetch(cachedGuildId)
|
|
||||||
|
|
||||||
if (!guild || !guild.members.cache) {
|
if (!guild || !guild.members.cache) {
|
||||||
return
|
return
|
||||||
@ -356,6 +338,8 @@ async function setRolesFromEmoji(
|
|||||||
reaction: MessageReaction | PartialMessageReaction,
|
reaction: MessageReaction | PartialMessageReaction,
|
||||||
action: "add" | "remove"
|
action: "add" | "remove"
|
||||||
) {
|
) {
|
||||||
|
if (!DISCORD_GUILDID) return
|
||||||
|
|
||||||
const discordRolesSheet = await getSheet<DiscordRoleWithoutId, DiscordRole>(
|
const discordRolesSheet = await getSheet<DiscordRoleWithoutId, DiscordRole>(
|
||||||
"DiscordRoles",
|
"DiscordRoles",
|
||||||
new DiscordRole(),
|
new DiscordRole(),
|
||||||
@ -367,7 +351,7 @@ async function setRolesFromEmoji(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await client.guilds.fetch()
|
await client.guilds.fetch()
|
||||||
const guild = client.guilds.resolve(cachedGuildId)
|
const guild = client.guilds.resolve(DISCORD_GUILDID)
|
||||||
|
|
||||||
if (!guild || !guild.members.cache) {
|
if (!guild || !guild.members.cache) {
|
||||||
return
|
return
|
||||||
@ -408,20 +392,3 @@ async function fetchPartial(reaction: MessageReaction | PartialMessageReaction):
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCreds(): Promise<void> {
|
|
||||||
if (!cachedToken) {
|
|
||||||
try {
|
|
||||||
const credsContent = await fs.readFile(CREDS_PATH)
|
|
||||||
const parsedCreds = credsContent && JSON.parse(credsContent.toString())
|
|
||||||
if (!parsedCreds) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cachedToken = parsedCreds.token
|
|
||||||
// cachedClientId = parsedCreds.clientId
|
|
||||||
cachedGuildId = parsedCreds.guildId
|
|
||||||
} catch (e: any) {
|
|
||||||
cachedToken = config.DEV_DISCORD_TOKEN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
// eslint-disable-next-line max-classes-per-file
|
// eslint-disable-next-line max-classes-per-file
|
||||||
import path from "path"
|
|
||||||
import _, { assign, pick } from "lodash"
|
import _, { assign, pick } from "lodash"
|
||||||
import { promises as fs, constants } from "fs"
|
|
||||||
import { GoogleSpreadsheet, GoogleSpreadsheetWorksheet } from "google-spreadsheet"
|
import { GoogleSpreadsheet, GoogleSpreadsheetWorksheet } from "google-spreadsheet"
|
||||||
import { SheetNames, saveLocalDb, loadLocalDb } from "./localDb"
|
import { SheetNames, saveLocalDb, loadLocalDb } from "./localDb"
|
||||||
|
|
||||||
@ -9,14 +7,10 @@ export { SheetNames } from "./localDb"
|
|||||||
|
|
||||||
// Test write attack with: wget --header='Content-Type:application/json' --post-data='{"prenom":"Pierre","nom":"SCELLES","email":"test@gmail.com","telephone":"0601010101","dejaBenevole":false,"commentaire":""}' http://localhost:3000/PostulantAdd
|
// Test write attack with: wget --header='Content-Type:application/json' --post-data='{"prenom":"Pierre","nom":"SCELLES","email":"test@gmail.com","telephone":"0601010101","dejaBenevole":false,"commentaire":""}' http://localhost:3000/PostulantAdd
|
||||||
|
|
||||||
const CRED_PATH = path.resolve(process.cwd(), "access/gsheets.json")
|
|
||||||
|
|
||||||
const REMOTE_UPDATE_DELAY = 120000
|
const REMOTE_UPDATE_DELAY = 120000
|
||||||
const DELAY_BETWEEN_ATTEMPTS = 30000
|
const DELAY_BETWEEN_ATTEMPTS = 30000
|
||||||
const DELAY_BETWEEN_FIRST_LOAD = 1500
|
const DELAY_BETWEEN_FIRST_LOAD = 1500
|
||||||
|
|
||||||
let creds: string | undefined | null
|
|
||||||
|
|
||||||
export type ElementWithId<ElementNoId> = { id: number } & ElementNoId
|
export type ElementWithId<ElementNoId> = { id: number } & ElementNoId
|
||||||
|
|
||||||
export const sheetNames = new SheetNames()
|
export const sheetNames = new SheetNames()
|
||||||
@ -25,23 +19,16 @@ export const sheetNames = new SheetNames()
|
|||||||
type SheetList = { [sheetName in keyof SheetNames]?: Sheet<object, ElementWithId<object>> }
|
type SheetList = { [sheetName in keyof SheetNames]?: Sheet<object, ElementWithId<object>> }
|
||||||
const sheetList: SheetList = {}
|
const sheetList: SheetList = {}
|
||||||
|
|
||||||
let hasGSheetsAccessReturn: boolean | undefined
|
export function hasGSheetsAccess(): boolean {
|
||||||
export async function hasGSheetsAccess(): Promise<boolean> {
|
return Boolean(
|
||||||
if (hasGSheetsAccessReturn !== undefined) {
|
process.env.GSHEET_ID &&
|
||||||
return hasGSheetsAccessReturn
|
process.env.GCP_SERVICE_ACCOUNT_CLIENT_EMAIL &&
|
||||||
}
|
process.env.GCP_SERVICE_ACCOUNT_PRIVATE_KEY
|
||||||
try {
|
)
|
||||||
// eslint-disable-next-line no-bitwise
|
|
||||||
await fs.access(CRED_PATH, constants.R_OK | constants.W_OK)
|
|
||||||
hasGSheetsAccessReturn = true
|
|
||||||
} catch {
|
|
||||||
hasGSheetsAccessReturn = false
|
|
||||||
}
|
|
||||||
return hasGSheetsAccessReturn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkGSheetsAccess(): Promise<void> {
|
export async function checkGSheetsAccess(): Promise<void> {
|
||||||
if (!(await hasGSheetsAccess())) {
|
if (!hasGSheetsAccess()) {
|
||||||
console.error(`Google Sheets: no creds found, loading local database instead`)
|
console.error(`Google Sheets: no creds found, loading local database instead`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,22 +354,17 @@ export class Sheet<
|
|||||||
private async getGSheet(attempts = 3): Promise<GoogleSpreadsheetWorksheet | null> {
|
private async getGSheet(attempts = 3): Promise<GoogleSpreadsheetWorksheet | null> {
|
||||||
return tryNTimes(
|
return tryNTimes(
|
||||||
async () => {
|
async () => {
|
||||||
if (creds === undefined) {
|
if (hasGSheetsAccess()) {
|
||||||
if (await hasGSheetsAccess()) {
|
|
||||||
const credsBuffer = await fs.readFile(CRED_PATH)
|
|
||||||
creds = credsBuffer?.toString() || null
|
|
||||||
} else {
|
|
||||||
creds = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (creds === null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
// Authentication
|
// Authentication
|
||||||
const doc = new GoogleSpreadsheet("1g-GB1NHLtUAQnQkbyo_5Lv6GzJ58DeOsUTrHlIVi01M")
|
const doc = new GoogleSpreadsheet(process.env.GSHEET_ID)
|
||||||
await doc.useServiceAccountAuth(JSON.parse(creds))
|
await doc.useServiceAccountAuth({
|
||||||
|
client_email: process.env.GCP_SERVICE_ACCOUNT_CLIENT_EMAIL || "",
|
||||||
|
private_key: process.env.GCP_SERVICE_ACCOUNT_PRIVATE_KEY || "",
|
||||||
|
})
|
||||||
await doc.loadInfo()
|
await doc.loadInfo()
|
||||||
return doc.sheetsByTitle[this.sheetName]
|
return doc.sheetsByTitle[this.sheetName]
|
||||||
|
}
|
||||||
|
return null
|
||||||
},
|
},
|
||||||
() => null,
|
() => null,
|
||||||
attempts,
|
attempts,
|
||||||
|
@ -49,7 +49,7 @@ import {
|
|||||||
volunteerOnSiteInfo,
|
volunteerOnSiteInfo,
|
||||||
} from "./gsheets/volunteers"
|
} from "./gsheets/volunteers"
|
||||||
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
||||||
import config from "../config"
|
|
||||||
import { notificationsSubscribe, notificationMain } from "./notifications"
|
import { notificationsSubscribe, notificationMain } from "./notifications"
|
||||||
import { /* discordRegisterCommands, */ discordBot, hasDiscordAccess } from "./discordBot"
|
import { /* discordRegisterCommands, */ discordBot, hasDiscordAccess } from "./discordBot"
|
||||||
import checkAccess from "./checkAccess"
|
import checkAccess from "./checkAccess"
|
||||||
@ -202,7 +202,9 @@ if (validCertPath) {
|
|||||||
* Listen on provided port, on all network interfaces.
|
* Listen on provided port, on all network interfaces.
|
||||||
*/
|
*/
|
||||||
servers.forEach(({ protocol, server }) => {
|
servers.forEach(({ protocol, server }) => {
|
||||||
server.listen(protocol === "http" ? config.PORT : <number>config.PORT + 2)
|
const port = Number(process.env.PORT) || 3000
|
||||||
|
|
||||||
|
server.listen(protocol === "http" ? port : port + 2)
|
||||||
server.on("error", onError)
|
server.on("error", onError)
|
||||||
server.on("listening", () => onListening(server))
|
server.on("listening", () => onListening(server))
|
||||||
})
|
})
|
||||||
@ -227,13 +229,11 @@ function onListening(server: any) {
|
|||||||
addStatus("Server listening:", chalk.green(`✅ ${bind}`))
|
addStatus("Server listening:", chalk.green(`✅ ${bind}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
hasGSheetsAccess().then((hasApiAccess: boolean) => {
|
if (hasGSheetsAccess()) {
|
||||||
if (hasApiAccess) {
|
|
||||||
addStatus("Database:", chalk.green(`✅ online from Google Sheet`))
|
addStatus("Database:", chalk.green(`✅ online from Google Sheet`))
|
||||||
} else {
|
} else {
|
||||||
addStatus("Database:", chalk.blue(`🚧 offline, simulated from local db file`))
|
addStatus("Database:", chalk.blue(`🚧 offline, simulated from local db file`))
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const hasSendGridApiAccess = !!process.env.SENDGRID_API_KEY
|
const hasSendGridApiAccess = !!process.env.SENDGRID_API_KEY
|
||||||
if (hasSendGridApiAccess) {
|
if (hasSendGridApiAccess) {
|
||||||
@ -249,13 +249,11 @@ if (hasPushNotifAccess) {
|
|||||||
addStatus("Push notif:", chalk.blue(`🚧 offline, simulated`))
|
addStatus("Push notif:", chalk.blue(`🚧 offline, simulated`))
|
||||||
}
|
}
|
||||||
|
|
||||||
hasDiscordAccess().then((hasApiAccess: boolean) => {
|
if (hasDiscordAccess()) {
|
||||||
if (hasApiAccess) {
|
|
||||||
addStatus("Discord bot:", chalk.green(`✅ online through discord.js`))
|
addStatus("Discord bot:", chalk.green(`✅ online through discord.js`))
|
||||||
} else {
|
} else {
|
||||||
addStatus("Discord bot:", chalk.blue(`🚧 no creds, disabled`))
|
addStatus("Discord bot:", chalk.blue(`🚧 no creds, disabled`))
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
hasSecret().then((has: boolean) => {
|
hasSecret().then((has: boolean) => {
|
||||||
if (has) {
|
if (has) {
|
||||||
|
@ -3,8 +3,6 @@ import path from "path"
|
|||||||
import { constants, promises as fs } from "fs"
|
import { constants, promises as fs } from "fs"
|
||||||
import { verify, sign } from "jsonwebtoken"
|
import { verify, sign } from "jsonwebtoken"
|
||||||
|
|
||||||
import config from "../config"
|
|
||||||
|
|
||||||
type AuthorizedRequest = Request & { headers: { authorization: string } }
|
type AuthorizedRequest = Request & { headers: { authorization: string } }
|
||||||
|
|
||||||
let cachedSecret: string
|
let cachedSecret: string
|
||||||
@ -57,7 +55,7 @@ async function getSecret() {
|
|||||||
const secretContent = await fs.readFile(SECRET_PATH)
|
const secretContent = await fs.readFile(SECRET_PATH)
|
||||||
cachedSecret = secretContent && JSON.parse(secretContent.toString()).secret
|
cachedSecret = secretContent && JSON.parse(secretContent.toString()).secret
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
cachedSecret = config.DEV_JWT_SECRET
|
cachedSecret = "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
|
|
||||||
import config from "../config"
|
|
||||||
import { axiosConfig } from "./auth"
|
import { axiosConfig } from "./auth"
|
||||||
|
|
||||||
export type ElementWithId = unknown & { id: number }
|
export type ElementWithId = unknown & { id: number }
|
||||||
@ -26,7 +25,7 @@ export default class ServiceAccessors<
|
|||||||
}
|
}
|
||||||
return async (id: number): Promise<ElementGetResponse> => {
|
return async (id: number): Promise<ElementGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`${config.API_URL}/${this.elementName}Get`, {
|
const { data } = await axios.get(`${API_URL}/${this.elementName}Get`, {
|
||||||
...axiosConfig,
|
...axiosConfig,
|
||||||
params: { id },
|
params: { id },
|
||||||
})
|
})
|
||||||
@ -51,7 +50,7 @@ export default class ServiceAccessors<
|
|||||||
return async (): Promise<ElementListGetResponse> => {
|
return async (): Promise<ElementListGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(
|
const { data } = await axios.get(
|
||||||
`${config.API_URL}/${this.elementName}ListGet`,
|
`${API_URL}/${this.elementName}ListGet`,
|
||||||
axiosConfig
|
axiosConfig
|
||||||
)
|
)
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
@ -77,7 +76,7 @@ export default class ServiceAccessors<
|
|||||||
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
||||||
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
||||||
const { data } = await axios.get(
|
const { data } = await axios.get(
|
||||||
`${config.API_URL}/${this.elementName}ListGet`,
|
`${API_URL}/${this.elementName}ListGet`,
|
||||||
fullAxiosConfig
|
fullAxiosConfig
|
||||||
)
|
)
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
@ -107,7 +106,7 @@ export default class ServiceAccessors<
|
|||||||
try {
|
try {
|
||||||
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
||||||
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
||||||
const rawData = await axios.get(`${config.API_URL}/${this.elementName}${apiName}`, {
|
const rawData = await axios.get(`${API_URL}/${this.elementName}${apiName}`, {
|
||||||
...fullAxiosConfig,
|
...fullAxiosConfig,
|
||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
@ -135,7 +134,7 @@ export default class ServiceAccessors<
|
|||||||
return async (volunteerWithoutId: ElementNoId): Promise<ElementGetResponse> => {
|
return async (volunteerWithoutId: ElementNoId): Promise<ElementGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${config.API_URL}/${this.elementName}Add`,
|
`${API_URL}/${this.elementName}Add`,
|
||||||
volunteerWithoutId,
|
volunteerWithoutId,
|
||||||
axiosConfig
|
axiosConfig
|
||||||
)
|
)
|
||||||
@ -160,7 +159,7 @@ export default class ServiceAccessors<
|
|||||||
return async (volunteer: Element): Promise<ElementGetResponse> => {
|
return async (volunteer: Element): Promise<ElementGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${config.API_URL}/${this.elementName}Set`,
|
`${API_URL}/${this.elementName}Set`,
|
||||||
volunteer,
|
volunteer,
|
||||||
axiosConfig
|
axiosConfig
|
||||||
)
|
)
|
||||||
@ -185,7 +184,7 @@ export default class ServiceAccessors<
|
|||||||
return async (): Promise<ElementCountGetResponse> => {
|
return async (): Promise<ElementCountGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(
|
const { data } = await axios.get(
|
||||||
`${config.API_URL}/${this.elementName}CountGet`,
|
`${API_URL}/${this.elementName}CountGet`,
|
||||||
axiosConfig
|
axiosConfig
|
||||||
)
|
)
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
@ -210,10 +209,10 @@ export default class ServiceAccessors<
|
|||||||
}
|
}
|
||||||
return async (...params: InputElements): Promise<ElementGetResponse> => {
|
return async (...params: InputElements): Promise<ElementGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(
|
const { data } = await axios.get(`${API_URL}/${this.elementName}${apiName}`, {
|
||||||
`${config.API_URL}/${this.elementName}${apiName}`,
|
...axiosConfig,
|
||||||
{ ...axiosConfig, params }
|
params,
|
||||||
)
|
})
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
throw Error(data.error)
|
throw Error(data.error)
|
||||||
}
|
}
|
||||||
@ -237,7 +236,7 @@ export default class ServiceAccessors<
|
|||||||
return async (...params: InputElements): Promise<ElementGetResponse> => {
|
return async (...params: InputElements): Promise<ElementGetResponse> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${config.API_URL}/${this.elementName}${apiName}`,
|
`${API_URL}/${this.elementName}${apiName}`,
|
||||||
params,
|
params,
|
||||||
axiosConfig
|
axiosConfig
|
||||||
)
|
)
|
||||||
@ -268,10 +267,10 @@ export default class ServiceAccessors<
|
|||||||
try {
|
try {
|
||||||
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
||||||
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
||||||
const { data } = await axios.get(
|
const { data } = await axios.get(`${API_URL}/${this.elementName}${apiName}`, {
|
||||||
`${config.API_URL}/${this.elementName}${apiName}`,
|
...fullAxiosConfig,
|
||||||
{ ...fullAxiosConfig, params }
|
params,
|
||||||
)
|
})
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
throw Error(data.error)
|
throw Error(data.error)
|
||||||
}
|
}
|
||||||
@ -300,7 +299,7 @@ export default class ServiceAccessors<
|
|||||||
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
const auth = { headers: { Authorization: `Bearer ${jwt}` } }
|
||||||
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
const fullAxiosConfig = _.defaultsDeep(auth, axiosConfig)
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${config.API_URL}/${this.elementName}${apiName}`,
|
`${API_URL}/${this.elementName}${apiName}`,
|
||||||
params,
|
params,
|
||||||
fullAxiosConfig
|
fullAxiosConfig
|
||||||
)
|
)
|
||||||
|
9
src/types/index.d.ts
vendored
9
src/types/index.d.ts
vendored
@ -4,6 +4,7 @@ declare const __DEV__: boolean
|
|||||||
declare const __LOCAL__: boolean
|
declare const __LOCAL__: boolean
|
||||||
declare const __REGISTER_DISCORD_COMMANDS__: boolean
|
declare const __REGISTER_DISCORD_COMMANDS__: boolean
|
||||||
declare const __TEST__: boolean
|
declare const __TEST__: boolean
|
||||||
|
declare const API_URL: string
|
||||||
|
|
||||||
declare module "*.svg"
|
declare module "*.svg"
|
||||||
declare module "*.gif"
|
declare module "*.gif"
|
||||||
@ -22,6 +23,7 @@ declare namespace NodeJS {
|
|||||||
__LOCAL__: boolean
|
__LOCAL__: boolean
|
||||||
__REGISTER_DISCORD_COMMANDS__: boolean
|
__REGISTER_DISCORD_COMMANDS__: boolean
|
||||||
__TEST__: boolean
|
__TEST__: boolean
|
||||||
|
API_URL: string
|
||||||
$RefreshReg$: () => void
|
$RefreshReg$: () => void
|
||||||
$RefreshSig$$: () => void
|
$RefreshSig$$: () => void
|
||||||
}
|
}
|
||||||
@ -30,6 +32,13 @@ declare namespace NodeJS {
|
|||||||
SENDGRID_API_KEY?: string
|
SENDGRID_API_KEY?: string
|
||||||
FORCE_ORANGE_PUBLIC_VAPID_KEY?: string
|
FORCE_ORANGE_PUBLIC_VAPID_KEY?: string
|
||||||
FORCE_ORANGE_PRIVATE_VAPID_KEY?: string
|
FORCE_ORANGE_PRIVATE_VAPID_KEY?: string
|
||||||
|
PORT?: string
|
||||||
|
HOST?: string
|
||||||
|
API_URL?: string
|
||||||
|
GCP_SERVICE_ACCOUNT_CLIENT_ID?: string
|
||||||
|
GCP_SERVICE_ACCOUNT_PRIVATE_KEY?: string
|
||||||
|
GCP_SERVICE_ACCOUNT_CLIENT_EMAIL?: string
|
||||||
|
GSHEET_ID?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer"
|
|||||||
export const isDev = process.env.NODE_ENV === "development"
|
export const isDev = process.env.NODE_ENV === "development"
|
||||||
const isLocal = process.env.LOCAL === "true"
|
const isLocal = process.env.LOCAL === "true"
|
||||||
const isRegisterDiscordCommands = process.env.REGISTER_DISCORD_COMMANDS === "true"
|
const isRegisterDiscordCommands = process.env.REGISTER_DISCORD_COMMANDS === "true"
|
||||||
|
|
||||||
const getStyleLoaders = (isWeb: boolean, isSass?: boolean) => {
|
const getStyleLoaders = (isWeb: boolean, isSass?: boolean) => {
|
||||||
let loaders: RuleSetUseItem[] = [
|
let loaders: RuleSetUseItem[] = [
|
||||||
{
|
{
|
||||||
@ -51,6 +52,7 @@ const getPlugins = (isWeb: boolean) => {
|
|||||||
__DEV__: isDev,
|
__DEV__: isDev,
|
||||||
__LOCAL__: isLocal,
|
__LOCAL__: isLocal,
|
||||||
__REGISTER_DISCORD_COMMANDS__: isRegisterDiscordCommands,
|
__REGISTER_DISCORD_COMMANDS__: isRegisterDiscordCommands,
|
||||||
|
API_URL: process.env.API_URL || "'http://localhost:3000'",
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4186,6 +4186,11 @@ domutils@^2.8.0:
|
|||||||
domelementtype "^2.2.0"
|
domelementtype "^2.2.0"
|
||||||
domhandler "^4.2.0"
|
domhandler "^4.2.0"
|
||||||
|
|
||||||
|
dotenv@^16.4.5:
|
||||||
|
version "16.4.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
|
||||||
|
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
|
||||||
|
|
||||||
download@^6.2.2:
|
download@^6.2.2:
|
||||||
version "6.2.5"
|
version "6.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714"
|
resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user