Skip to content

Commit

Permalink
Merge branch 'main' into staging
Browse files Browse the repository at this point in the history
  • Loading branch information
theolemague committed Dec 3, 2024
2 parents c8c6b3b + 0d0ea96 commit d9a1a8e
Show file tree
Hide file tree
Showing 30 changed files with 225 additions and 121 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy-pdf-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Connect and restart process
uses: appleboy/ssh-action@master
with:
host: process.api-engagement.beta.gouv.fr
host: pdf.api-engagement.beta.gouv.fr
username: "root"
key: ${{ secrets.SCW_SSH_KEY }}
script: |
Expand Down
2 changes: 1 addition & 1 deletion api/src/controllers/rna.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ router.get("/", passport.authenticate("user", { session: false }), async (req: U
const response = await esClient.search({ index: RNA_INDEX, body: esBody });
const total = response.body.hits.total.value;
const data = {
hits: response.body.hits.hits.map((h: { _id: string; _source: Mission }) => ({ _id: h._id, ...h._source })),
hits: response.body.hits.hits.map((h: { _id: string; _source: Mission }) => ({ ...h._source, _id: h._id })),
aggs: {
departments: response.body.aggregations.departements.buckets,
cities: response.body.aggregations.cities.buckets,
Expand Down
15 changes: 13 additions & 2 deletions api/src/controllers/stats-admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,19 @@ router.get("/publishers-views", passport.authenticate("user", { session: false }

const total = {
publishers: publishers.length,
announcers: publishers.filter((e) => e.role_promoteur).length,
broadcasters: publishers.filter((e) => e.role_annonceur_api || e.role_annonceur_campagne || e.role_annonceur_widget).length,
announcers: publishers.filter((e) => {
if (!e.role_promoteur) return false;
if (query.data.type === "volontariat") return e.name === "Service Civique";
if (query.data.type === "benevolat") return e.name !== "Service Civique";
return true;
}).length,
broadcasters: publishers.filter((e) => {
const isBroadcaster = e.role_annonceur_api || e.role_annonceur_campagne || e.role_annonceur_widget;
if (!isBroadcaster) return false;
if (query.data.type === "volontariat") return e.publishers?.some((p) => p.publisherName === "Service Civique");
if (query.data.type === "benevolat") return e.publishers?.some((p) => p.publisherName !== "Service Civique");
return true;
}).length,
clicks: response.body.aggregations.totalClick.doc_count,
applys: response.body.aggregations.totalApply.doc_count,
};
Expand Down
13 changes: 9 additions & 4 deletions api/src/controllers/stats-global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@ router.get("/broadcast-preview", passport.authenticate("user", { session: false
},
},
},
totalMission: {
cardinality: {
field: "missionId.keyword",
totalMissionClick: {
filter: { term: { type: "click" } },
aggs: {
missions: {
cardinality: {
field: "missionId.keyword",
},
},
},
},
},
Expand All @@ -73,7 +78,7 @@ router.get("/broadcast-preview", passport.authenticate("user", { session: false
totalPrint: response.body.aggregations.totalPrint.doc_count,
totalAccount: response.body.aggregations.totalAccount.doc_count,
totalMissionApply: response.body.aggregations.totalMissionApply.missions.value,
totalMission: response.body.aggregations.totalMission.value,
totalMissionClick: response.body.aggregations.totalMissionClick.missions.value,
};

return res.status(200).send({ ok: true, data });
Expand Down
3 changes: 2 additions & 1 deletion app/src/components/SelectCity.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const SelectCity = ({ onChange }) => {
useEffect(() => {
const fetchOptions = async () => {
try {
if (search.length > 0 && search.length < 3) {
if (search.length === 0) {
onChange(null);
setOptions([]);
return;
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/components/SelectOrganization.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const SelectOrganization = ({ onChange }) => {
useEffect(() => {
const fetchOptions = async () => {
try {
if (search.length > 0 && search.length < 3) {
if (search.length === 0) {
onChange(null);
setOptions([]);
return;
}
Expand Down
69 changes: 56 additions & 13 deletions app/src/scenes/admin-stats/Apercu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { captureError } from "../../services/error";

const Apercu = () => {
const [searchParams, setSearchParams] = useSearchParams();
const [stickyVisible, setStickyVisible] = useState(false);
const [filterSection, setFilterSection] = useState(null);

const [filters, setFilters] = useState({
from: searchParams.has("from") ? new Date(searchParams.get("from")) : new Date(new Date().getFullYear() - 1, new Date().getMonth(), new Date().getDate()),
to: searchParams.has("to") ? new Date(searchParams.get("to")) : new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() + 1, 0, 0, 0, -1),
Expand All @@ -26,24 +29,64 @@ const Apercu = () => {
setSearchParams(query);
}, [filters, location.pathname]);

useEffect(() => {
if (!filterSection) return;

const observer = new IntersectionObserver(
([entry]) => {
setStickyVisible(!entry.isIntersecting);
},
{ threshold: 0 },
);

observer.observe(filterSection);

return () => {
if (filterSection) {
observer.unobserve(filterSection);
}
};
}, [filterSection]);

return (
<div className="space-y-12 p-12">
<Helmet>
<title>Aperçu - Statistiques - Administration - API Engagement</title>
</Helmet>
<div className="flex items-end gap-4">
<div className="space-y-2">
<label className="text-sm text-gray-dark uppercase font-semibold">Période</label>
<DateRangePicker value={filters} onChange={(value) => setFilters({ ...filters, from: value.from, to: value.to })} />

{stickyVisible && (
<div className="fixed top-0 left-0 w-full bg-white shadow-lg z-50 px-48 items-center justify-center py-4">
<div className="flex items-end gap-4">
<div className="space-y-2 flex-1">
<DateRangePicker value={filters} onChange={(value) => setFilters({ ...filters, from: value.from, to: value.to })} />
</div>
<label htmlFor="mission-type-sticky" className="sr-only">
Type de mission
</label>
<select id="mission-type-sticky" className="select w-80" value={filters.type} onChange={(e) => setFilters({ ...filters, type: e.target.value })}>
<option value="">Tous les types de missions</option>
<option value="benevolat">Toutes les missions de bénévolat</option>
<option value="volontariat">Toutes les missions de volontariat</option>
</select>
</div>
</div>
)}

<div ref={(node) => setFilterSection(node)}>
<div className="flex items-end gap-4">
<div className="space-y-2 flex-1">
<label className="text-sm text-gray-dark uppercase font-semibold">Période</label>
<DateRangePicker value={filters} onChange={(value) => setFilters({ ...filters, from: value.from, to: value.to })} />
</div>
<label htmlFor="mission-type" className="sr-only">
Type de mission
</label>
<select id="mission-type" className="select w-80" value={filters.type} onChange={(e) => setFilters({ ...filters, type: e.target.value })}>
<option value="">Tous les types de missions</option>
<option value="benevolat">Toutes les missions de bénévolat</option>
<option value="volontariat">Toutes les missions de volontariat</option>
</select>
</div>
<label htmlFor="mission-type" className="sr-only">
Type de mission
</label>
<select id="mission-type" className="select w-80" value={filters.type} onChange={(e) => setFilters({ ...filters, type: e.target.value })}>
<option value="">Tous les types de missions</option>
<option value="benevolat">Toutes les missions de bénévolat</option>
<option value="volontariat">Toutes les missions de volontariat</option>
</select>
</div>
<div className="border-b border-b-gray-border" />

Expand Down Expand Up @@ -447,7 +490,7 @@ const Patners = ({ filters }) => {
);
const announcePie = buildPie(
data.filter((d) => d.role_promoteur),
"applyFrom",
"applyTo",
);

return (
Expand Down
6 changes: 3 additions & 3 deletions app/src/scenes/performance/GlobalBroadcast.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const COLORS = ["rgba(250,117,117,255)", "rgba(252,205,109,255)", "rgba(251,146,

const GlobalDiffuseur = ({ filters, onFiltersChange }) => {
const { publisher } = useStore();
const [data, setData] = useState({ totalMission: 0, totalMissionApply: 0, totalPrint: 0, totalClick: 0, totalAccount: 0, totalApply: 0 });
const [data, setData] = useState({ totalMissionClick: 0, totalMissionApply: 0, totalPrint: 0, totalClick: 0, totalAccount: 0, totalApply: 0 });
const [loading, setLoading] = useState(true);
const [trackingWarning, setTrackingWarning] = useState(false);

Expand Down Expand Up @@ -111,8 +111,8 @@ const GlobalDiffuseur = ({ filters, onFiltersChange }) => {
<div className="grid gap-4 mt-4">
<div className="grid grid-cols-2 gap-4">
<div className="border p-6">
<p className="font-bold text-[28px]">{data.totalMission.toLocaleString("fr")}</p>
<p className="text-base">missions diffusées</p>
<p className="font-bold text-[28px]">{data.totalMissionClick.toLocaleString("fr")}</p>
<p className="text-base">missions ayant généré au moins une redirection</p>
</div>
<div className="border p-6">
<p className="font-bold text-[28px]">{data.totalMissionApply.toLocaleString("fr")}</p>
Expand Down
8 changes: 8 additions & 0 deletions pdf-next/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"arrowParens": "always",
"printWidth": 180,
"semi": true,
"doubleQuote": true,
"tabWidth": 2,
"jsxBracketSameLine": true
}
2 changes: 1 addition & 1 deletion pdf-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dev": "next dev -p 3000",
"build": "next build",
"start-dev": "next start -p 3000",
"start": "pm2 start npx --name pdf -- next -p 3000",
"start": "pm2 start npx --name pdf -- next -p 8080",
"stop": "pm2 stop pdf"
},
"dependencies": {
Expand Down
9 changes: 8 additions & 1 deletion pdf-next/src/app/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@ const Page = async ({ params, searchParams }: { params: { id: string }; searchPa
const id = params.id;
const year = searchParams?.year ? Number(searchParams?.year) : new Date().getFullYear();
const month = searchParams?.month ? Number(searchParams?.month) : new Date().getMonth();
const apiKey = searchParams?.apiKey as string;

const res = await api.get<{ data: StatsReport; publisher: Publisher }>(`/stats-report?year=${year}&month=${month}&publisherId=${id}`);
if (!apiKey) return null;

const res = await api.get<{ data: StatsReport; publisher: Publisher }>(`/stats-report?year=${year}&month=${month}&publisherId=${id}`, {
headers: {
"x-api-key": apiKey,
},
});
if (!res.data) return null;
return (
<>
Expand Down
8 changes: 4 additions & 4 deletions pdf-next/src/services/api.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { API_KEY, API_URL } from "./config";
import { API_URL } from "./config";

class APIHandler {
name: string;
baseUrl: string;
headers: { "Content-Type": string; "x-api-key": string };
headers: { "Content-Type": string };

constructor() {
this.name = "APIHandler";
this.baseUrl = API_URL;
this.headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY || "",
};
}
async get<T>(endpoint: string) {
async get<T>(endpoint: string, options?: { headers?: { "x-api-key": string } }) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
cache: "no-store",
method: "GET",
headers: {
...this.headers,
...options?.headers,
},
credentials: "include",
});
Expand Down
5 changes: 0 additions & 5 deletions pdf-next/src/services/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
export const API_URL = process.env.API_URL || "http://localhost:4000";
export const API_KEY = process.env.API_KEY;
export const ES_ENDPOINT = process.env.ES_ENDPOINT || "https://uMauldOGSf1wYkNlSjf3:G8yQCPMp8M6el9dBEIsu@bddrzfdyvueuszf4d5ex-elasticsearch.services.clever-cloud.com";
export const DB_ENDPOINT =
process.env.DB_ENDPOINT || "mongodb://ujs56xwhhbadijpyvlbm:sLVzx0f3us4dqoOIgwI@bammvxrlz7r7fbaulp2m-mongodb.services.clever-cloud.com:2668/bammvxrlz7r7fbaulp2m";
export const STATS_INDEX = "stats";
1 change: 1 addition & 0 deletions process/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ process.env.TZ = "Europe/Paris";
export const PORT = process.env.PORT || 4001;
export const API_URL = process.env.API_URL || "http://localhost:4000";
export const API_KEY = process.env.API_KEY;
export const PDF_URL = process.env.PDF_URL || "http://localhost:3000";

export const ENVIRONMENT = process.env.ENV || "development";
export const ES_ENDPOINT = process.env.ES_ENDPOINT;
Expand Down
4 changes: 2 additions & 2 deletions process/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ const leboncoinJob = new CronJob(

// Every first Tuesday of the month at 10:00 AM
const reportJob = new CronJob(
"0 10 2 * *",
"10 16 * * 2",
async () => {
// if not the first Tuesday of the month, return
const date = new Date();
Expand Down Expand Up @@ -392,4 +392,4 @@ app.get("/tasks", async (req, res) => {
}
});

app.listen(PORT, () => console.log("Listening on port ", PORT, "at", new Date().toISOString()));
app.listen(PORT, () => console.log(`Listening on port ${PORT} at ${new Date().toISOString()}`));
1 change: 1 addition & 0 deletions process/src/jobs/metabase/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ const handler = async () => {
}

console.log(`[Accounts] Ended at ${new Date().toISOString()} in ${(Date.now() - start.getTime()) / 1000}s.`);
return { created, updated };
} catch (error) {
captureException(error, "[Accounts] Error while syncing docs.");
}
Expand Down
13 changes: 9 additions & 4 deletions process/src/jobs/metabase/apply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const buildData = async (
widget_id: sourceId && doc.source === "widget" ? sourceId : null,
to_partner_id: partnerToId,
from_partner_id: partnerFromId,
status: doc.status,
status: doc.status || null,
} as Apply;

return obj;
Expand Down Expand Up @@ -154,8 +154,13 @@ const handler = async () => {
}
const obj = await buildData({ ...hit._source, _id: hit._id }, partners, missions, campaigns, widgets, clickId);
if (!obj) continue;
if (stored[hit._id.toString()] && stored[hit._id.toString()].status !== obj.status && stored[hit._id.toString()].click_id !== obj.click_id) dataToUpdate.push(obj);
else if (!stored[hit._id.toString()]) dataToCreate.push(obj);

if (stored[hit._id.toString()] && (stored[hit._id.toString()].status !== obj.status || stored[hit._id.toString()].click_id !== obj.click_id)) {
console.log("UPDATE");
console.log("status", stored[hit._id.toString()].status !== obj.status, stored[hit._id.toString()].status, obj.status);
console.log("click_id", stored[hit._id.toString()].click_id !== obj.click_id, stored[hit._id.toString()].click_id, obj.click_id);
dataToUpdate.push(obj);
} else if (!stored[hit._id.toString()]) dataToCreate.push(obj);
}

console.log(`[Applies] ${dataToCreate.length} docs to create, ${dataToUpdate.length} docs to update.`);
Expand All @@ -180,8 +185,8 @@ const handler = async () => {
updated += dataToUpdate.length;
console.log(`[Applies] Updated ${dataToUpdate.length} docs, ${updated} updated so far.`);
}

console.log(`[Applies] Ended at ${new Date().toISOString()} in ${(Date.now() - start.getTime()) / 1000}s.`);
return { created, updated };
} catch (error) {
captureException(error, "[Applies] Error while syncing docs.");
}
Expand Down
3 changes: 2 additions & 1 deletion process/src/jobs/metabase/campaign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const handler = async () => {

const stored = {} as { [key: string]: { old_id: string; updated_at: Date } };
await prisma.campaign.findMany({ select: { old_id: true, updated_at: true } }).then((data) => data.forEach((d) => (stored[d.old_id] = d)));
console.log(`[Campaigns] Found ${stored.length} docs in database.`);
console.log(`[Campaigns] Found ${Object.keys(stored).length} docs in database.`);
const partners = {} as { [key: string]: string };
await prisma.partner.findMany({ select: { id: true, old_id: true } }).then((data) => data.forEach((d) => (partners[d.old_id] = d.id)));

Expand Down Expand Up @@ -77,6 +77,7 @@ const handler = async () => {
}

console.log(`[Campaigns] Ended at ${new Date().toISOString()} in ${(Date.now() - start.getTime()) / 1000}s.`);
return { created: dataToCreate.length, updated: dataToUpdate.length };
} catch (error) {
captureException(error, "[Campaigns] Error while syncing docs.");
}
Expand Down
1 change: 1 addition & 0 deletions process/src/jobs/metabase/click.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ const handler = async () => {
}

console.log(`[Clicks] Ended at ${new Date().toISOString()} in ${(Date.now() - start.getTime()) / 1000}s.`);
return { created };
} catch (error) {
captureException(error, "[Clicks] Error while syncing docs.");
}
Expand Down
1 change: 1 addition & 0 deletions process/src/jobs/metabase/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const handler = async () => {
}

console.log(`[Imports] Ended at ${new Date().toISOString()} in ${(Date.now() - start.getTime()) / 1000}s.`);
return { created };
} catch (error) {
captureException(error, "[Imports] Error while syncing docs.");
}
Expand Down
Loading

0 comments on commit d9a1a8e

Please sign in to comment.