Skip to content

Commit

Permalink
feat: start v3
Browse files Browse the repository at this point in the history
  • Loading branch information
EmmanuelDemey committed Oct 2, 2024
1 parent 7436a0e commit 326e68b
Show file tree
Hide file tree
Showing 37 changed files with 510 additions and 368 deletions.
Binary file added .DS_Store
Binary file not shown.
10 changes: 5 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
include:
- org: Devfest Lille
- org: DevLille
secret: DEVFEST_FIREBASE_TOKEN
function: "functions:cms4devfestgdg"
target: "default"
Expand All @@ -37,9 +37,9 @@ jobs:
- name: Deploy to Firebase for ${{ matrix.org }}
run: |
npm --prefix public run build -- --configuration ${{ matrix.front }}
npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only hosting
npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only firestore:rules
npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only functions:cms
npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only ${{ matrix.function }}
#npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only hosting
#npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only firestore:rules
#npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only functions:cms
#npx firebase-tools deploy -c ${{matrix.config}} -P ${{ matrix.target }} --only ${{ matrix.function }}
env:
FIREBASE_TOKEN: ${{ secrets[matrix.secret] }}
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ Pour faire fonctionner les Firebase functions, vous devez définir cette configu
"zipcode": "...",
"tel": "...",
"city": "...",
"event": "Devfest Lille",
"event": "DevLille",
"address": "...",
"accountantemail": "...@gdglille.org",
"accountantemail": "...@devlille.fr",
"website": "https://"
},
"mail": {
"to": "...@gdglille.org",
"from": "...@gdglille.org",
"cc": "...@gdglille.org",
"to": "...@devlille.fr",
"from": "...@devlille.fr",
"cc": "...@devlille.fr",
"enabled": "true",
"signature": "L'équipe du Devfest Lille",
"signature": "L'équipe du DevLille",
"fromname": "GDG Lille"
},
"hosting": {
"baseurl": "https://cms4partners.gdglille.org/"
"baseurl": "https://partenaire.devlille.fr/"
},
"mailjet": {
"api": "...",
Expand Down
2 changes: 1 addition & 1 deletion firestore.devfest.rules
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ function isOwner(companyId) {
return request.auth.token.email in resource.data.email;
}
function isAdministrator() {
return request.auth.token.email.matches(".*@gdglille.org")
return request.auth.token.email.matches(".*@devlille.fr")
}
26 changes: 4 additions & 22 deletions functions/src/cms4devfest-gdg.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import axios from "axios";
import { Configuration } from "./model";
import { getConfiguration } from "./v3/infrastructure/getConfiguration";
import { sendToWebhooks } from "./v3/domain/sendToWebhooks";

const firestore = admin.firestore();

export const onSendChangesToWebHooks = functions.firestore
.document("companies-2025/{companyId}")
.onUpdate(async (changes) => {
const configurationFromFirestore = await firestore
.doc("editions/2025")
.get()
.then((configuration) => {
return configuration.data() as Configuration;
});

if (configurationFromFirestore.webhooks?.length! > 0) {
for (let webhook of configurationFromFirestore.webhooks!) {
console.log(
`Sending to webhook ${webhook} information about ${
changes.after.data().name
}`
);
await axios.post(webhook, {
id: changes.after.id,
data: changes.after.data(),
});
}
}
const configuration = await getConfiguration(firestore);
sendToWebhooks(configuration, changes);
});
176 changes: 101 additions & 75 deletions functions/src/cms4devfest.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import { sendEmail, sendEmailToAllContacts } from "./utils/mail";
import { StatusEnum, onDocumentChange } from "./utils/document-change";
import { Timestamp } from "@google-cloud/firestore";
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import relanceConventionSignee from "./emails/template/relanceConventionSignee";
import { StatusEnum, onDocumentChange } from "./utils/document-change";
import { sendEmailToAllContacts } from "./utils/mail";

import WelcomeEmailFactory from "./emails/template/step-1-partnership-demand";
import relancePaiement from "./emails/template/relancePaiement";
import relanceInformationsComplementaires from "./emails/template/relanceInformationsComplementaires";
import { Company, Settings } from "./model";
import relancePaiement from "./emails/template/relancePaiement";
import { Company, Configuration } from "./model";
import {
sendNewPartnerToOrganizationTeam,
sendWelcomeEmail,
} from "./v3/domain/email";
import { getConfiguration } from "./v3/infrastructure/getConfiguration";

admin.initializeApp();
const firestore = admin.firestore();
function sendWelcomeEmail(company: Company, id: string, settings: Settings) {
const emailTemplate = WelcomeEmailFactory(company, id, settings);
return sendEmailToAllContacts(company, emailTemplate, settings);
}

function addCreationDate(id: string) {
return firestore
Expand All @@ -36,97 +36,123 @@ function updatesStatus(id: string, company: any, status: any) {
.catch((err) => console.log(err));
}

export const getAllPublicSponsors = functions.https.onRequest(async (req, resp) => {
const data = await firestore.collection("companies-2025").get();
const partners = data.docs
.map((d) => ({
id: d.id,
...d.data(),
}))
.filter((p: any) => p.status.paid === StatusEnum.DONE && p.public && !!p.siteUrl && !!p.logoUrl);
resp.send(partners);
});
export const getAllPublicSponsors = functions.https.onRequest(
async (req, resp) => {
const data = await firestore.collection("companies-2025").get();
const partners = data.docs
.map((d) => ({
id: d.id,
...d.data(),
}))
.filter(
(p: any) =>
p.status.paid === StatusEnum.DONE &&
p.public &&
!!p.siteUrl &&
!!p.logoUrl
);
resp.send(partners);
}
);

const relance = (
emailFactory: (partner: Record<string, any>, settings: Settings) => any,
emailFactory: (
partner: Record<string, any>,
configuration: Configuration
) => any,
partners: any[],
settings: Settings
configuration: Configuration
) => {
partners.forEach((c: any) => {
const emailTemplate = emailFactory(c, settings);
sendEmailToAllContacts(c, emailTemplate, settings);
const emailTemplate = emailFactory(c, configuration);
sendEmailToAllContacts(c, emailTemplate, configuration);
});
};

export const relancePartnaireConventionASigner = functions.https.onCall(async (req, res) => {
const data = await firestore.collection("companies-2025").get();
const partners = data.docs.map((d) => d.data()).filter((p) => p.status.sign === StatusEnum.PENDING);
relance(relanceConventionSignee, partners, functions.config() as Settings);
});
export const relancePartnaireConventionASigner = functions.https.onCall(
async (req, res) => {
const configuration = await getConfiguration(firestore);
const data = await firestore.collection("companies-2025").get();
const partners = data.docs
.map((d) => d.data())
.filter((p) => p.status.sign === StatusEnum.PENDING);
relance(relanceConventionSignee, partners, configuration);
}
);

export const relancePartnaireFacture = functions.https.onCall(async (req, res) => {
const data = await firestore.collection("companies-2025").get();
const partners = data.docs.map((d) => d.data()).filter((p) => p.status.paid === StatusEnum.PENDING);
relance(relancePaiement, partners, functions.config() as Settings);
});
export const relancePartnaireFacture = functions.https.onCall(
async (req, res) => {
const configuration = await getConfiguration(firestore);
const data = await firestore.collection("companies-2025").get();
const partners = data.docs
.map((d) => d.data())
.filter((p) => p.status.paid === StatusEnum.PENDING);
relance(relancePaiement, partners, configuration);
}
);

export const relanceInformationPourGeneration = functions.https.onCall(async (req, res) => {
const data = await firestore.collection("companies-2025").get();
const partners = data.docs.map((d) => d.data()).filter((p) => p.status.generated === StatusEnum.PENDING);
relance(relanceInformationsComplementaires, partners, functions.config() as Settings);
});
export const relanceInformationPourGeneration = functions.https.onCall(
async (req, res) => {
const configuration = await getConfiguration(firestore);
const data = await firestore.collection("companies-2025").get();
const partners = data.docs
.map((d) => d.data())
.filter((p) => p.status.generated === StatusEnum.PENDING);
relance(relanceInformationsComplementaires, partners, configuration);
}
);

export const newPartner = functions.firestore.document("companies-2025/{companyId}").onCreate(async (snap) => {
const settings = functions.config() as Settings;
const company: Company = snap.data() as Company;
const id = snap.id;
export const newPartner = functions.firestore
.document("companies-2025/{companyId}")
.onCreate(async (snap) => {
const configuration = await getConfiguration(firestore);
const company: Company = snap.data() as Company;
const id = snap.id;

if (!company.name) {
return;
}
await addCreationDate(id);
await sendWelcomeEmail(company, snap.id, settings);
await sendEmail(
settings.mail.to,
"🎉 Nouveau Partenaire " + company.name,
`
La société ${company.name} souhaite devenir partenaire ${company.sponsoring}<br>
`,
settings
);
if (!company.name) {
return;
}
await addCreationDate(id);
await sendWelcomeEmail(company, snap.id, configuration);
await sendNewPartnerToOrganizationTeam(company, configuration);

return updatesStatus(id, company, {
filled: "done",
validated: "pending",
return updatesStatus(id, company, {
filled: "done",
validated: "pending",
});
});
});

export const partnershipUpdated = functions
.runWith({
memory: "1GB",
})
.firestore.document("companies-2025/{companyId}")
.onUpdate((changes) => {
.onUpdate(async (changes) => {
const configuration = await getConfiguration(firestore);
const before = changes.before.data() as Company;
const after = changes.after.data() as Company;
if (!before || !after) {
return;
}
const id = changes.after.id;

return onDocumentChange(firestore, before, after, id, functions.config() as Settings);
return onDocumentChange(firestore, before, after, id, configuration);
});

exports.updateConventionSignedUrlProperty = functions.storage.object().onFinalize(async (object) => {
const name = object.name || "";
return admin
.storage()
.bucket()
.file(name)
.getSignedUrl({ action: "read", expires: "03-17-2025" })
.then(([url]) => {
return firestore.doc("companies-2025/" + name.replace("signed/", "")).update({
conventionSignedUrl: url,
exports.updateConventionSignedUrlProperty = functions.storage
.object()
.onFinalize(async (object) => {
const name = object.name || "";
return admin
.storage()
.bucket()
.file(name)
.getSignedUrl({ action: "read", expires: "03-17-2025" })
.then(([url]) => {
return firestore
.doc("companies-2025/" + name.replace("signed/", ""))
.update({
conventionSignedUrl: url,
});
});
});
});
});
12 changes: 6 additions & 6 deletions functions/src/emails/template/convention-signed.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Settings } from "../../model";
import { Configuration } from "../../model";

export default (id: string, settings: Settings) => {
const adress_cms4devfest = `${settings.hosting.baseurl}/partner/${id}`;
export default (id: string, configuration: Configuration) => {
const adress_cms4devfest = `${configuration.hosting.baseurl}/partner/${id}`;
return {
subject: `${settings.gdg.event} ${settings.convention.edition} : Convention Signée`,
subject: `${configuration.gdg.event} ${configuration.convention.edition} : Convention Signée`,
body: `
Bonjour
<br><br>
Expand All @@ -13,11 +13,11 @@ export default (id: string, settings: Settings) => {
<br><br>
Une fois cette étape terminée, nous pourrons commencer la communication de notre partenariat sur les réseaux sociaux.
<br><br>
Nous restons à votre disposition pour tout complément via l'adresse ${settings.mail.from}.
Nous restons à votre disposition pour tout complément via l'adresse ${configuration.mail.from}.
<br><br>
Cordialement
<br><br>
${settings.mail.signature} ${settings.convention.edition}
${configuration.mail.signature} ${configuration.convention.edition}
`,
};
};
12 changes: 6 additions & 6 deletions functions/src/emails/template/relanceConventionSignee.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Settings } from "../../model";
import { Configuration } from "../../model";

export default (company: Record<string, any>, settings: Settings) => {
export default (company: Record<string, any>, configuration: Configuration) => {
return {
subject: `Partenariat ${settings.gdg.event} ${settings.convention.edition}: Relance Convention à Signer`,
subject: `Partenariat ${configuration.gdg.event} ${configuration.convention.edition}: Relance Convention à Signer`,
body: `
Bonjour
<br><br>
Nous vous envoyons cet email afin de vous annoncer que nous sommes toujours dans l'attente de votre signature pour la convention de partenariat pour ${settings.gdg.event}.
Nous vous envoyons cet email afin de vous annoncer que nous sommes toujours dans l'attente de votre signature pour la convention de partenariat pour ${configuration.gdg.event}.
<br><br>
Une fois signée, vous pouvez nous la retourner par email, ou la sauvegarde sur votre espace dédié.
<br><br>
Nous restons à votre disposition pour tout complément via l'adresse email ${settings.mail.from}.
Nous restons à votre disposition pour tout complément via l'adresse email ${configuration.mail.from}.
<br><br>
Cordialement
<br><br>
${settings.mail.signature} ${settings.convention.edition}
${configuration.mail.signature} ${configuration.convention.edition}
`,
};
};
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Settings } from "../../model";
import { Configuration } from "../../model";

export default (partner: Record<string, any>, settings: Settings) => {
export default (partner: Record<string, any>, configuration: Configuration) => {
return {
subject: `Partenariat ${settings.gdg.event} ${settings.convention.edition}: Relance Informations Complémentaires`,
subject: `Partenariat ${configuration.gdg.event} ${configuration.convention.edition}: Relance Informations Complémentaires`,
body: `
Bonjour
<br><br>
Nous vous envoyons cet email afin de vous annoncer que nous sommes toujours dans l'attente d'informations complémentaires afin d'établir la convention et la facture pour ${settings.gdg.event}.
Nous vous envoyons cet email afin de vous annoncer que nous sommes toujours dans l'attente d'informations complémentaires afin d'établir la convention et la facture pour ${configuration.gdg.event}.
<br><br>
Vous pouvez renseigner ces informations sur votre espace dédié.
<br><br>
Nous restons à votre disposition pour tout complément via l'adresse email ${settings.mail.from}.
Nous restons à votre disposition pour tout complément via l'adresse email ${configuration.mail.from}.
<br><br>
Cordialement
<br><br>
${settings.mail.signature} ${settings.convention.edition}
${configuration.mail.signature} ${configuration.convention.edition}
`,
};
};
Loading

0 comments on commit 326e68b

Please sign in to comment.