diff --git a/api/src/controllers/publisher.ts b/api/src/controllers/publisher.ts index 9b88141..781f8be 100644 --- a/api/src/controllers/publisher.ts +++ b/api/src/controllers/publisher.ts @@ -44,12 +44,7 @@ router.get("/", passport.authenticate("user", { session: false }), async (req: U } } else if (user.role !== "admin") where._id = { $in: user.publishers }; - let data = await PublisherModel.find(where).lean(); - - if (query.partnersOf) { - // remove API Enagagement from the list of partners - data = data.filter((e) => e._id.toString() !== "63da29db7d356a87a4e35d4a"); - } + const data = await PublisherModel.find(where).lean(); return res.status(200).send({ ok: true, data }); } catch (error) { @@ -77,12 +72,12 @@ router.post("/search", passport.authenticate("user", { session: false }), async if (body.data.ids) where._id = { $in: body.data.ids }; if (body.data.partnersOf) { - if (req.user.role !== "admin" && !req.user.publishers.find((e: string) => e === body.data.partnersOf)) - return res.status(403).send({ ok: false, code: FORBIDDEN, message: `Not allowed` }); - else where["publishers.publisher"] = body.data.partnersOf; + if (req.user.role === "admin" || (req.user.role !== "admin" && req.user.publishers.some((e: string) => e === body.data.partnersOf))) + where["publishers.publisher"] = body.data.partnersOf; + else return res.status(403).send({ ok: false, code: FORBIDDEN, message: `Not allowed` }); } - if ((!where._id || !where["publishers.publisher"]) && req.user.role !== "admin") where._id = { $in: req.user.publishers }; + if (!where._id && !where["publishers.publisher"] && req.user.role !== "admin") where._id = { $in: req.user.publishers }; const data = await PublisherModel.find(where); const total = await PublisherModel.countDocuments(where); diff --git a/api/src/controllers/redirect.ts b/api/src/controllers/redirect.ts index 08ca19c..722bc20 100644 --- a/api/src/controllers/redirect.ts +++ b/api/src/controllers/redirect.ts @@ -1,11 +1,9 @@ import cors from "cors"; import { Request, Response, Router } from "express"; -import { isbot } from "isbot"; -import hash from "object-hash"; import zod from "zod"; import { HydratedDocument } from "mongoose"; -import { ENV, JVA_URL, SC_ID, STATS_INDEX } from "../config"; +import { JVA_URL, SC_ID, STATS_INDEX } from "../config"; import esClient from "../db/elastic"; import { INVALID_PARAMS, INVALID_QUERY, NOT_FOUND, SERVER_ERROR, captureException, captureMessage } from "../error"; import CampaignModel from "../models/campaign"; @@ -13,20 +11,10 @@ import MissionModel from "../models/mission"; import PublisherModel from "../models/publisher"; import WidgetModel from "../models/widget"; import { Mission, Stats } from "../types"; -import { slugify } from "../utils"; +import { identify, slugify } from "../utils"; const router = Router(); -const identify = (req: Request) => { - const userAgent = req.get("user-agent"); - if (isbot(userAgent) && ENV !== "development") return; - - const ip = req.ip; - const referer = req.header("referer") || "not_defined"; - const user = hash([ip, referer, userAgent]); - return { user, referer: referer.includes("?") ? referer.split("?")[0] : referer }; -}; - router.get("/apply", cors({ origin: "*" }), async (req: Request, res: Response) => { try { const identity = identify(req); @@ -75,8 +63,9 @@ router.get("/apply", cors({ origin: "*" }), async (req: Request, res: Response) if (!mission) captureMessage(`[Apply] Mission not found`, `mission ${query.data.mission}`); } - const obj1 = { + const obj = { referer: identity.referer, + userAgent: identity.userAgent, user: identity.user, host: req.get("host") || "", origin: req.get("origin") || "", @@ -86,40 +75,40 @@ router.get("/apply", cors({ origin: "*" }), async (req: Request, res: Response) } as Stats; if (mission) { - obj1.missionId = mission._id.toString(); - obj1.missionClientId = mission.clientId; - obj1.missionDomain = mission.domain; - obj1.missionTitle = mission.title; - obj1.missionPostalCode = mission.postalCode; - obj1.missionDepartmentName = mission.departmentName; - obj1.missionOrganizationName = mission.organizationName; - obj1.missionOrganizationId = mission.organizationId; - obj1.toPublisherId = mission.publisherId; - obj1.toPublisherName = mission.publisherName; + obj.missionId = mission._id.toString(); + obj.missionClientId = mission.clientId; + obj.missionDomain = mission.domain; + obj.missionTitle = mission.title; + obj.missionPostalCode = mission.postalCode; + obj.missionDepartmentName = mission.departmentName; + obj.missionOrganizationName = mission.organizationName; + obj.missionOrganizationId = mission.organizationId; + obj.toPublisherId = mission.publisherId; + obj.toPublisherName = mission.publisherName; } if (click) { - obj1.clickId = click._id; - obj1.source = click.source || "publisher"; - obj1.sourceName = click.sourceName || ""; - obj1.sourceId = click.sourceId || ""; - obj1.fromPublisherId = click.fromPublisherId || ""; - obj1.fromPublisherName = click.fromPublisherName || ""; + obj.clickId = click._id; + obj.source = click.source || "publisher"; + obj.sourceName = click.sourceName || ""; + obj.sourceId = click.sourceId || ""; + obj.fromPublisherId = click.fromPublisherId || ""; + obj.fromPublisherName = click.fromPublisherName || ""; } if (click && !mission) { - obj1.missionId = click.missionId; - obj1.missionClientId = click.missionClientId; - obj1.missionDomain = click.missionDomain; - obj1.missionTitle = click.missionTitle; - obj1.missionPostalCode = click.missionPostalCode; - obj1.missionDepartmentName = click.missionDepartmentName; - obj1.missionOrganizationName = click.missionOrganizationName; - obj1.missionOrganizationId = click.missionOrganizationId; - obj1.toPublisherId = click.toPublisherId; - obj1.toPublisherName = click.toPublisherName; - } - - const response = await esClient.index({ index: STATS_INDEX, body: obj1 }); + obj.missionId = click.missionId; + obj.missionClientId = click.missionClientId; + obj.missionDomain = click.missionDomain; + obj.missionTitle = click.missionTitle; + obj.missionPostalCode = click.missionPostalCode; + obj.missionDepartmentName = click.missionDepartmentName; + obj.missionOrganizationName = click.missionOrganizationName; + obj.missionOrganizationId = click.missionOrganizationId; + obj.toPublisherId = click.toPublisherId; + obj.toPublisherName = click.toPublisherName; + } + + const response = await esClient.index({ index: STATS_INDEX, body: obj }); return res.status(200).send({ ok: true, id: response.body._id }); } catch (error) { captureException(error); @@ -175,8 +164,9 @@ router.get("/account", cors({ origin: "*" }), async (req: Request, res: Response if (!mission) captureMessage(`[Account] Mission not found`, `mission ${query.data.mission}`); } - const obj1 = { + const obj = { referer: identity.referer, + userAgent: identity.userAgent, user: identity.user, host: req.get("host") || "", origin: req.get("origin") || "", @@ -186,40 +176,40 @@ router.get("/account", cors({ origin: "*" }), async (req: Request, res: Response } as Stats; if (mission) { - obj1.missionId = mission._id.toString(); - obj1.missionClientId = mission.clientId; - obj1.missionDomain = mission.domain; - obj1.missionTitle = mission.title; - obj1.missionPostalCode = mission.postalCode; - obj1.missionDepartmentName = mission.departmentName; - obj1.missionOrganizationName = mission.organizationName; - obj1.missionOrganizationId = mission.organizationId; - obj1.toPublisherId = mission.publisherId; - obj1.toPublisherName = mission.publisherName; + obj.missionId = mission._id.toString(); + obj.missionClientId = mission.clientId; + obj.missionDomain = mission.domain; + obj.missionTitle = mission.title; + obj.missionPostalCode = mission.postalCode; + obj.missionDepartmentName = mission.departmentName; + obj.missionOrganizationName = mission.organizationName; + obj.missionOrganizationId = mission.organizationId; + obj.toPublisherId = mission.publisherId; + obj.toPublisherName = mission.publisherName; } if (click) { - obj1.clickId = click._id; - obj1.source = click.source || "publisher"; - obj1.sourceName = click.sourceName || ""; - obj1.sourceId = click.sourceId || ""; - obj1.fromPublisherId = click.fromPublisherId || ""; - obj1.fromPublisherName = click.fromPublisherName || ""; + obj.clickId = click._id; + obj.source = click.source || "publisher"; + obj.sourceName = click.sourceName || ""; + obj.sourceId = click.sourceId || ""; + obj.fromPublisherId = click.fromPublisherId || ""; + obj.fromPublisherName = click.fromPublisherName || ""; } if (click && !mission) { - obj1.missionId = click.missionId; - obj1.missionClientId = click.missionClientId; - obj1.missionDomain = click.missionDomain; - obj1.missionTitle = click.missionTitle; - obj1.missionPostalCode = click.missionPostalCode; - obj1.missionDepartmentName = click.missionDepartmentName; - obj1.missionOrganizationName = click.missionOrganizationName; - obj1.missionOrganizationId = click.missionOrganizationId; - obj1.toPublisherId = click.toPublisherId; - obj1.toPublisherName = click.toPublisherName; - } - - const response = await esClient.index({ index: STATS_INDEX, body: obj1 }); + obj.missionId = click.missionId; + obj.missionClientId = click.missionClientId; + obj.missionDomain = click.missionDomain; + obj.missionTitle = click.missionTitle; + obj.missionPostalCode = click.missionPostalCode; + obj.missionDepartmentName = click.missionDepartmentName; + obj.missionOrganizationName = click.missionOrganizationName; + obj.missionOrganizationId = click.missionOrganizationId; + obj.toPublisherId = click.toPublisherId; + obj.toPublisherName = click.toPublisherName; + } + + const response = await esClient.index({ index: STATS_INDEX, body: obj }); return res.status(200).send({ ok: true, id: response.body._id }); } catch (error: any) { captureException(error); @@ -262,8 +252,9 @@ router.get("/campaign/:id", cors({ origin: "*" }), async (req, res) => { const obj1 = { type: "click", - user: identity?.user, - referer: identity?.referer, + user: identity.user, + referer: identity.referer, + userAgent: identity.userAgent, host: req.get("host") || "", origin: req.get("origin") || "", source: "campaign", @@ -276,7 +267,6 @@ router.get("/campaign/:id", cors({ origin: "*" }), async (req, res) => { fromPublisherName: campaign.fromPublisherName, } as Stats; const click = await esClient.index({ index: STATS_INDEX, body: obj1 }); - console.log("click", click.body._id); const url = new URL(campaign.url); @@ -397,10 +387,11 @@ router.get("/widget/:id", cors({ origin: "*" }), async (req: Request, res: Respo return res.redirect(302, mission.applicationUrl); } - const obj1 = { + const obj = { type: "click", - user: identity?.user, - referer: identity?.referer, + user: identity.user, + referer: identity.referer, + userAgent: identity.userAgent, host: req.get("host") || "", origin: req.get("origin") || "", requestId: query.data.requestId, @@ -422,8 +413,7 @@ router.get("/widget/:id", cors({ origin: "*" }), async (req: Request, res: Respo fromPublisherId: widget.fromPublisherId, fromPublisherName: widget.fromPublisherName, } as Stats; - const click = await esClient.index({ index: STATS_INDEX, body: obj1 }); - console.log("click", click.body._id); + const click = await esClient.index({ index: STATS_INDEX, body: obj }); if (mission.applicationUrl.indexOf("http://") === -1 && mission.applicationUrl.indexOf("https://") === -1) { mission.applicationUrl = "https://" + mission.applicationUrl; @@ -478,6 +468,7 @@ router.get("/seo/:id", cors({ origin: "*" }), async (req: Request, res: Response host: req.get("host") || "", origin: req.get("origin") || "", referer: identity.referer, + userAgent: identity.userAgent, user: identity.user, createdAt: new Date(), source: "seo", @@ -499,8 +490,6 @@ router.get("/seo/:id", cors({ origin: "*" }), async (req: Request, res: Response } as Stats; const click = await esClient.index({ index: STATS_INDEX, body: obj }); - console.log("click", click.body._id); - const url = new URL(mission.applicationUrl || JVA_URL); url.searchParams.set("apiengagement_id", click.body._id); @@ -575,6 +564,7 @@ router.get("/:missionId/:publisherId", cors({ origin: "*" }), async function tra host: req.get("host") || "", origin: req.get("origin") || "", referer: identity.referer, + userAgent: identity.userAgent, user: identity.user, source: "publisher", sourceId: fromPublisher?._id || "", @@ -597,7 +587,7 @@ router.get("/:missionId/:publisherId", cors({ origin: "*" }), async function tra } as Stats; const click = await esClient.index({ index: STATS_INDEX, body: obj }); - console.log("click", click.body._id); + if (mission.applicationUrl.indexOf("http://") === -1 && mission.applicationUrl.indexOf("https://") === -1) { mission.applicationUrl = "https://" + mission.applicationUrl; } @@ -656,6 +646,7 @@ router.get("/impression/campaign/:campaignId", cors({ origin: "*" }), async (req host: req.get("host") || "", origin: req.get("origin") || "", referer: identity.referer, + userAgent: identity.userAgent, user: identity.user, createdAt: new Date(), tag: "link", @@ -672,7 +663,6 @@ router.get("/impression/campaign/:campaignId", cors({ origin: "*" }), async (req } as Stats; const print = await esClient.index({ index: STATS_INDEX, body: obj }); - console.log("print", print.body._id); res.status(200).send({ ok: true, data: { ...obj, _id: print.body._id } }); } catch (error) { captureException(error); @@ -735,6 +725,7 @@ router.get("/impression/:missionId/:publisherId", cors({ origin: "*" }), async ( host: req.get("host") || "", origin: req.get("origin") || "", referer: identity.referer, + userAgent: identity.userAgent, user: identity.user, createdAt: new Date(), tag: query.data.tracker, @@ -759,7 +750,6 @@ router.get("/impression/:missionId/:publisherId", cors({ origin: "*" }), async ( } as Stats; const print = await esClient.index({ index: STATS_INDEX, body: obj }); - console.log("print", print.body._id); res.status(200).send({ ok: true, data: { ...obj, _id: print.body._id } }); } catch (error: any) { diff --git a/api/src/models/mission.ts b/api/src/models/mission.ts index 58085b0..728d327 100644 --- a/api/src/models/mission.ts +++ b/api/src/models/mission.ts @@ -15,134 +15,136 @@ const geoPointSchema = new Schema({ }, }); -const schema = new Schema({ - // Identifiers - _old_id: { type: String }, - _old_ids: { type: [String] }, - - // Mission - clientId: { type: String, required: true }, - title: { type: String, required: true }, - description: { type: String, required: true }, - descriptionHtml: { type: String }, - tags: { type: [String] }, - tasks: { type: [String] }, - audience: { type: [String] }, - soft_skills: { type: [String] }, - reducedMobilityAccessible: { type: String, enum: ["yes", "no"], default: "no" }, - closeToTransport: { type: String, enum: ["yes", "no"], default: "no" }, - openToMinors: { type: String, enum: ["yes", "no"], default: "no" }, - remote: { type: String, enum: ["no", "possible", "full"], default: "no" }, - schedule: { type: String }, - duration: { type: Number }, - postedAt: { type: Date, default: Date.now }, - startAt: { type: Date, default: Date.now }, - endAt: { type: Date }, - priority: { type: String }, - places: { type: Number }, - metadata: { type: String }, - domain: { type: String }, - domainOriginal: { type: String }, - domainLogo: { type: String }, - activity: { type: String }, - type: { type: String }, - snu: { type: Boolean }, - snuPlaces: { type: Number }, - - // Address - adresse: { type: String }, // Misspelled in the doc but used in the code - address: { type: String }, - postalCode: { type: String }, - departmentName: { type: String }, - departmentCode: { type: String }, - city: { type: String }, - region: { type: String }, - country: { type: String }, - location: { - lat: { type: Number }, - lon: { type: Number }, +const schema = new Schema( + { + // Identifiers + _old_id: { type: String }, + _old_ids: { type: [String] }, + + // Mission + clientId: { type: String, required: true }, + title: { type: String, required: true }, + description: { type: String, required: true }, + descriptionHtml: { type: String }, + tags: { type: [String] }, + tasks: { type: [String] }, + audience: { type: [String] }, + soft_skills: { type: [String] }, + reducedMobilityAccessible: { type: String, enum: ["yes", "no"], default: "no" }, + closeToTransport: { type: String, enum: ["yes", "no"], default: "no" }, + openToMinors: { type: String, enum: ["yes", "no"], default: "no" }, + remote: { type: String, enum: ["no", "possible", "full"], default: "no" }, + schedule: { type: String }, + duration: { type: Number }, + postedAt: { type: Date, default: Date.now }, + startAt: { type: Date, default: Date.now }, + endAt: { type: Date }, + priority: { type: String }, + places: { type: Number }, + metadata: { type: String }, + domain: { type: String }, + domainOriginal: { type: String }, + domainLogo: { type: String }, + activity: { type: String }, + type: { type: String }, + snu: { type: Boolean }, + snuPlaces: { type: Number }, + + // Address + adresse: { type: String }, // Misspelled in the doc but used in the code + address: { type: String }, + postalCode: { type: String }, + departmentName: { type: String }, + departmentCode: { type: String }, + city: { type: String }, + region: { type: String }, + country: { type: String }, + location: { + lat: { type: Number }, + lon: { type: Number }, + }, + geoPoint: { type: geoPointSchema, default: null }, + + // Organisation + organizationId: { type: String }, + organizationUrl: { type: String }, + organizationName: { type: String }, + organizationType: { type: String }, + organizationLogo: { type: String }, + organizationDescription: { type: String }, + organizationClientId: { type: String }, + organizationFullAddress: { type: String }, + organizationRNA: { type: String }, + organizationSiren: { type: String }, + organizationDepartment: { type: String }, + organizationPostCode: { type: String }, + organizationCity: { type: String }, + organizationStatusJuridique: { type: String }, + organizationBeneficiaries: { type: [String] }, + organizationActions: { type: [String] }, + organizationReseaux: { type: [String] }, + + // Publisher (added by the API) + publisherId: { type: String, required: true }, + publisherName: { type: String, required: true }, + publisherUrl: { type: String }, + publisherLogo: { type: String }, + lastSyncAt: { type: Date, required: true }, + applicationUrl: { type: String }, + statusCode: { type: String, required: true, enum: ["ACCEPTED", "REFUSED"], default: "ACCEPTED" }, + statusComment: { type: String }, + statusCommentHistoric: { + type: [ + { + status: { type: String }, + comment: { type: String }, + date: { type: Date }, + }, + ], + }, + + // Association (added by the API) + associationId: { type: String }, + associationName: { type: String }, + associationSiren: { type: String }, + associationRNA: { type: String }, + associationSources: { type: [String] }, + associationReseaux: { type: [String] }, + associationLogo: { type: String }, + associationAddress: { type: String }, + associationCity: { type: String }, + associationPostalCode: { type: String }, + associationDepartmentCode: { type: String }, + associationDepartmentName: { type: String }, + associationRegion: { type: String }, + + // Metadata + deleted: { type: Boolean, default: false }, + deletedAt: { type: Date, default: null }, + + // Moderation JVA + moderation_5f5931496c7ea514150a818f_status: { type: String, enum: ["PENDING", "ONGOING", "ACCEPTED", "REFUSED"], default: "PENDING" }, + moderation_5f5931496c7ea514150a818f_comment: { type: String }, + moderation_5f5931496c7ea514150a818f_note: { type: String }, + moderation_5f5931496c7ea514150a818f_title: { type: String }, + moderation_5f5931496c7ea514150a818f_date: { type: Date }, + + // LeBonCoin + leboncoinStatus: { type: String }, + leboncoinUrl: { type: String }, + leboncoinComment: { type: String }, + leboncoinUpdatedAt: { type: Date }, + + // JobTeaser + jobteaserStatus: { type: String }, + jobteaserUrl: { type: String }, + jobteaserComment: { type: String }, + jobteaserUpdatedAt: { type: Date }, }, - geoPoint: { type: geoPointSchema, default: null }, - - // Organisation - organizationId: { type: String }, - organizationUrl: { type: String }, - organizationName: { type: String }, - organizationType: { type: String }, - organizationLogo: { type: String }, - organizationDescription: { type: String }, - organizationClientId: { type: String }, - organizationFullAddress: { type: String }, - organizationRNA: { type: String }, - organizationSiren: { type: String }, - organizationDepartment: { type: String }, - organizationPostCode: { type: String }, - organizationCity: { type: String }, - organizationStatusJuridique: { type: String }, - organizationBeneficiaries: { type: [String] }, - organizationActions: { type: [String] }, - organizationReseaux: { type: [String] }, - - // Publisher (added by the API) - publisherId: { type: String, required: true }, - publisherName: { type: String, required: true }, - publisherUrl: { type: String }, - publisherLogo: { type: String }, - lastSyncAt: { type: Date, required: true }, - applicationUrl: { type: String }, - statusCode: { type: String, required: true, enum: ["ACCEPTED", "REFUSED"], default: "ACCEPTED" }, - statusComment: { type: String }, - statusCommentHistoric: { - type: [ - { - status: { type: String }, - comment: { type: String }, - date: { type: Date }, - }, - ], + { + timestamps: true, }, - - // Association (added by the API) - associationId: { type: String }, - associationName: { type: String }, - associationSiren: { type: String }, - associationRNA: { type: String }, - associationSources: { type: [String] }, - associationReseaux: { type: [String] }, - associationLogo: { type: String }, - associationAddress: { type: String }, - associationCity: { type: String }, - associationPostalCode: { type: String }, - associationDepartmentCode: { type: String }, - associationDepartmentName: { type: String }, - associationRegion: { type: String }, - - // Metadata - deleted: { type: Boolean, default: false }, - deletedAt: { type: Date, default: null }, - - // Moderation JVA - moderation_5f5931496c7ea514150a818f_status: { type: String, enum: ["PENDING", "ONGOING", "ACCEPTED", "REFUSED"], default: "PENDING" }, - moderation_5f5931496c7ea514150a818f_comment: { type: String }, - moderation_5f5931496c7ea514150a818f_note: { type: String }, - moderation_5f5931496c7ea514150a818f_title: { type: String }, - moderation_5f5931496c7ea514150a818f_date: { type: Date }, - - // LeBonCoin - leboncoinStatus: { type: String }, - leboncoinUrl: { type: String }, - leboncoinComment: { type: String }, - leboncoinUpdatedAt: { type: Date }, - - // JobTeaser - jobteaserStatus: { type: String }, - jobteaserUrl: { type: String }, - jobteaserComment: { type: String }, - jobteaserUpdatedAt: { type: Date }, - - createdAt: { type: Date, default: Date.now }, - updatedAt: { type: Date, default: Date.now }, -}); +); schema.index({ _old_id: 1 }); schema.index({ _old_ids: 1 }); diff --git a/api/src/types/index.d.ts b/api/src/types/index.d.ts index bfa7c62..3cad3c5 100644 --- a/api/src/types/index.d.ts +++ b/api/src/types/index.d.ts @@ -463,6 +463,7 @@ export interface Stats { requestId?: string; origin: string; referer: string; + userAgent: string; host: string; user?: string; createdAt: Date; diff --git a/api/src/utils.ts b/api/src/utils.ts index 607ccaf..b8690d1 100644 --- a/api/src/utils.ts +++ b/api/src/utils.ts @@ -1,5 +1,8 @@ import { Request } from "express"; import geoip from "geoip-lite"; +import { isbot } from "isbot"; +import hash from "object-hash"; +import { ENV } from "./config"; import { EsQuery } from "./types"; export const slugify = (value: string) => { @@ -132,3 +135,14 @@ export const getDistanceFromLatLonInKm = (lat1?: number, lon1?: number, lat2?: n return r * c; // Distance in kilometers }; + +export const identify = (req: Request) => { + const userAgent = req.get("user-agent"); + + if (isbot(userAgent) && ENV !== "development") return null; + + const ip = req.ip; + const referer = req.header("referer") || "not_defined"; + const user = hash([ip, referer, userAgent]); + return { user, userAgent, referer: referer.includes("?") ? referer.split("?")[0] : referer }; +}; diff --git a/api/src/v0/mission.ts b/api/src/v0/mission.ts index 150ea9c..e5d0760 100644 --- a/api/src/v0/mission.ts +++ b/api/src/v0/mission.ts @@ -411,6 +411,7 @@ router.post("/search", async (req: PublisherRequest, res: Response, next: NextFu const buildData = (data: Mission, publisherId: string, moderator: boolean = false) => { return { _id: data._id, + id: data._id, clientId: data.clientId, publisherId: data.publisherId, activity: data.activity, diff --git a/api/src/v0/mymission.ts b/api/src/v0/mymission.ts index 7bdb0b0..deebf70 100644 --- a/api/src/v0/mymission.ts +++ b/api/src/v0/mymission.ts @@ -161,6 +161,7 @@ router.get("/:clientId/stats", passport.authenticate(["apikey", "api"], { sessio const buildData = (data: Mission) => { return { _id: data._id, + id: data._id, clientId: data.clientId, publisherId: data.publisherId, activity: data.activity, diff --git a/app/.gitignore b/app/.gitignore index dff4276..77bc5b4 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,4 +1,4 @@ node_modules dist .env -.env.sentry-build-plugin \ No newline at end of file +.env.sentry-build-plugin diff --git a/app/src/scenes/my-missions/Flux.jsx b/app/src/scenes/my-missions/Flux.jsx index bc679e1..a5d966c 100644 --- a/app/src/scenes/my-missions/Flux.jsx +++ b/app/src/scenes/my-missions/Flux.jsx @@ -8,11 +8,11 @@ import Loader from "../../components/Loader"; import Select from "../../components/NewSelect"; import TablePagination from "../../components/NewTablePagination"; import SearchInput from "../../components/SearchInput"; +import { STATUS_PLR } from "../../constants"; import api from "../../services/api"; import { captureError } from "../../services/error"; import useStore from "../../services/store"; import exportCSV from "../../services/utils"; -import { STATUS } from "../broadcast/moderation/components/Constants"; const TABLE_HEADER = [ { title: "Mission", key: "title.keyword", colSpan: 4 }, @@ -72,7 +72,6 @@ const Flux = () => { }, []); useEffect(() => { - // Debounce search const controller = new AbortController(); const fetchData = async () => { setLoading(true); @@ -163,35 +162,35 @@ const Flux = () => { setFilters({ ...filters, search })} placeholder="Rechercher par mot-clé" />
({ value: e.key, label: e.key, count: e.doc_count }))} + options={options.domains.map((e) => ({ value: e.key === "" ? "none" : e.key, label: e.key === "" ? "Non renseignée" : e.key, count: e.doc_count }))} value={filters.domain} onChange={(e) => setFilters({ ...filters, domain: e.value })} placeholder="Domaine" loading={loading} /> ({ value: e.key, label: e.key, count: e.doc_count }))} + options={options.cities.map((e) => ({ value: e.key === "" ? "none" : e.key, label: e.key === "" ? "Non renseignée" : e.key, count: e.doc_count }))} value={filters.city} onChange={(e) => setFilters({ ...filters, city: e.value })} placeholder="Ville" loading={loading} />