mirror of
https://github.com/Paris-est-Ludique/intranet.git
synced 2025-06-08 00:24:21 +02:00
Add Discord bot, reactivate team-assign
This commit is contained in:
parent
a906dfff07
commit
71fd770a27
@ -58,6 +58,7 @@ module.exports = {
|
||||
__SERVER__: true,
|
||||
__DEV__: true,
|
||||
__LOCAL__: false,
|
||||
__REGISTER_DISCORD_COMMANDS__: false,
|
||||
__TEST__: false,
|
||||
},
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ module.exports = {
|
||||
__CLIENT__: true,
|
||||
__SERVER__: false,
|
||||
__LOCAL__: false,
|
||||
__REGISTER_DISCORD_COMMANDS__: false,
|
||||
__TEST__: true,
|
||||
},
|
||||
maxConcurrency: 50,
|
||||
|
@ -43,6 +43,7 @@
|
||||
"ser": "yarn dev:build && node ./public/server",
|
||||
"dev:build": "cross-env NODE_ENV=development webpack --config ./webpack/server.config.ts",
|
||||
"local-start": "cross-env LOCAL=true yarn build && node ./public/server",
|
||||
"discord-register": "cross-env REGISTER_DISCORD_COMMANDS=true yarn build && node ./public/server",
|
||||
"start": "node ./public/server",
|
||||
"build": "run-s build:*",
|
||||
"build:server": "cross-env NODE_ENV=production webpack --config ./webpack/server.config.ts",
|
||||
@ -94,6 +95,7 @@
|
||||
"core-js": "^3.15.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"detect-node": "^2.1.0",
|
||||
"discord.js": "^14.7.1",
|
||||
"express": "^4.17.1",
|
||||
"fs": "^0.0.1-security",
|
||||
"google-auth-library": "^7.10.1",
|
||||
|
BIN
public/favicon.ico
Normal file → Executable file
BIN
public/favicon.ico
Normal file → Executable file
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 6.6 KiB |
@ -10,7 +10,7 @@ import { AskDayWishes, fetchFor as fetchForDayWishes } from "./AskDayWishes"
|
||||
// import { AskHosting, fetchFor as fetchForHosting } from "./AskHosting"
|
||||
// import { AskMeals, fetchFor as fetchForMeals } from "./AskMeals"
|
||||
// import { AskPersonalInfo, fetchFor as fetchForPersonalInfo } from "./AskPersonalInfo"
|
||||
// import { AskTeamWishes, fetchFor as fetchForTeamWishes } from "./AskTeamWishes"
|
||||
import { AskTeamWishes, fetchFor as fetchForTeamWishes } from "./AskTeamWishes"
|
||||
// import {
|
||||
// AskParticipationDetails,
|
||||
// fetchFor as fetchForParticipationDetails,
|
||||
@ -27,7 +27,7 @@ const Asks = (): JSX.Element | null => {
|
||||
AskDiscord(asks, 5)
|
||||
|
||||
AskDayWishes(asks, 10)
|
||||
// AskTeamWishes(asks, 11)
|
||||
AskTeamWishes(asks, 11)
|
||||
// AskParticipationDetails(asks, 12)
|
||||
// AskPersonalInfo(asks, 15)
|
||||
// AskHosting(asks, 20)
|
||||
@ -72,7 +72,7 @@ export const fetchFor = [
|
||||
...fetchForDayWishes,
|
||||
// ...fetchForHosting,
|
||||
// ...fetchForMeals,
|
||||
// ...fetchForTeamWishes,
|
||||
...fetchForTeamWishes,
|
||||
// ...fetchForParticipationDetails,
|
||||
// ...fetchForPersonalInfo,
|
||||
]
|
||||
|
@ -29,7 +29,7 @@ const LoginForm = (): JSX.Element => {
|
||||
return (
|
||||
<form>
|
||||
<div className={styles.loginIntro} key="login-intro">
|
||||
Si tu es bénévole, connecte-toi pour accéder à ton espace.
|
||||
Si tu es bénévole ou que tu l'as déjà été, connecte-toi pour accéder à ton espace.
|
||||
</div>
|
||||
<div className={styles.formLine} key="line-email">
|
||||
<label htmlFor="email">Email</label>
|
||||
|
@ -2,10 +2,10 @@ import React, { memo } from "react"
|
||||
import { useSelector } from "react-redux"
|
||||
import styles from "./styles.module.scss"
|
||||
import TeamItem from "./TeamItem"
|
||||
import { selectSortedActiveTeams } from "../../store/teamList"
|
||||
import { selectSortedTeams } from "../../store/teamList"
|
||||
|
||||
const TeamList: React.FC = (): JSX.Element | null => {
|
||||
const teams = useSelector(selectSortedActiveTeams)
|
||||
const teams = useSelector(selectSortedTeams)
|
||||
if (!teams || teams.length === 0) return null
|
||||
|
||||
return (
|
||||
|
@ -7,8 +7,8 @@ import DayWishesFormModal from "./DayWishesForm/DayWishesFormModal"
|
||||
// import MealsFormModal from "./MealsForm/MealsFormModal"
|
||||
// import ParticipationDetails from "./ParticipationDetails/ParticipationDetails"
|
||||
// import ParticipationDetailsFormModal from "./ParticipationDetailsForm/ParticipationDetailsFormModal"
|
||||
// import TeamWishes from "./TeamWishes/TeamWishes"
|
||||
// import TeamWishesFormModal from "./TeamWishesForm/TeamWishesFormModal"
|
||||
import TeamWishes from "./TeamWishes/TeamWishes"
|
||||
import TeamWishesFormModal from "./TeamWishesForm/TeamWishesFormModal"
|
||||
// import VolunteerTeam from "./VolunteerTeam/VolunteerTeam"
|
||||
import withUserConnected from "../../utils/withUserConnected"
|
||||
import ContentTitle from "../ui/Content/ContentTitle"
|
||||
@ -16,7 +16,7 @@ import { fetchFor as fetchForDayWishesForm } from "./DayWishesForm/DayWishesForm
|
||||
// import { fetchFor as fetchForHostingForm } from "./HostingForm/HostingForm"
|
||||
// import { fetchFor as fetchForMealsForm } from "./MealsForm/MealsForm"
|
||||
// import { fetchFor as fetchForParticipationDetailsForm } from "./ParticipationDetailsForm/ParticipationDetailsForm"
|
||||
// import { fetchFor as fetchForTeamWishesForm } from "./TeamWishesForm/TeamWishesForm"
|
||||
import { fetchFor as fetchForTeamWishesForm } from "./TeamWishesForm/TeamWishesForm"
|
||||
import { fetchFor as fetchForPersonalInfoForm } from "./PersonalInfoForm/PersonalInfoForm"
|
||||
import PersonalInfo from "./PersonalInfo/PersonalInfo"
|
||||
import PersonalInfoFormModal from "./PersonalInfoForm/PersonalInfoFormModal"
|
||||
@ -43,10 +43,10 @@ const Board: FC = (): JSX.Element => (
|
||||
<DayWishes />
|
||||
<DayWishesFormModal />
|
||||
{/* <ParticipationDetails />
|
||||
<ParticipationDetailsFormModal />
|
||||
<ParticipationDetailsFormModal /> */}
|
||||
<TeamWishes />
|
||||
<TeamWishesFormModal />
|
||||
<VolunteerTeam />
|
||||
{/* <VolunteerTeam />
|
||||
<Hosting />
|
||||
<HostingFormModal />
|
||||
<Meals />
|
||||
@ -66,5 +66,5 @@ export const fetchFor = [
|
||||
// ...fetchForHostingForm,
|
||||
// ...fetchForMealsForm,
|
||||
// ...fetchForParticipationDetailsForm,
|
||||
// ...fetchForTeamWishesForm,
|
||||
...fetchForTeamWishesForm,
|
||||
]
|
||||
|
@ -38,6 +38,12 @@ const DayWishes: FC = (): JSX.Element | null => {
|
||||
Je <b>ne sais pas encore</b> si je participerai à PeL 2023
|
||||
</div>
|
||||
)}
|
||||
{participation === "à distance" && (
|
||||
<div className={styles.participationLabel}>
|
||||
Je <b className={styles.yesParticipation}>participerai</b> à PeL 2023 ! Sans y
|
||||
être pendant le weekend.
|
||||
</div>
|
||||
)}
|
||||
{participation === "inconnu" && (
|
||||
<div className={styles.lineEmpty}>
|
||||
Participation à PeL 2023{" "}
|
||||
|
@ -16,4 +16,5 @@ export default {
|
||||
],
|
||||
},
|
||||
DEV_JWT_SECRET: "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!",
|
||||
DEV_DISCORD_TOKEN: "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!",
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import AsyncTeamAssignment, { loadData as loadTeamAssignmentData } from "../page
|
||||
import AsyncRegisterPage, { loadData as loadRegisterPage } from "../pages/Register"
|
||||
import AsyncKnowledge, { loadData as loadKnowledgeData } from "../pages/Knowledge"
|
||||
// import AsyncLoans, { loadData as loadLoansData } from "../pages/Loans"
|
||||
// import AsyncLoaning, { loadData as loadLoaningData } from "../pages/Loaning"
|
||||
import AsyncLoaning, { loadData as loadLoaningData } from "../pages/Loaning"
|
||||
import AsyncKnowledgeCards, { loadData as loadCardKnowledgeData } from "../pages/KnowledgeCards"
|
||||
import AsyncTeams, { loadData as loadTeamsData } from "../pages/Teams"
|
||||
import AsyncBoard, { loadData as loadBoardData } from "../pages/Board"
|
||||
@ -51,11 +51,11 @@ export default [
|
||||
// component: AsyncLoans,
|
||||
// loadData: loadLoansData,
|
||||
// },
|
||||
// {
|
||||
// path: "/emprunter",
|
||||
// component: AsyncLoaning,
|
||||
// loadData: loadLoaningData,
|
||||
// },
|
||||
{
|
||||
path: "/emprunter",
|
||||
component: AsyncLoaning,
|
||||
loadData: loadLoaningData,
|
||||
},
|
||||
{
|
||||
path: "/fiches",
|
||||
component: AsyncKnowledgeCards,
|
||||
|
405
src/server/discordBot.ts
Normal file
405
src/server/discordBot.ts
Normal file
@ -0,0 +1,405 @@
|
||||
import _ from "lodash"
|
||||
import {
|
||||
Client,
|
||||
GatewayIntentBits,
|
||||
Collection,
|
||||
Events,
|
||||
SlashCommandBuilder,
|
||||
CommandInteraction,
|
||||
/* REST, Routes, */ Partials,
|
||||
MessageReaction,
|
||||
PartialMessageReaction,
|
||||
Guild,
|
||||
User,
|
||||
PartialUser,
|
||||
} from "discord.js"
|
||||
import { promises as fs, constants } from "fs"
|
||||
import path from "path"
|
||||
|
||||
import { translationVolunteer, Volunteer, VolunteerWithoutId } from "../services/volunteers"
|
||||
import {
|
||||
translationDiscordRoles,
|
||||
DiscordRole,
|
||||
DiscordRoleWithoutId,
|
||||
} from "../services/discordRoles"
|
||||
import { getSheet } from "./gsheets/accessors"
|
||||
import config from "../config"
|
||||
|
||||
let cachedToken: string
|
||||
// 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 = {
|
||||
data: SlashCommandBuilder
|
||||
execute: (interaction: CommandInteraction) => Promise<void>
|
||||
}
|
||||
const commands: Collection<string, Command> = new Collection()
|
||||
|
||||
// const userCommand: Command = {
|
||||
// data: new SlashCommandBuilder()
|
||||
// .setName('user')
|
||||
// .setDescription('Provides information about the user.'),
|
||||
// async execute(interaction: CommandInteraction) {
|
||||
|
||||
// const { commandName } = interaction
|
||||
|
||||
// if (commandName === 'user') {
|
||||
// const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true })
|
||||
// message.react('😄')
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
|
||||
let hasDiscordAccessReturn: boolean | undefined
|
||||
export async function hasDiscordAccess(): Promise<boolean> {
|
||||
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> {
|
||||
// if (!__REGISTER_DISCORD_COMMANDS__) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// if (!(await hasDiscordAccess())) {
|
||||
// console.error(`Discord bot: no creds found, not running bot`)
|
||||
// return
|
||||
// }
|
||||
|
||||
// await getCreds()
|
||||
|
||||
// const commandsToRegister = []
|
||||
// commandsToRegister.push(userCommand.data.toJSON())
|
||||
|
||||
// const rest = new REST({ version: '10' }).setToken(cachedToken)
|
||||
|
||||
// try {
|
||||
// await rest.put(
|
||||
// Routes.applicationGuildCommands(cachedClientId, cachedGuildId),
|
||||
// { body: commandsToRegister },
|
||||
// )
|
||||
// } catch (error) {
|
||||
// console.error(error)
|
||||
// }
|
||||
|
||||
// process.exit()
|
||||
// }
|
||||
|
||||
export async function discordBot(): Promise<void> {
|
||||
try {
|
||||
if (__REGISTER_DISCORD_COMMANDS__) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!(await hasDiscordAccess())) {
|
||||
console.error(`Discord bot: no creds found, not running bot`)
|
||||
return
|
||||
}
|
||||
await getCreds()
|
||||
|
||||
const client = new Client({
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
GatewayIntentBits.GuildMessageReactions,
|
||||
GatewayIntentBits.GuildMembers,
|
||||
GatewayIntentBits.MessageContent,
|
||||
],
|
||||
partials: [Partials.Message, Partials.Channel, Partials.Reaction],
|
||||
})
|
||||
|
||||
// commands.set(userCommand.data.name, userCommand)
|
||||
|
||||
client.once(Events.ClientReady, (localClient) => {
|
||||
setInterval(() => setBotReactions(localClient), 5 * 60 * 1000)
|
||||
setTimeout(() => setBotReactions(localClient), 20 * 1000)
|
||||
|
||||
setInterval(() => setAllRoles(localClient), 5 * 60 * 1000)
|
||||
setTimeout(() => setAllRoles(localClient), 5 * 1000)
|
||||
})
|
||||
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return
|
||||
|
||||
const command = commands.get(interaction.commandName)
|
||||
|
||||
if (!command) {
|
||||
console.error(`No command matching ${interaction.commandName} was found.`)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await command.execute(interaction)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
})
|
||||
|
||||
client.on(Events.MessageReactionAdd, async (reaction, user) => {
|
||||
await fetchPartial(reaction)
|
||||
|
||||
await setRolesFromEmoji(client, user, reaction, "add")
|
||||
})
|
||||
|
||||
client.on(Events.MessageReactionRemove, async (reaction, user) => {
|
||||
await fetchPartial(reaction)
|
||||
|
||||
await setRolesFromEmoji(client, user, reaction, "remove")
|
||||
})
|
||||
|
||||
client.login(cachedToken)
|
||||
} catch (error) {
|
||||
console.error("Discord error", error)
|
||||
}
|
||||
}
|
||||
|
||||
async function setBotReactions(client: Client) {
|
||||
try {
|
||||
const discordRolesSheet = await getSheet<DiscordRoleWithoutId, DiscordRole>(
|
||||
"DiscordRoles",
|
||||
new DiscordRole(),
|
||||
translationDiscordRoles
|
||||
)
|
||||
const discordRolesList = await discordRolesSheet.getList()
|
||||
if (!discordRolesList) {
|
||||
return
|
||||
}
|
||||
|
||||
client.channels.cache.each(async (channel) => {
|
||||
if (!channel.isTextBased()) {
|
||||
return
|
||||
}
|
||||
|
||||
discordRolesList.forEach(async (discordRole: DiscordRole) => {
|
||||
let message
|
||||
try {
|
||||
message = await channel.messages.fetch(discordRole.messageId)
|
||||
} catch (error) {
|
||||
return
|
||||
}
|
||||
|
||||
const reaction = message.reactions.cache.find(
|
||||
(r) => r.emoji.name === discordRole.emoji
|
||||
)
|
||||
if (reaction) {
|
||||
return
|
||||
}
|
||||
await message.react(discordRole.emoji)
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Error in setBotReactions", error)
|
||||
}
|
||||
}
|
||||
|
||||
async function setAllRoles(client: Client) {
|
||||
try {
|
||||
const volunteerSheet = await getSheet<VolunteerWithoutId, Volunteer>(
|
||||
"Volunteers",
|
||||
new Volunteer(),
|
||||
translationVolunteer
|
||||
)
|
||||
const volunteerList = await volunteerSheet.getList()
|
||||
if (!volunteerList) {
|
||||
return
|
||||
}
|
||||
|
||||
const volunteerByDiscordId = _.mapKeys(volunteerList, (v) => v.discordId.toString())
|
||||
|
||||
const guild = await client.guilds.fetch(cachedGuildId)
|
||||
|
||||
if (!guild || !guild.members.cache) {
|
||||
return
|
||||
}
|
||||
|
||||
// Set (maybe) volunteer roles
|
||||
|
||||
const volunteerRoleIds: { [key: string]: string } = _.mapValues(
|
||||
{
|
||||
oui: "Bénévole",
|
||||
"peut-etre": "Bénévole incertain",
|
||||
"à distance": "Bénévole à distance",
|
||||
non: "",
|
||||
},
|
||||
(v) => (_.isEmpty(v) ? "" : guild.roles.cache.find((role) => role.name === v)?.id || "")
|
||||
)
|
||||
|
||||
await setVolunteersRoles(
|
||||
guild,
|
||||
volunteerByDiscordId,
|
||||
volunteerRoleIds,
|
||||
(volunteer: Volunteer) => volunteer.active
|
||||
)
|
||||
|
||||
// Set Team- and Référent- roles
|
||||
|
||||
const teamIds = {
|
||||
"1": "accueil",
|
||||
"5": "paillante",
|
||||
"21": "photo",
|
||||
"4": "tournois",
|
||||
// "19": "exposants-asso", ignored because it's mixed with volunteers of last edition
|
||||
"2": "jav",
|
||||
"18": "jeux-xl",
|
||||
"27": "ring",
|
||||
"8": "coindespetitsjoueurs",
|
||||
"23": "jeuxdelires",
|
||||
"3": "jdd",
|
||||
"9": "figurines",
|
||||
"10": "jdr",
|
||||
"28": "jeuxhistoire",
|
||||
"6": "évènements",
|
||||
"29": "presse",
|
||||
"30": "initiation-18xx",
|
||||
"0": "",
|
||||
}
|
||||
|
||||
const teamRoleIds: { [key: string]: string } = _.mapValues(teamIds, (v) =>
|
||||
_.isEmpty(v)
|
||||
? ""
|
||||
: guild.roles.cache.find((role) => role.name === `Team-${v}`)?.id || ""
|
||||
)
|
||||
|
||||
await setVolunteersRoles(guild, volunteerByDiscordId, teamRoleIds, (volunteer: Volunteer) =>
|
||||
_.includes(["oui", "peut-etre", "à distance"], volunteer.active)
|
||||
? `${volunteer.team}`
|
||||
: ""
|
||||
)
|
||||
|
||||
const referentRoleIds: { [key: string]: string } = _.mapValues(teamIds, (v) =>
|
||||
_.isEmpty(v)
|
||||
? ""
|
||||
: guild.roles.cache.find((role) => role.name === `Référent-${v}`)?.id || ""
|
||||
)
|
||||
|
||||
await setVolunteersRoles(
|
||||
guild,
|
||||
volunteerByDiscordId,
|
||||
referentRoleIds,
|
||||
(volunteer: Volunteer) =>
|
||||
_.includes(["oui", "peut-etre", "à distance"], volunteer.active) &&
|
||||
volunteer.roles.includes("référent")
|
||||
? `${volunteer.team}`
|
||||
: "0"
|
||||
)
|
||||
} catch (error) {
|
||||
console.error("Error in setAllRoles", error)
|
||||
}
|
||||
}
|
||||
|
||||
async function setVolunteersRoles(
|
||||
guild: Guild,
|
||||
volunteerByDiscordId: { [key: string]: Volunteer },
|
||||
volunteerRoleIds: { [key: string]: string },
|
||||
funcKey: (volunteer: Volunteer) => string
|
||||
) {
|
||||
const members = await guild.members.fetch()
|
||||
members.each(async (member) => {
|
||||
const volunteer = volunteerByDiscordId[member.id]
|
||||
if (!volunteer) {
|
||||
return
|
||||
}
|
||||
|
||||
_.forOwn(volunteerRoleIds, (roleId, active) => {
|
||||
if (!roleId) {
|
||||
return
|
||||
}
|
||||
|
||||
const shouldHaveRole = active === funcKey(volunteer)
|
||||
const hasRole = member.roles.cache.has(roleId)
|
||||
|
||||
if (hasRole && !shouldHaveRole) {
|
||||
member.roles.remove(roleId)
|
||||
} else if (!hasRole && shouldHaveRole) {
|
||||
member.roles.add(roleId)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function setRolesFromEmoji(
|
||||
client: Client,
|
||||
user: User | PartialUser,
|
||||
reaction: MessageReaction | PartialMessageReaction,
|
||||
action: "add" | "remove"
|
||||
) {
|
||||
const discordRolesSheet = await getSheet<DiscordRoleWithoutId, DiscordRole>(
|
||||
"DiscordRoles",
|
||||
new DiscordRole(),
|
||||
translationDiscordRoles
|
||||
)
|
||||
const discordRolesList = await discordRolesSheet.getList()
|
||||
if (!discordRolesList) {
|
||||
return
|
||||
}
|
||||
|
||||
await client.guilds.fetch()
|
||||
const guild = client.guilds.resolve(cachedGuildId)
|
||||
|
||||
if (!guild || !guild.members.cache) {
|
||||
return
|
||||
}
|
||||
|
||||
discordRolesList.forEach(async (discordRole: DiscordRole) => {
|
||||
if (
|
||||
reaction.message.id === discordRole.messageId &&
|
||||
reaction.emoji.name === discordRole.emoji
|
||||
) {
|
||||
const roleId = guild.roles.cache.find((role) => role.name === discordRole.role)
|
||||
if (!roleId) {
|
||||
return
|
||||
}
|
||||
|
||||
const member = guild.members.cache.find((m) => m.id === user.id)
|
||||
if (!member) {
|
||||
return
|
||||
}
|
||||
await member.fetch()
|
||||
if (action === "add") {
|
||||
member.roles.add(roleId)
|
||||
} else if (action === "remove") {
|
||||
member.roles.remove(roleId)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function fetchPartial(reaction: MessageReaction | PartialMessageReaction): Promise<boolean> {
|
||||
if (reaction.partial) {
|
||||
try {
|
||||
await reaction.fetch()
|
||||
} catch (error) {
|
||||
console.error("Something went wrong when fetching the message", error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -11,8 +11,8 @@ export { SheetNames } from "./localDb"
|
||||
|
||||
const CRED_PATH = path.resolve(process.cwd(), "access/gsheets.json")
|
||||
|
||||
const REMOTE_UPDATE_DELAY = 40000
|
||||
const DELAY_BETWEEN_ATTEMPTS = 10000
|
||||
const REMOTE_UPDATE_DELAY = 120000
|
||||
const DELAY_BETWEEN_ATTEMPTS = 30000
|
||||
const DELAY_BETWEEN_FIRST_LOAD = 1500
|
||||
|
||||
let creds: string | undefined | null
|
||||
@ -59,7 +59,7 @@ export async function getSheet<
|
||||
sheet = new Sheet<ElementNoId, Element>(sheetName, specimen, translation)
|
||||
await sheet.waitForFirstLoad()
|
||||
sheetList[sheetName] = sheet
|
||||
setInterval(() => sheet.dbUpdate(), REMOTE_UPDATE_DELAY)
|
||||
setInterval(() => sheet.dbUpdate(), REMOTE_UPDATE_DELAY * (1 + Math.random() / 10))
|
||||
} else {
|
||||
sheet = sheetList[sheetName] as Sheet<ElementNoId, Element>
|
||||
}
|
||||
@ -265,6 +265,7 @@ export class Sheet<
|
||||
}
|
||||
|
||||
await tryNTimesVoidReturn(async () => {
|
||||
console.log(`dbSaveAsync on ${this.name} at ${new Date()}`)
|
||||
// Load sheet into an array of objects
|
||||
const rows = await sheet.getRows()
|
||||
if (!rows[0]) {
|
||||
@ -317,6 +318,7 @@ export class Sheet<
|
||||
await rows[rowToDelete].delete()
|
||||
}
|
||||
}
|
||||
console.log(`dbSaveAsync successful on ${this.name} at ${new Date()}`)
|
||||
})
|
||||
}
|
||||
|
||||
@ -330,6 +332,7 @@ export class Sheet<
|
||||
|
||||
await tryNTimesVoidReturn(async () => {
|
||||
// Load sheet into an array of objects
|
||||
console.log(`dbLoadAsync on ${this.name} at ${new Date()}`)
|
||||
const rows = (await sheet.getRows()) as StringifiedElement[]
|
||||
const elements: Element[] = []
|
||||
if (!rows[0]) {
|
||||
@ -357,6 +360,7 @@ export class Sheet<
|
||||
})
|
||||
|
||||
this._state = elements
|
||||
console.log(`dbLoadAsync successful on ${this.name} at ${new Date()}`)
|
||||
})
|
||||
}
|
||||
|
||||
|
14
src/server/gsheets/discordRoles.ts
Normal file
14
src/server/gsheets/discordRoles.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import ExpressAccessors from "./expressAccessors"
|
||||
import {
|
||||
DiscordRole,
|
||||
DiscordRoleWithoutId,
|
||||
translationDiscordRoles,
|
||||
} from "../../services/discordRoles"
|
||||
|
||||
const expressAccessor = new ExpressAccessors<DiscordRoleWithoutId, DiscordRole>(
|
||||
"DiscordRoles",
|
||||
new DiscordRole(),
|
||||
translationDiscordRoles
|
||||
)
|
||||
|
||||
export const discordRolesListGet = expressAccessor.listGet()
|
@ -16,6 +16,8 @@ export class SheetNames {
|
||||
|
||||
Boxes = "Boîtes"
|
||||
|
||||
DiscordRoles = "Rôles Discord"
|
||||
|
||||
Games = "Jeux"
|
||||
|
||||
Miscs = "Divers"
|
||||
|
@ -50,6 +50,7 @@ import {
|
||||
import { wishListGet, wishAdd } from "./gsheets/wishes"
|
||||
import config from "../config"
|
||||
import { notificationsSubscribe, notificationMain } from "./notifications"
|
||||
import { /* discordRegisterCommands, */ discordBot, hasDiscordAccess } from "./discordBot"
|
||||
import checkAccess from "./checkAccess"
|
||||
import { hasGSheetsAccess } from "./gsheets/accessors"
|
||||
import { addStatus, showStatusAt } from "./status"
|
||||
@ -64,6 +65,9 @@ checkAccess()
|
||||
|
||||
notificationMain()
|
||||
|
||||
// discordRegisterCommands()
|
||||
discordBot()
|
||||
|
||||
const app = express()
|
||||
|
||||
// Allow receiving big images
|
||||
@ -243,6 +247,14 @@ if (hasPushNotifAccess) {
|
||||
addStatus("Push notif:", chalk.blue(`🚧 offline, simulated`))
|
||||
}
|
||||
|
||||
hasDiscordAccess().then((hasApiAccess: boolean) => {
|
||||
if (hasApiAccess) {
|
||||
addStatus("Discord bot:", chalk.green(`✅ online through discord.js`))
|
||||
} else {
|
||||
addStatus("Discord bot:", chalk.blue(`🚧 no creds, disabled`))
|
||||
}
|
||||
})
|
||||
|
||||
hasSecret().then((has: boolean) => {
|
||||
if (has) {
|
||||
addStatus("JWT secret:", chalk.green(`✅ prod private one from file`))
|
||||
|
@ -108,7 +108,9 @@ async function notifyAboutAnnouncement(): Promise<void> {
|
||||
}
|
||||
|
||||
const audience = volunteerList.filter(
|
||||
(v) => v.acceptsNotifs === "oui" && (v.active === "oui" || v.active === "peut-etre")
|
||||
(v) =>
|
||||
v.acceptsNotifs === "oui" &&
|
||||
(v.active === "oui" || v.active === "peut-etre" || v.active === "à distance")
|
||||
)
|
||||
|
||||
console.error(
|
||||
|
28
src/services/discordRoles.ts
Normal file
28
src/services/discordRoles.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
export class DiscordRole {
|
||||
id = 0
|
||||
|
||||
messageId = ""
|
||||
|
||||
emoji = ""
|
||||
|
||||
role = ""
|
||||
}
|
||||
|
||||
export const translationDiscordRoles: { [k in keyof DiscordRole]: string } = {
|
||||
id: "id",
|
||||
messageId: "messageId",
|
||||
emoji: "emoji",
|
||||
role: "rôle",
|
||||
}
|
||||
|
||||
export const elementName = "DiscordRoles"
|
||||
|
||||
export type DiscordRoleWithoutId = Omit<DiscordRole, "id">
|
||||
|
||||
export interface DiscordRole {
|
||||
id: DiscordRole["id"]
|
||||
messageId: DiscordRole["messageId"]
|
||||
emoji: DiscordRole["emoji"]
|
||||
role: DiscordRole["role"]
|
||||
}
|
@ -59,6 +59,10 @@ export const selectTeamList = createSelector(
|
||||
}
|
||||
)
|
||||
|
||||
export const selectSortedTeams = createSelector(selectTeamList, (teams) =>
|
||||
[...teams].sort((a, b) => get(a, "order", 0) - get(b, "order", 0))
|
||||
)
|
||||
|
||||
export const selectSortedActiveTeams = createSelector(selectTeamList, (teams) =>
|
||||
[...teams.filter((team) => get(team, "status") === "active")].sort(
|
||||
(a, b) => get(a, "order", 0) - get(b, "order", 0)
|
||||
|
2
src/types/index.d.ts
vendored
2
src/types/index.d.ts
vendored
@ -2,6 +2,7 @@ declare const __CLIENT__: boolean
|
||||
declare const __SERVER__: boolean
|
||||
declare const __DEV__: boolean
|
||||
declare const __LOCAL__: boolean
|
||||
declare const __REGISTER_DISCORD_COMMANDS__: boolean
|
||||
declare const __TEST__: boolean
|
||||
|
||||
declare module "*.svg"
|
||||
@ -19,6 +20,7 @@ declare namespace NodeJS {
|
||||
__SERVER__: boolean
|
||||
__DEV__: boolean
|
||||
__LOCAL__: boolean
|
||||
__REGISTER_DISCORD_COMMANDS__: boolean
|
||||
__TEST__: boolean
|
||||
$RefreshReg$: () => void
|
||||
$RefreshSig$$: () => void
|
||||
|
@ -9,6 +9,7 @@ import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer"
|
||||
|
||||
export const isDev = process.env.NODE_ENV === "development"
|
||||
const isLocal = process.env.LOCAL === "true"
|
||||
const isRegisterDiscordCommands = process.env.REGISTER_DISCORD_COMMANDS === "true"
|
||||
const getStyleLoaders = (isWeb: boolean, isSass?: boolean) => {
|
||||
let loaders: RuleSetUseItem[] = [
|
||||
{
|
||||
@ -49,6 +50,7 @@ const getPlugins = (isWeb: boolean) => {
|
||||
__SERVER__: !isWeb,
|
||||
__DEV__: isDev,
|
||||
__LOCAL__: isLocal,
|
||||
__REGISTER_DISCORD_COMMANDS__: isRegisterDiscordCommands,
|
||||
}),
|
||||
]
|
||||
|
||||
|
167
yarn.lock
167
yarn.lock
@ -1037,6 +1037,42 @@
|
||||
dependencies:
|
||||
"@jridgewell/trace-mapping" "0.3.9"
|
||||
|
||||
"@discordjs/builders@^1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@discordjs/builders/-/builders-1.4.0.tgz#b951b5e6ce4e459cd06174ce50dbd51c254c1d47"
|
||||
integrity sha512-nEeTCheTTDw5kO93faM1j8ZJPonAX86qpq/QVoznnSa8WWcCgJpjlu6GylfINTDW6o7zZY0my2SYdxx2mfNwGA==
|
||||
dependencies:
|
||||
"@discordjs/util" "^0.1.0"
|
||||
"@sapphire/shapeshift" "^3.7.1"
|
||||
discord-api-types "^0.37.20"
|
||||
fast-deep-equal "^3.1.3"
|
||||
ts-mixer "^6.0.2"
|
||||
tslib "^2.4.1"
|
||||
|
||||
"@discordjs/collection@^1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-1.3.0.tgz#65bf9674db72f38c25212be562bb28fa0dba6aa3"
|
||||
integrity sha512-ylt2NyZ77bJbRij4h9u/wVy7qYw/aDqQLWnadjvDqW/WoWCxrsX6M3CIw9GVP5xcGCDxsrKj5e0r5evuFYwrKg==
|
||||
|
||||
"@discordjs/rest@^1.4.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@discordjs/rest/-/rest-1.5.0.tgz#dc15474ab98cf6f31291bf61bbc72bcf4f30cea2"
|
||||
integrity sha512-lXgNFqHnbmzp5u81W0+frdXN6Etf4EUi8FAPcWpSykKd8hmlWh1xy6BmE0bsJypU1pxohaA8lQCgp70NUI3uzA==
|
||||
dependencies:
|
||||
"@discordjs/collection" "^1.3.0"
|
||||
"@discordjs/util" "^0.1.0"
|
||||
"@sapphire/async-queue" "^1.5.0"
|
||||
"@sapphire/snowflake" "^3.2.2"
|
||||
discord-api-types "^0.37.23"
|
||||
file-type "^18.0.0"
|
||||
tslib "^2.4.1"
|
||||
undici "^5.13.0"
|
||||
|
||||
"@discordjs/util@^0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@discordjs/util/-/util-0.1.0.tgz#e42ca1bf407bc6d9adf252877d1b206e32ba369a"
|
||||
integrity sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==
|
||||
|
||||
"@discoveryjs/json-ext@^0.5.0":
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
|
||||
@ -1442,6 +1478,24 @@
|
||||
redux-thunk "^2.4.1"
|
||||
reselect "^4.1.5"
|
||||
|
||||
"@sapphire/async-queue@^1.5.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@sapphire/async-queue/-/async-queue-1.5.0.tgz#2f255a3f186635c4fb5a2381e375d3dfbc5312d8"
|
||||
integrity sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==
|
||||
|
||||
"@sapphire/shapeshift@^3.7.1":
|
||||
version "3.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@sapphire/shapeshift/-/shapeshift-3.8.1.tgz#b98dc6a7180f9b38219267917b2e6fa33f9ec656"
|
||||
integrity sha512-xG1oXXBhCjPKbxrRTlox9ddaZTvVpOhYLmKmApD/vIWOV1xEYXnpoFs68zHIZBGbqztq6FrUPNPerIrO1Hqeaw==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@sapphire/snowflake@^3.2.2":
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@sapphire/snowflake/-/snowflake-3.4.0.tgz#25c012158a9feea2256c718985dbd6c1859a5022"
|
||||
integrity sha512-zZxymtVO6zeXVMPds+6d7gv/OfnCc25M1Z+7ZLB0oPmeMTPeRWVPQSS16oDJy5ZsyCOLj7M6mbZml5gWXcVRNw==
|
||||
|
||||
"@sendgrid/client@^7.7.0":
|
||||
version "7.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.7.0.tgz#f8f67abd604205a0d0b1af091b61517ef465fdbf"
|
||||
@ -1556,6 +1610,11 @@
|
||||
"@testing-library/dom" "^8.0.0"
|
||||
"@types/react-dom" "<18.0.0"
|
||||
|
||||
"@tokenizer/token@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
|
||||
integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==
|
||||
|
||||
"@tootallnate/once@1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
@ -2164,6 +2223,13 @@
|
||||
anymatch "^3.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/ws@^8.5.3":
|
||||
version "8.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5"
|
||||
integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/xml2js@^0.4.11":
|
||||
version "0.4.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.11.tgz#bf46a84ecc12c41159a7bd9cf51ae84129af0e79"
|
||||
@ -3102,6 +3168,13 @@ buffer@^5.2.1:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
busboy@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
|
||||
dependencies:
|
||||
streamsearch "^1.1.0"
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
@ -4006,6 +4079,29 @@ dir-glob@^3.0.1:
|
||||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
discord-api-types@^0.37.20, discord-api-types@^0.37.23:
|
||||
version "0.37.31"
|
||||
resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.37.31.tgz#128d33d641fd9a92fba97a47d7052e1f5694ec27"
|
||||
integrity sha512-k9DQQ7Wv+ehiF7901qk/FnP47k6O2MHm3meQFee4gUzi5dfGAVLf7SfLNtb4w7G2dmukJyWQtVJEDF9oMb9yuQ==
|
||||
|
||||
discord.js@^14.7.1:
|
||||
version "14.7.1"
|
||||
resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-14.7.1.tgz#26079d0ff4d27daf02480a403c456121f0682bd9"
|
||||
integrity sha512-1FECvqJJjjeYcjSm0IGMnPxLqja/pmG1B0W2l3lUY2Gi4KXiyTeQmU1IxWcbXHn2k+ytP587mMWqva2IA87EbA==
|
||||
dependencies:
|
||||
"@discordjs/builders" "^1.4.0"
|
||||
"@discordjs/collection" "^1.3.0"
|
||||
"@discordjs/rest" "^1.4.0"
|
||||
"@discordjs/util" "^0.1.0"
|
||||
"@sapphire/snowflake" "^3.2.2"
|
||||
"@types/ws" "^8.5.3"
|
||||
discord-api-types "^0.37.20"
|
||||
fast-deep-equal "^3.1.3"
|
||||
lodash.snakecase "^4.1.1"
|
||||
tslib "^2.4.1"
|
||||
undici "^5.13.0"
|
||||
ws "^8.11.0"
|
||||
|
||||
doctrine@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
|
||||
@ -4834,6 +4930,15 @@ file-type@^12.0.0:
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-12.4.2.tgz#a344ea5664a1d01447ee7fb1b635f72feb6169d9"
|
||||
integrity sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==
|
||||
|
||||
file-type@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-18.2.0.tgz#c2abec00d1af0f09151e1549e3588aab0bac5001"
|
||||
integrity sha512-M3RQMWY3F2ykyWZ+IHwNCjpnUmukYhtdkGGC1ZVEUb0ve5REGF7NNJ4Q9ehCUabtQKtSVFOMbFTXgJlFb0DQIg==
|
||||
dependencies:
|
||||
readable-web-to-node-stream "^3.0.2"
|
||||
strtok3 "^7.0.0"
|
||||
token-types "^5.0.1"
|
||||
|
||||
file-type@^3.8.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
|
||||
@ -5648,7 +5753,7 @@ identity-obj-proxy@^3.0.0:
|
||||
dependencies:
|
||||
harmony-reflect "^1.4.6"
|
||||
|
||||
ieee754@^1.1.13:
|
||||
ieee754@^1.1.13, ieee754@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||
@ -7014,6 +7119,11 @@ lodash.once@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
||||
integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==
|
||||
|
||||
lodash.snakecase@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
|
||||
integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==
|
||||
|
||||
lodash.truncate@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
||||
@ -7990,6 +8100,11 @@ path-type@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
peek-readable@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec"
|
||||
integrity sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==
|
||||
|
||||
pend@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
@ -8787,6 +8902,13 @@ readable-stream@^3.1.1, readable-stream@^3.6.0:
|
||||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
readable-web-to-node-stream@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb"
|
||||
integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==
|
||||
dependencies:
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||
@ -9495,6 +9617,11 @@ statuses@2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
||||
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
|
||||
|
||||
strict-uri-encode@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||
@ -9665,6 +9792,14 @@ strnum@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
|
||||
integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==
|
||||
|
||||
strtok3@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0.tgz#868c428b4ade64a8fd8fee7364256001c1a4cbe5"
|
||||
integrity sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==
|
||||
dependencies:
|
||||
"@tokenizer/token" "^0.3.0"
|
||||
peek-readable "^5.0.0"
|
||||
|
||||
style-search@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
|
||||
@ -10000,6 +10135,14 @@ toidentifier@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
token-types@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/token-types/-/token-types-5.0.1.tgz#aa9d9e6b23c420a675e55413b180635b86a093b4"
|
||||
integrity sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==
|
||||
dependencies:
|
||||
"@tokenizer/token" "^0.3.0"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
totalist@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
||||
@ -10070,6 +10213,11 @@ ts-jest@^27.0.3:
|
||||
semver "7.x"
|
||||
yargs-parser "20.x"
|
||||
|
||||
ts-mixer@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ts-mixer/-/ts-mixer-6.0.2.tgz#3e4e4bb8daffb24435f6980b15204cb5b287e016"
|
||||
integrity sha512-zvHx3VM83m2WYCE8XL99uaM7mFwYSkjR2OZti98fabHrwkjsCvgwChda5xctein3xGOyaQhtTeDq/1H/GNvF3A==
|
||||
|
||||
ts-node@^10.0.0:
|
||||
version "10.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
|
||||
@ -10109,6 +10257,11 @@ tslib@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
|
||||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
|
||||
tslib@^2.4.1:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
|
||||
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
||||
@ -10215,6 +10368,13 @@ undefsafe@^2.0.5:
|
||||
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
|
||||
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
|
||||
|
||||
undici@^5.13.0:
|
||||
version "5.16.0"
|
||||
resolved "https://registry.yarnpkg.com/undici/-/undici-5.16.0.tgz#6b64f9b890de85489ac6332bd45ca67e4f7d9943"
|
||||
integrity sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ==
|
||||
dependencies:
|
||||
busboy "^1.6.0"
|
||||
|
||||
unicode-canonical-property-names-ecmascript@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
|
||||
@ -10705,6 +10865,11 @@ ws@^7.3.1, ws@^7.4.6:
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
|
||||
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
|
||||
|
||||
ws@^8.11.0:
|
||||
version "8.12.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8"
|
||||
integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==
|
||||
|
||||
xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
||||
|
Loading…
x
Reference in New Issue
Block a user