all repos — caroster @ 250953e47e050512ff7bc85b405e1073128d7f3f

[Octree] Group carpool to your event https://caroster.io

🐛 Fixes after PO review #324 #466 #513
Tim Izzo tim@octree.ch
Tue, 12 Mar 2024 08:20:23 +0000
commit

250953e47e050512ff7bc85b405e1073128d7f3f

parent

ef6b0a286bfe6a572afc38159283e8d3e43fbe06

M backend/src/api/email/locales/en.jsonbackend/src/api/email/locales/en.json

@@ -4,9 +4,17 @@ "header": "<img src='https://app.caroster.io/uploads/Caroster_logo1_cddd3057fc.png?updated_at=2022-09-12T08:11:11.735Z' width='100%' alt='Caroster'/>",

"footer": "---\n💝 You also think Caroster is awesome? Keep it free and support us with a donation!\n\n👉 [Open collective](https://opencollective.com/caroster)\n\n<center><a href='https://caroster.io'>https://caroster.io</a></center>" }, "notifications": { + "ConfirmEmail": { + "title": "Please confirm your email address", + "content": "## Welcome on Caroster !\nPlease confirm your account by clicking on this link:\n\n[<%= confirmationLink %>](<%= confirmationLink %>)" + }, "NewTrip": { "title": "<%= event.name %> - A new trip is available", "content": "## New trip is available for \"<%= event.name %>\"\n\n**Car: <%= travel.vehicleName %>**\nCount of seats: <%= travel.seats %>\nDeparture location: <%= travel.meeting %>\nInformation: <%= travel.details %>.\n\n[Book my seat](<%= host %>/e/<%= event.uuid %>).\n\nYou are receiving this email because you are on the waiting list to find a carpool spot in this event." + }, + "NewTripAlert": { + "title": "<%= event.name %> - A new trip is available", + "content": "## New trip is available for \"<%= event.name %>\"\n\n**Car: <%= travel.vehicleName %>**\nCount of seats: <%= travel.seats %>\nDeparture location: <%= travel.meeting %>\nInformation: <%= travel.details %>.\n\n[Book my seat](<%= host %>/e/<%= event.uuid %>).\n\nYou are receiving this email because you've enabled alerts in this event." }, "DeletedTrip": { "title": "<%= event.name %> - Trip removed",
M backend/src/api/email/locales/fr.jsonbackend/src/api/email/locales/fr.json

@@ -4,9 +4,17 @@ "header": "<img src='https://app.caroster.io/uploads/Caroster_logo1_cddd3057fc.png?updated_at=2022-09-12T08:11:11.735Z' width='100%' alt='Caroster'/>",

"footer": "---\n💝 Vous pensez aussi que Caroster est gĂ©nial ? Aidez-nous Ă  le maintenir libre et gratuit en faisant une donation !\n\n👉 [Open collective](https://opencollective.com/caroster)\n\n<center><a href='https://caroster.io'>https://caroster.io</a></center>" }, "notifications": { + "ConfirmEmail": { + "title": "Merci de confirmer votre adresse email", + "content": "## Bienvenue sur Caroster !\nMerci de confirmer votre compte en cliquant sur le lien ci-dessous:\n\n[<%= confirmationLink %>](<%= confirmationLink %>)" + }, "NewTrip": { "title": "<%= event.name %> - Nouveau trajet disponible", - "content": "## Nouveau trajet pour \"<%= event.name %>\"\n\n**Voiture: <%= travel.vehicleName %>**\nNombre de places: <%= travel.seats %>\nLieu de dĂ©part: <%= travel.meeting %>\nInformations: <%= travel.details %>.\n\n[RĂ©server ma place](<%= host %>/e/<%= event.uuid %>).\n\nVous recevez cet e-mail, car vous ĂȘtes inscrit en liste d'attente pour trouver une place de covoiturage dans cet Ă©vĂ©nement." + "content": "## Nouveau trajet pour \"<%= event.name %>\"\n\n**Voiture: <%= travel.vehicleName %>**\nNombre de places: <%= travel.seats %>\nLieu de dĂ©part: <%= travel.meeting %>\nInformations: <%= travel.details %>.\n\n[RĂ©server ma place](<%= host %>/e/<%= event.uuid %>).\n\nVous recevez cet e-mail car vous ĂȘtes inscrit en liste d'attente pour trouver une place de covoiturage dans cet Ă©vĂ©nement." + }, + "NewTripAlert": { + "title": "<%= event.name %> - Nouveau trajet disponible", + "content": "## Nouveau trajet pour \"<%= event.name %>\"\n\n**Voiture: <%= travel.vehicleName %>**\nNombre de places: <%= travel.seats %>\nLieu de dĂ©part: <%= travel.meeting %>\nInformations: <%= travel.details %>.\n\n[RĂ©server ma place](<%= host %>/e/<%= event.uuid %>).\n\nVous recevez cet e-mail car vous avez configurĂ© une alerte de trajet Ă  proximitĂ© pour cet Ă©vĂ©nement." }, "DeletedTrip": { "title": "<%= event.name %> - Trajet supprimĂ©",
M backend/src/api/email/services/email.tsbackend/src/api/email/services/email.ts

@@ -84,7 +84,7 @@ const mdFooter = locales?.[lang]?.template.footer;

const htmlContent = await marked.parse(mdContent, { breaks: true }); const htmlHeader = await marked.parse(mdHeader, { breaks: true }); const htmlFooter = await marked.parse(mdFooter, { breaks: true }); - const html = `${getHTMLMeta()}<main>${htmlHeader}${htmlContent}${htmlFooter}</main>`; + const html = `${getHTMLMeta()}<header>${htmlHeader}</header><main>${htmlContent}${htmlFooter}</main>`; return { subject,
M backend/src/api/email/utils/layout.tsbackend/src/api/email/utils/layout.ts

@@ -3,6 +3,13 @@ <style type="text/css">

body { font-family: sans; } + header { + text-align: center; + } + header img { + width: 20rem; + max-width: 100%; + } main { max-width: 40rem; margin: 0 auto;
M backend/src/api/notification/content-types/notification/schema.jsonbackend/src/api/notification/content-types/notification/schema.json

@@ -17,6 +17,7 @@ "type": "enumeration",

"enum": [ "NewPassengerInYourTrip", "NewTrip", + "NewTripAlert", "DeletedTrip", "DeletedYourTrip", "DeletedFromTrip",
M backend/src/api/trip-alert/services/trip-alert.tsbackend/src/api/trip-alert/services/trip-alert.ts

@@ -49,7 +49,7 @@ `Create trip alert notification for user ${tripAlert.user.id}`

); strapi.entityService.create("api::notification.notification", { data: { - type: "NewTrip", + type: "NewTripAlert", event: eventId, user: tripAlert.user.id, payload: { travel },
A backend/src/extensions/users-permissions/services/sendConfirmationEmail.ts

@@ -0,0 +1,32 @@

+import crypto from "crypto"; +import urlJoin from "url-join"; +import { getAbsoluteServerUrl, sanitize } from "@strapi/utils"; + +export default async (user) => { + const userSchema = strapi.getModel("plugin::users-permissions.user"); + + const confirmationToken = crypto.randomBytes(20).toString("hex"); + strapi.entityService.update("plugin::users-permissions.user", user.id, { + data: { confirmationToken }, + populate: ["role"], + }); + + const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput( + userSchema, + user + ); + const apiPrefix = strapi.config.get("api.rest.prefix"); + const url = urlJoin( + getAbsoluteServerUrl(strapi.config), + apiPrefix, + "/auth/email-confirmation" + ); + const confirmationLink = `${url}?confirmation=${confirmationToken}`; + await strapi + .service("api::email.email") + .sendEmailNotif(user.email, "ConfirmEmail", user.lang, { + confirmationToken, + confirmationLink, + user: sanitizedUserInfo, + }); +};
A backend/src/extensions/users-permissions/strapi-server.ts

@@ -0,0 +1,13 @@

+import sendConfirmationEmail from "./services/sendConfirmationEmail"; + +export default (plugin) => { + const userServices = plugin.services.user; + plugin.services.user = (params) => { + const services = userServices(params); + return { + ...services, + sendConfirmationEmail, + }; + }; + return plugin; +};
M backend/types/generated/contentTypes.d.tsbackend/types/generated/contentTypes.d.ts

@@ -964,6 +964,7 @@ type: Attribute.Enumeration<

[ 'NewPassengerInYourTrip', 'NewTrip', + 'NewTripAlert', 'DeletedTrip', 'DeletedYourTrip', 'DeletedFromTrip',
M frontend/containers/DashboardEmpty/index.tsxfrontend/containers/DashboardEmpty/index.tsx

@@ -1,5 +1,4 @@

import {useRouter} from 'next/router'; -import { styled } from '@mui/material/styles'; import Container from '@mui/material/Container'; import Card from '@mui/material/Card'; import CardActions from '@mui/material/CardActions';

@@ -8,29 +7,12 @@ import Typography from '@mui/material/Typography';

import Button from '@mui/material/Button'; import {useTranslation} from 'react-i18next'; -const PREFIX = 'DashboardEmpty'; - -const classes = { - container: `${PREFIX}-container` -}; - -const StyledContainer = styled(Container)(( - { - theme - } -) => ({ - [`&.${classes.container}`]: { - paddingTop: theme.spacing(8), - } -})); - const DashboardEmpty = () => { const {t} = useTranslation(); const router = useRouter(); - return ( - <StyledContainer maxWidth="sm" className={classes.container}> + <Container maxWidth="sm" sx={{pt: 8}}> <Card> <CardContent> <Typography gutterBottom variant="h5" component="h1">

@@ -46,7 +28,7 @@ />

</CardContent> <CardActions> <Button - onClick={() => router.push('/')} + onClick={() => router.push('/new')} variant="contained" color="primary" >

@@ -54,7 +36,7 @@ {t('dashboard.noEvent.create_event')}

</Button> </CardActions> </Card> - </StyledContainer> + </Container> ); };
M frontend/locales/en.jsonfrontend/locales/en.json

@@ -131,6 +131,7 @@ "notifications.markAllRead": "Mark all in read",

"notifications.content": "No notification", "notification.type.NewPassengerInYourTrip.content": "A passenger has been added to your trip.", "notification.type.NewTrip.content": "A new trip close to you is available.", + "notification.type.NewTripAlert.content": "A new trip close to you is available.", "notification.type.DeletedTrip.content": "A trip has been removed.", "notification.type.DeletedYourTrip.content": "Your trip has been removed by an event administrator", "notification.type.AddedAsAdmin.content": "You have been promoted as administrator to the event.",

@@ -262,7 +263,7 @@ "travel.passengers.add_me": "Add myself",

"travel.passengers.registered": "Assigned", "travel.passengers.add_someone": "Add someone", "travel.passengers.remove": "Remove", - "travel.passengers.removed": "Passenger removed from the car" , + "travel.passengers.removed": "Passenger removed from the car", "travel.passengers.add_to_car": "Add to car", "travel.passengers.add_to_travel": "Add passenger", "travel.passengers.add_to_waitingList": "Add to waiting list",
M frontend/locales/fr.jsonfrontend/locales/fr.json

@@ -131,6 +131,7 @@ "notifications.markAllRead": "Tout marquer en lu",

"notifications.content": "Aucune notification", "notification.type.NewPassengerInYourTrip.content": "Un passager a été ajouté à votre trajet.", "notification.type.NewTrip.content": "Un nouveau trajet proche de chez vous est disponible.", + "notification.type.NewTripAlert.content": "Un nouveau trajet proche de chez vous est disponible.", "notification.type.DeletedTrip.content": "Un trajet a été supprimée.", "notification.type.DeletedYourTrip.content": "Votre trajet a été supprimé par un administrateur de l'événement.", "notification.type.AddedAsAdmin.content": "Vous avez été promu administrateur.",
M frontend/locales/nl.jsonfrontend/locales/nl.json

@@ -119,6 +119,7 @@ "notifications.markAllRead": "",

"notifications.content": "", "notification.type.NewPassengerInYourTrip.content": "", "notification.type.NewTrip.content": "", + "notification.type.NewTripAlert.content": "", "notification.type.DeletedTrip.content": "", "notification.type.DeletedYourTrip.content": "", "notification.type.DeletedFromTrip.content": "",
M frontend/locales/pl.jsonfrontend/locales/pl.json

@@ -122,6 +122,7 @@ "notifications.markAllRead": "",

"notifications.content": "", "notification.type.NewPassengerInYourTrip.content": "", "notification.type.NewTrip.content": "", + "notification.type.NewTripAlert.content": "", "notification.type.DeletedTrip.content": "", "notification.type.DeletedYourTrip.content": "", "notification.type.DeletedFromTrip.content": "",
M frontend/locales/sv.jsonfrontend/locales/sv.json

@@ -119,6 +119,7 @@ "notifications.markAllRead": "",

"notifications.content": "", "notification.type.NewPassengerInYourTrip.content": "", "notification.type.NewTrip.content": "", + "notification.type.NewTripAlert.content": "", "notification.type.DeletedTrip.content": "", "notification.type.DeletedYourTrip.content": "", "notification.type.DeletedFromTrip.content": "",