Add volunteerParticipationDetailsSet to store

This commit is contained in:
pikiou 2022-01-25 03:28:20 +01:00
parent 1e302e6c31
commit f890ab505b
5 changed files with 158 additions and 31 deletions

View File

@ -11,6 +11,7 @@ import {
VolunteerTeamWishes,
translationVolunteer,
VolunteerDayWishes,
VolunteerParticipationDetails,
} from "../../services/volunteers"
import { canonicalEmail } from "../../utils/standardization"
import { getJwt } from "../secure"
@ -87,6 +88,32 @@ export const volunteerForgot = expressAccessor.set(async (list, bodyArray) => {
}
})
function generatePassword(): string {
const s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return Array(16)
.join()
.split(",")
.map(() => s.charAt(Math.floor(Math.random() * s.length)))
.join("")
}
async function sendForgetEmail(email: string, password: string): Promise<void> {
const apiKey = process.env.SENDGRID_API_KEY || ""
if (__DEV__ || apiKey === "") {
console.error(`Fake sending forget email to ${email} with password ${password}`)
} else {
sgMail.setApiKey(apiKey)
const msg = {
to: email,
from: "contact@parisestludique.fr",
subject: "Nouveau mot de passe pour le site de Paris est Ludique",
text: `Voici le nouveau mot de passe : ${password}\nL'ancien fonctionne encore, si tu t'en rappelles.`,
html: `Voici le nouveau mot de passe : <strong>${password}</strong><br />L'ancien fonctionne encore, si tu t'en rappelles.`,
}
await sgMail.send(msg)
}
}
export const volunteerNotifsSet = expressAccessor.set(async (list, body, id) => {
const requestedId = +body[0] || id
if (requestedId !== id && requestedId !== 0) {
@ -172,34 +199,42 @@ export const volunteerDayWishesSet = expressAccessor.set(async (list, body, id)
} as VolunteerDayWishes,
}
})
function getByEmail(list: Volunteer[], rawEmail: string): Volunteer | undefined {
export const volunteerParticipationDetailsSet = expressAccessor.set(async (list, body, id) => {
const requestedId = +body[0] || id
if (requestedId !== id && requestedId !== 0) {
throw Error(`On ne peut acceder qu'à ses propres infos d'age, taille et alimentation`)
}
const wishes = body[1] as VolunteerParticipationDetails
const volunteer = list.find((v) => v.id === requestedId)
if (!volunteer) {
throw Error(`Il n'y a aucun bénévole avec cet identifiant ${requestedId}`)
}
const newVolunteer = _.cloneDeep(volunteer)
if (wishes.age !== undefined) {
newVolunteer.age = wishes.age
}
if (wishes.teeshirtSize !== undefined) {
newVolunteer.teeshirtSize = wishes.teeshirtSize
}
if (wishes.food !== undefined) {
newVolunteer.food = wishes.food
}
return {
toDatabase: newVolunteer,
toCaller: {
id: newVolunteer.id,
age: newVolunteer.age,
teeshirtSize: newVolunteer.teeshirtSize,
food: newVolunteer.food,
} as VolunteerParticipationDetails,
}
})
function getByEmail<T extends { email: string }>(list: T[], rawEmail: string): T | undefined {
const email = canonicalEmail(rawEmail || "")
const volunteer = list.find((v) => canonicalEmail(v.email) === email)
return volunteer
}
function generatePassword(): string {
const s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return Array(16)
.join()
.split(",")
.map(() => s.charAt(Math.floor(Math.random() * s.length)))
.join("")
}
async function sendForgetEmail(email: string, password: string): Promise<void> {
const apiKey = process.env.SENDGRID_API_KEY || ""
if (__DEV__ || apiKey === "") {
console.error(`Fake sending forget email to ${email} with password ${password}`)
} else {
sgMail.setApiKey(apiKey)
const msg = {
to: email,
from: "contact@parisestludique.fr",
subject: "Nouveau mot de passe pour le site de Paris est Ludique",
text: `Voici le nouveau mot de passe : ${password}\nL'ancien fonctionne encore, si tu t'en rappelles.`,
html: `Voici le nouveau mot de passe : <strong>${password}</strong><br />L'ancien fonctionne encore, si tu t'en rappelles.`,
}
await sgMail.send(msg)
}
}

View File

@ -25,6 +25,7 @@ import {
volunteerLogin,
volunteerForgot,
volunteerNotifsSet,
volunteerParticipationDetailsSet,
volunteerTeamWishesSet,
volunteerDayWishesSet,
} from "./gsheets/volunteers"
@ -77,6 +78,11 @@ app.post("/VolunteerSet", secure as RequestHandler, volunteerSet)
app.get("/TeamListGet", teamListGet)
// UNSAFE app.post("/VolunteerGet", secure as RequestHandler, volunteerGet)
app.post("/VolunteerNotifsSet", secure as RequestHandler, volunteerNotifsSet)
app.post(
"/VolunteerParticipationDetailsSet",
secure as RequestHandler,
volunteerParticipationDetailsSet
)
app.post("/VolunteerDayWishesSet", secure as RequestHandler, volunteerDayWishesSet)
app.post("/VolunteerTeamWishesSet", secure as RequestHandler, volunteerTeamWishesSet)

View File

@ -13,8 +13,6 @@ export class Volunteer {
photo = ""
food = ""
adult = 1
privileges = 0
@ -25,6 +23,12 @@ export class Volunteer {
dayWishesComment = ""
age = 0
teeshirtSize = ""
food = ""
teamWishes: string[] = []
teamWishesComment = ""
@ -49,12 +53,14 @@ export const translationVolunteer: { [k in keyof Volunteer]: string } = {
email: "mail",
mobile: "telephone",
photo: "photo",
food: "alimentation",
adult: "majeur",
privileges: "privilege",
active: "actif",
dayWishes: "enviesJours",
dayWishesComment: "commentaireEnviesJours",
age: "age",
teeshirtSize: "teeshirt",
food: "alimentation",
teamWishes: "enviesEquipe",
teamWishesComment: "commentaireEnviesEquipe",
hiddenNotifs: "notifsCachees",
@ -74,12 +80,14 @@ export const volunteerExample: Volunteer = {
email: "pakouille.lakouille@yahoo.fr",
mobile: "0675650392",
photo: "images/volunteers/$taille/amélie_aupeix.jpg",
food: "Végétarien",
adult: 1,
privileges: 0,
active: "inconnu",
dayWishes: [],
dayWishesComment: "",
age: 33,
teeshirtSize: "FM",
food: "Végétarien",
teamWishes: [],
teamWishesComment: "",
hiddenNotifs: [],
@ -142,3 +150,14 @@ export interface VolunteerDayWishes {
}
export const volunteerDayWishesSet =
serviceAccessors.securedCustomPost<[number, Partial<VolunteerDayWishes>]>("DayWishesSet")
export interface VolunteerParticipationDetails {
id: Volunteer["id"]
age: Volunteer["age"]
teeshirtSize: Volunteer["teeshirtSize"]
food: Volunteer["food"]
}
export const volunteerParticipationDetailsSet =
serviceAccessors.securedCustomPost<[number, Partial<VolunteerParticipationDetails>]>(
"ParticipationDetailsSet"
)

View File

@ -13,6 +13,7 @@ import volunteerSet from "./volunteerSet"
import volunteerLogin from "./volunteerLogin"
import volunteerForgot from "./volunteerForgot"
import volunteerNotifsSet from "./volunteerNotifsSet"
import volunteerParticipationDetailsSet from "./volunteerParticipationDetailsSet"
import volunteerDayWishesSet from "./volunteerDayWishesSet"
import volunteerTeamWishesSet from "./volunteerTeamWishesSet"
import wishAdd from "./wishAdd"
@ -33,6 +34,7 @@ export default (history: History) => ({
volunteerLogin,
volunteerForgot,
volunteerNotifsSet,
volunteerParticipationDetailsSet,
volunteerDayWishesSet,
volunteerTeamWishesSet,
wishAdd,

View File

@ -0,0 +1,65 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
import { StateRequest, toastError, elementFetch } from "./utils"
import {
VolunteerParticipationDetails,
volunteerParticipationDetailsSet,
} from "../services/volunteers"
import { AppThunk, AppState } from "."
type StateVolunteerParticipationDetailsSet = {
entity?: VolunteerParticipationDetails
} & StateRequest
export const initialState: StateVolunteerParticipationDetailsSet = {
readyStatus: "idle",
}
const volunteerParticipationDetailsSetSlice = createSlice({
name: "volunteerParticipationDetailsSet",
initialState,
reducers: {
getRequesting: (_) => ({
readyStatus: "request",
}),
getSuccess: (_, { payload }: PayloadAction<VolunteerParticipationDetails>) => ({
readyStatus: "success",
entity: payload,
}),
getFailure: (_, { payload }: PayloadAction<string>) => ({
readyStatus: "failure",
error: payload,
}),
},
})
export default volunteerParticipationDetailsSetSlice.reducer
export const { getRequesting, getSuccess, getFailure } =
volunteerParticipationDetailsSetSlice.actions
export const fetchVolunteerParticipationDetailsSet = elementFetch(
volunteerParticipationDetailsSet,
getRequesting,
getSuccess,
getFailure,
(error: Error) => toastError(`Erreur lors du chargement des notifications: ${error.message}`)
)
const shouldFetchVolunteerParticipationDetailsSet = (state: AppState, id: number) =>
state.volunteerParticipationDetailsSet?.readyStatus !== "success" ||
(state.volunteerParticipationDetailsSet?.entity &&
state.volunteerParticipationDetailsSet?.entity?.id !== id)
export const fetchVolunteerParticipationDetailsSetIfNeed =
(id = 0, wishes: Partial<VolunteerParticipationDetails> = {}): AppThunk =>
(dispatch, getState) => {
let jwt = ""
if (!id) {
;({ id, jwt } = getState().auth)
}
if (shouldFetchVolunteerParticipationDetailsSet(getState(), id))
return dispatch(fetchVolunteerParticipationDetailsSet(jwt, id, wishes))
return null
}