From ac1e5808b270c80451f5273aa6a49d604396c64c Mon Sep 17 00:00:00 2001 From: aecsocket <43144841+aecsocket@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:49:25 +0100 Subject: [PATCH 1/3] fix: analytics event endpoint --- apps/labrinth/src/routes/internal/mod.rs | 5 ----- apps/labrinth/src/routes/v3/mod.rs | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/labrinth/src/routes/internal/mod.rs b/apps/labrinth/src/routes/internal/mod.rs index 272ac2de8b..c29917bcab 100644 --- a/apps/labrinth/src/routes/internal/mod.rs +++ b/apps/labrinth/src/routes/internal/mod.rs @@ -50,11 +50,6 @@ pub fn config(cfg: &mut web::ServiceConfig) { .configure(medal::config) .configure(mural::config) .configure(statuses::config), - ) - .service( - web::scope("/v3/analytics-event") - .wrap(default_cors()) - .configure(super::v3::analytics_event::config), ); } diff --git a/apps/labrinth/src/routes/v3/mod.rs b/apps/labrinth/src/routes/v3/mod.rs index 919bffee4e..133c5071b9 100644 --- a/apps/labrinth/src/routes/v3/mod.rs +++ b/apps/labrinth/src/routes/v3/mod.rs @@ -30,6 +30,11 @@ pub mod versions; pub mod oauth_clients; pub fn config(cfg: &mut web::ServiceConfig) { + cfg.service( + web::scope("/v3/analytics-event") + .wrap(default_cors()) + .configure(analytics_event::config), + ); cfg.service( web::scope("/v3/analytics") .wrap(default_cors()) From d9791fc94e8baf32212ee9cc995a04940b47bb8e Mon Sep 17 00:00:00 2001 From: aecsocket <43144841+aecsocket@users.noreply.github.com> Date: Thu, 30 Jul 2026 04:52:20 +0100 Subject: [PATCH 2/3] split admin-only routes into internal --- .../src/pages/admin/analytics/events.vue | 8 +- .../src/routes/internal/analytics_event.rs | 192 ++++++++++++++++++ apps/labrinth/src/routes/internal/mod.rs | 12 +- .../labrinth/src/routes/v3/analytics_event.rs | 188 +---------------- apps/labrinth/src/routes/v3/mod.rs | 1 + packages/api-client/src/modules/index.ts | 2 + .../modules/labrinth/analytics/internal.ts | 51 +++++ .../src/modules/labrinth/analytics/v3.ts | 43 ---- .../api-client/src/modules/labrinth/index.ts | 1 + .../api-client/src/modules/labrinth/types.ts | 18 +- 10 files changed, 273 insertions(+), 243 deletions(-) create mode 100644 apps/labrinth/src/routes/internal/analytics_event.rs create mode 100644 packages/api-client/src/modules/labrinth/analytics/internal.ts diff --git a/apps/frontend/src/pages/admin/analytics/events.vue b/apps/frontend/src/pages/admin/analytics/events.vue index bffebfaada..a471615ce9 100644 --- a/apps/frontend/src/pages/admin/analytics/events.vue +++ b/apps/frontend/src/pages/admin/analytics/events.vue @@ -485,9 +485,9 @@ async function saveEvent() { const payload = buildEventPayload() if (modalMode.value === 'edit' && editingEventId.value !== null) { - await client.labrinth.analytics_v3.editEvent(editingEventId.value, payload) + await client.labrinth.analytics_internal.editEvent(editingEventId.value, payload) } else { - await client.labrinth.analytics_v3.createEvent(payload) + await client.labrinth.analytics_internal.createEvent(payload) } await queryClient.invalidateQueries({ queryKey: analyticsEventsQueryKey }) @@ -528,7 +528,7 @@ async function deleteEvent(eventId: Labrinth.Analytics.v3.AnalyticsEventId) { setDeletingEvent(eventId, true) try { - await client.labrinth.analytics_v3.deleteEvent(eventId) + await client.labrinth.analytics_internal.deleteEvent(eventId) await queryClient.invalidateQueries({ queryKey: analyticsEventsQueryKey }) addNotification({ title: 'Analytics event deleted', @@ -581,7 +581,7 @@ function commitAnnouncementUrl() { committedAnnouncementUrl.value = form.value.announcementUrl } -function buildEventPayload(): Labrinth.Analytics.v3.AnalyticsEventUpsert { +function buildEventPayload(): Labrinth.Analytics.Internal.AnalyticsEventUpsert { const selectedRange = getEventFormDateRange() if (!selectedRange) { throw new Error('Select a valid start and end date') diff --git a/apps/labrinth/src/routes/internal/analytics_event.rs b/apps/labrinth/src/routes/internal/analytics_event.rs new file mode 100644 index 0000000000..a743703da3 --- /dev/null +++ b/apps/labrinth/src/routes/internal/analytics_event.rs @@ -0,0 +1,192 @@ +use actix_web::{HttpRequest, delete, patch, post, web}; +use chrono::{DateTime, Utc}; +use eyre::eyre; +use serde::{Deserialize, Serialize}; +use xredis::RedisPool; + +use crate::{ + auth::get_user_from_headers, + database::{ + PgPool, + models::{ + DBAnalyticsEvent, DBAnalyticsEventId, generate_analytics_event_id, + }, + }, + models::{ + ids::AnalyticsEventId, + pats::Scopes, + v3::analytics_event::{AnalyticsEvent, AnalyticsEventMeta}, + }, + queue::session::AuthQueue, + routes::ApiError, + util::error::Context, +}; + +pub fn config(cfg: &mut actix_web::web::ServiceConfig) { + cfg.service(analytics_event_create) + .service(analytics_event_edit) + .service(analytics_event_delete); +} + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct AnalyticsEventUpsert { + #[serde(flatten)] + pub meta: AnalyticsEventMeta, + pub starts: DateTime, + pub ends: DateTime, +} + +/// Create an analytics event. +#[utoipa::path( + context_path = "/analytics-event", + tag = "analytics events", responses((status = OK, body = AnalyticsEvent)) +)] +#[post("")] +pub async fn analytics_event_create( + req: HttpRequest, + event: web::Json, + pool: web::Data, + redis: web::Data, + session_queue: web::Data, +) -> Result, ApiError> { + let user = get_user_from_headers( + &req, + &**pool, + &redis, + &session_queue, + Scopes::empty(), + ) + .await? + .1; + + if !user.role.is_admin() { + return Err(ApiError::Auth(eyre!( + "you do not have permission to manage analytics events" + ))); + } + + let mut transaction = pool + .begin() + .await + .wrap_internal_err("failed to begin transaction")?; + let id = generate_analytics_event_id(&mut transaction) + .await + .wrap_internal_err("failed to generate analytics event ID")?; + + let event = DBAnalyticsEvent { + id, + meta: event.meta.clone(), + starts: event.starts, + ends: event.ends, + }; + event + .insert(&mut transaction) + .await + .wrap_internal_err("failed to insert analytics event")?; + + transaction + .commit() + .await + .wrap_internal_err("failed to commit transaction")?; + DBAnalyticsEvent::clear_cache(&redis) + .await + .wrap_internal_err("failed to clear analytics event cache")?; + + Ok(web::Json(event.into())) +} + +/// Update an analytics event. +#[utoipa::path( + context_path = "/analytics-event", + tag = "analytics events", responses((status = OK, body = AnalyticsEvent)) +)] +#[patch("/{id}")] +pub async fn analytics_event_edit( + req: HttpRequest, + id: web::Path<(AnalyticsEventId,)>, + event: web::Json, + pool: web::Data, + redis: web::Data, + session_queue: web::Data, +) -> Result, ApiError> { + let user = get_user_from_headers( + &req, + &**pool, + &redis, + &session_queue, + Scopes::empty(), + ) + .await? + .1; + + if !user.role.is_admin() { + return Err(ApiError::Auth(eyre!( + "you do not have permission to manage analytics events" + ))); + } + + let event = DBAnalyticsEvent { + id: DBAnalyticsEventId::from(id.into_inner().0), + meta: event.meta.clone(), + starts: event.starts, + ends: event.ends, + }; + + let updated = event + .update(&**pool) + .await + .wrap_internal_err("failed to update analytics event")?; + if !updated { + return Err(ApiError::NotFound); + } + DBAnalyticsEvent::clear_cache(&redis) + .await + .wrap_internal_err("failed to clear analytics event cache")?; + + Ok(web::Json(event.into())) +} + +/// Delete an analytics event. +#[utoipa::path( + context_path = "/analytics-event", + tag = "analytics events", responses((status = NO_CONTENT)) +)] +#[delete("/{id}")] +pub async fn analytics_event_delete( + req: HttpRequest, + id: web::Path<(AnalyticsEventId,)>, + pool: web::Data, + redis: web::Data, + session_queue: web::Data, +) -> Result<(), ApiError> { + let user = get_user_from_headers( + &req, + &**pool, + &redis, + &session_queue, + Scopes::empty(), + ) + .await? + .1; + + if !user.role.is_admin() { + return Err(ApiError::Auth(eyre!( + "you do not have permission to manage analytics events" + ))); + } + + let deleted = DBAnalyticsEvent::remove( + DBAnalyticsEventId::from(id.into_inner().0), + &**pool, + ) + .await + .wrap_internal_err("failed to delete analytics event")?; + if !deleted { + return Err(ApiError::NotFound); + } + DBAnalyticsEvent::clear_cache(&redis) + .await + .wrap_internal_err("failed to clear analytics event cache")?; + + Ok(()) +} diff --git a/apps/labrinth/src/routes/internal/mod.rs b/apps/labrinth/src/routes/internal/mod.rs index c29917bcab..1ad10523b1 100644 --- a/apps/labrinth/src/routes/internal/mod.rs +++ b/apps/labrinth/src/routes/internal/mod.rs @@ -1,5 +1,6 @@ pub mod admin; pub mod affiliate; +pub mod analytics_event; pub mod attribution; pub mod billing; pub mod blocked_users; @@ -35,6 +36,10 @@ pub fn config(cfg: &mut web::ServiceConfig) { .configure(flows::config) .configure(pats::config) .configure(oauth_clients::config) + .service( + web::scope("/analytics-event") + .configure(analytics_event::config), + ) .service(web::scope("/moderation").configure(moderation::config)) .service(web::scope("/affiliate").configure(affiliate::config)) .service(web::scope("/campaign").configure(campaign::config)) @@ -175,10 +180,9 @@ pub fn config(cfg: &mut web::ServiceConfig) { medal::redeem, mural::get_bank_details, statuses::ws_init, - super::v3::analytics_event::analytics_events_get, - super::v3::analytics_event::analytics_event_create, - super::v3::analytics_event::analytics_event_edit, - super::v3::analytics_event::analytics_event_delete, + analytics_event::analytics_event_create, + analytics_event::analytics_event_edit, + analytics_event::analytics_event_delete, ), modifiers(&InternalPathModifier, &SecurityAddon) )] diff --git a/apps/labrinth/src/routes/v3/analytics_event.rs b/apps/labrinth/src/routes/v3/analytics_event.rs index 9bbe2ef0a0..781a9d34d8 100644 --- a/apps/labrinth/src/routes/v3/analytics_event.rs +++ b/apps/labrinth/src/routes/v3/analytics_event.rs @@ -1,40 +1,15 @@ -use actix_web::{HttpRequest, delete, get, patch, post, web}; -use chrono::{DateTime, Utc}; -use eyre::eyre; -use serde::{Deserialize, Serialize}; +use actix_web::{get, web}; use xredis::RedisPool; use crate::{ - auth::get_user_from_headers, - database::{ - PgPool, - models::{ - DBAnalyticsEvent, DBAnalyticsEventId, generate_analytics_event_id, - }, - }, - models::{ - ids::AnalyticsEventId, - pats::Scopes, - v3::analytics_event::{AnalyticsEvent, AnalyticsEventMeta}, - }, - queue::session::AuthQueue, + database::{PgPool, models::DBAnalyticsEvent}, + models::v3::analytics_event::AnalyticsEvent, routes::ApiError, util::error::Context, }; pub fn config(cfg: &mut actix_web::web::ServiceConfig) { - cfg.service(analytics_events_get) - .service(analytics_event_create) - .service(analytics_event_edit) - .service(analytics_event_delete); -} - -#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] -pub struct AnalyticsEventUpsert { - #[serde(flatten)] - pub meta: AnalyticsEventMeta, - pub starts: DateTime, - pub ends: DateTime, + cfg.service(analytics_events_get); } /// List analytics events. @@ -56,158 +31,3 @@ pub async fn analytics_events_get( Ok(web::Json(events)) } - -/// Create an analytics event. -#[utoipa::path( - context_path = "/v3/analytics-event", - tag = "v3 analytics", responses((status = OK, body = AnalyticsEvent)) -)] -#[post("")] -pub async fn analytics_event_create( - req: HttpRequest, - event: web::Json, - pool: web::Data, - redis: web::Data, - session_queue: web::Data, -) -> Result, ApiError> { - let user = get_user_from_headers( - &req, - &**pool, - &redis, - &session_queue, - Scopes::empty(), - ) - .await? - .1; - - if !user.role.is_admin() { - return Err(ApiError::Auth(eyre!( - "you do not have permission to manage analytics events" - ))); - } - - let mut transaction = pool - .begin() - .await - .wrap_internal_err("failed to begin transaction")?; - let id = generate_analytics_event_id(&mut transaction) - .await - .wrap_internal_err("failed to generate analytics event ID")?; - - let event = DBAnalyticsEvent { - id, - meta: event.meta.clone(), - starts: event.starts, - ends: event.ends, - }; - event - .insert(&mut transaction) - .await - .wrap_internal_err("failed to insert analytics event")?; - - transaction - .commit() - .await - .wrap_internal_err("failed to commit transaction")?; - DBAnalyticsEvent::clear_cache(&redis) - .await - .wrap_internal_err("failed to clear analytics event cache")?; - - Ok(web::Json(event.into())) -} - -/// Update an analytics event. -#[utoipa::path( - context_path = "/v3/analytics-event", - tag = "v3 analytics", responses((status = OK, body = AnalyticsEvent)) -)] -#[patch("/{id}")] -pub async fn analytics_event_edit( - req: HttpRequest, - id: web::Path<(AnalyticsEventId,)>, - event: web::Json, - pool: web::Data, - redis: web::Data, - session_queue: web::Data, -) -> Result, ApiError> { - let user = get_user_from_headers( - &req, - &**pool, - &redis, - &session_queue, - Scopes::empty(), - ) - .await? - .1; - - if !user.role.is_admin() { - return Err(ApiError::Auth(eyre!( - "you do not have permission to manage analytics events" - ))); - } - - let event = DBAnalyticsEvent { - id: DBAnalyticsEventId::from(id.into_inner().0), - meta: event.meta.clone(), - starts: event.starts, - ends: event.ends, - }; - - let updated = event - .update(&**pool) - .await - .wrap_internal_err("failed to update analytics event")?; - if !updated { - return Err(ApiError::NotFound); - } - DBAnalyticsEvent::clear_cache(&redis) - .await - .wrap_internal_err("failed to clear analytics event cache")?; - - Ok(web::Json(event.into())) -} - -/// Delete an analytics event. -#[utoipa::path( - context_path = "/v3/analytics-event", - tag = "v3 analytics", responses((status = NO_CONTENT)) -)] -#[delete("/{id}")] -pub async fn analytics_event_delete( - req: HttpRequest, - id: web::Path<(AnalyticsEventId,)>, - pool: web::Data, - redis: web::Data, - session_queue: web::Data, -) -> Result<(), ApiError> { - let user = get_user_from_headers( - &req, - &**pool, - &redis, - &session_queue, - Scopes::empty(), - ) - .await? - .1; - - if !user.role.is_admin() { - return Err(ApiError::Auth(eyre!( - "you do not have permission to manage analytics events" - ))); - } - - let deleted = DBAnalyticsEvent::remove( - DBAnalyticsEventId::from(id.into_inner().0), - &**pool, - ) - .await - .wrap_internal_err("failed to delete analytics event")?; - if !deleted { - return Err(ApiError::NotFound); - } - DBAnalyticsEvent::clear_cache(&redis) - .await - .wrap_internal_err("failed to clear analytics event cache")?; - - Ok(()) -} diff --git a/apps/labrinth/src/routes/v3/mod.rs b/apps/labrinth/src/routes/v3/mod.rs index 133c5071b9..8b92681138 100644 --- a/apps/labrinth/src/routes/v3/mod.rs +++ b/apps/labrinth/src/routes/v3/mod.rs @@ -85,6 +85,7 @@ pub fn config(cfg: &mut web::ServiceConfig) { description = include_str!("../../api_v3_description.md"), ), paths( + analytics_event::analytics_events_get, analytics_get::fetch_analytics, analytics_get::facets::fetch_facets, analytics_get::old::playtimes_get, diff --git a/packages/api-client/src/modules/index.ts b/packages/api-client/src/modules/index.ts index 9f8167bbc8..28b3c77e9a 100644 --- a/packages/api-client/src/modules/index.ts +++ b/packages/api-client/src/modules/index.ts @@ -19,6 +19,7 @@ import { KyrosLogsV1Module } from './kyros/logs/v1' import { KyrosUploadSessionsV1Module } from './kyros/upload-sessions/v1' import { LabrinthVersionsV2Module, LabrinthVersionsV3Module } from './labrinth' import { LabrinthAffiliateInternalModule } from './labrinth/affiliate/internal' +import { LabrinthAnalyticsInternalModule } from './labrinth/analytics/internal' import { LabrinthAnalyticsV3Module } from './labrinth/analytics/v3' import { LabrinthAttributionInternalModule } from './labrinth/attribution/internal' import { LabrinthAuthInternalModule } from './labrinth/auth/internal' @@ -97,6 +98,7 @@ export const MODULE_REGISTRY = { kyros_logs_v1: KyrosLogsV1Module, kyros_upload_sessions_v1: KyrosUploadSessionsV1Module, labrinth_affiliate_internal: LabrinthAffiliateInternalModule, + labrinth_analytics_internal: LabrinthAnalyticsInternalModule, labrinth_analytics_v3: LabrinthAnalyticsV3Module, labrinth_auth_internal: LabrinthAuthInternalModule, labrinth_auth_v2: LabrinthAuthV2Module, diff --git a/packages/api-client/src/modules/labrinth/analytics/internal.ts b/packages/api-client/src/modules/labrinth/analytics/internal.ts new file mode 100644 index 0000000000..b794327ef8 --- /dev/null +++ b/packages/api-client/src/modules/labrinth/analytics/internal.ts @@ -0,0 +1,51 @@ +import { AbstractModule } from '../../../core/abstract-module' +import type { Labrinth } from '../types' + +export class LabrinthAnalyticsInternalModule extends AbstractModule { + public getModuleID(): string { + return 'labrinth_analytics_internal' + } + + /** + * Create an analytics event. + * POST /_internal/analytics-event + */ + public async createEvent( + data: Labrinth.Analytics.Internal.AnalyticsEventUpsert, + ): Promise { + return this.client.request('/analytics-event', { + api: 'labrinth', + version: 'internal', + method: 'POST', + body: data, + }) + } + + /** + * Edit an analytics event. + * PATCH /_internal/analytics-event/{id} + */ + public async editEvent( + id: Labrinth.Analytics.v3.AnalyticsEventId, + data: Labrinth.Analytics.Internal.AnalyticsEventUpsert, + ): Promise { + return this.client.request(`/analytics-event/${id}`, { + api: 'labrinth', + version: 'internal', + method: 'PATCH', + body: data, + }) + } + + /** + * Delete an analytics event. + * DELETE /_internal/analytics-event/{id} + */ + public async deleteEvent(id: Labrinth.Analytics.v3.AnalyticsEventId): Promise { + return this.client.request(`/analytics-event/${id}`, { + api: 'labrinth', + version: 'internal', + method: 'DELETE', + }) + } +} diff --git a/packages/api-client/src/modules/labrinth/analytics/v3.ts b/packages/api-client/src/modules/labrinth/analytics/v3.ts index ba93ca4ac8..6b7757e9cb 100644 --- a/packages/api-client/src/modules/labrinth/analytics/v3.ts +++ b/packages/api-client/src/modules/labrinth/analytics/v3.ts @@ -70,47 +70,4 @@ export class LabrinthAnalyticsV3Module extends AbstractModule { method: 'GET', }) } - - /** - * Create an analytics event. - * POST /v3/analytics-event - */ - public async createEvent( - data: Labrinth.Analytics.v3.AnalyticsEventUpsert, - ): Promise { - return this.client.request('/analytics-event', { - api: 'labrinth', - version: 3, - method: 'POST', - body: data, - }) - } - - /** - * Edit an analytics event. - * PATCH /v3/analytics-event/{id} - */ - public async editEvent( - id: Labrinth.Analytics.v3.AnalyticsEventId, - data: Labrinth.Analytics.v3.AnalyticsEventUpsert, - ): Promise { - return this.client.request(`/analytics-event/${id}`, { - api: 'labrinth', - version: 3, - method: 'PATCH', - body: data, - }) - } - - /** - * Delete an analytics event. - * DELETE /v3/analytics-event/{id} - */ - public async deleteEvent(id: Labrinth.Analytics.v3.AnalyticsEventId): Promise { - return this.client.request(`/analytics-event/${id}`, { - api: 'labrinth', - version: 3, - method: 'DELETE', - }) - } } diff --git a/packages/api-client/src/modules/labrinth/index.ts b/packages/api-client/src/modules/labrinth/index.ts index 38d23edd70..51cca73d32 100644 --- a/packages/api-client/src/modules/labrinth/index.ts +++ b/packages/api-client/src/modules/labrinth/index.ts @@ -1,3 +1,4 @@ +export * from './analytics/internal' export * from './analytics/v3' export * from './attribution/internal' export * from './auth/internal' diff --git a/packages/api-client/src/modules/labrinth/types.ts b/packages/api-client/src/modules/labrinth/types.ts index a5de5b8d8d..0e571a6291 100644 --- a/packages/api-client/src/modules/labrinth/types.ts +++ b/packages/api-client/src/modules/labrinth/types.ts @@ -463,24 +463,26 @@ export namespace Labrinth { } export namespace Analytics { - export namespace v3 { - export type AnalyticsEventId = number - export type AnalyticsEventMetricKind = 'views' | 'revenue' | 'downloads' | 'playtime' - - export type AnalyticsEvent = { + export namespace Internal { + export type AnalyticsEventUpsert = { announcement_url: string | null - for_metric_kind: AnalyticsEventMetricKind[] | null + for_metric_kind: v3.AnalyticsEventMetricKind[] | null title: string ends: string - id: AnalyticsEventId starts: string } + } - export type AnalyticsEventUpsert = { + export namespace v3 { + export type AnalyticsEventId = number + export type AnalyticsEventMetricKind = 'views' | 'revenue' | 'downloads' | 'playtime' + + export type AnalyticsEvent = { announcement_url: string | null for_metric_kind: AnalyticsEventMetricKind[] | null title: string ends: string + id: AnalyticsEventId starts: string } From de6aa7e2e47cfed6867bc157f31a9d44f6d50f17 Mon Sep 17 00:00:00 2001 From: aecsocket <43144841+aecsocket@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:33:30 +0100 Subject: [PATCH 3/3] fix pr comment --- apps/labrinth/src/routes/v3/analytics_event.rs | 5 ++--- apps/labrinth/src/routes/v3/mod.rs | 6 +----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/labrinth/src/routes/v3/analytics_event.rs b/apps/labrinth/src/routes/v3/analytics_event.rs index 781a9d34d8..53142b411e 100644 --- a/apps/labrinth/src/routes/v3/analytics_event.rs +++ b/apps/labrinth/src/routes/v3/analytics_event.rs @@ -12,12 +12,11 @@ pub fn config(cfg: &mut actix_web::web::ServiceConfig) { cfg.service(analytics_events_get); } -/// List analytics events. +/// List analytics events. #[utoipa::path( - context_path = "/v3/analytics-event", tag = "v3 analytics", responses((status = OK, body = Vec)) )] -#[get("")] +#[get("/analytics-event")] pub async fn analytics_events_get( pool: web::Data, redis: web::Data, diff --git a/apps/labrinth/src/routes/v3/mod.rs b/apps/labrinth/src/routes/v3/mod.rs index 8b92681138..735daff22f 100644 --- a/apps/labrinth/src/routes/v3/mod.rs +++ b/apps/labrinth/src/routes/v3/mod.rs @@ -30,11 +30,6 @@ pub mod versions; pub mod oauth_clients; pub fn config(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/v3/analytics-event") - .wrap(default_cors()) - .configure(analytics_event::config), - ); cfg.service( web::scope("/v3/analytics") .wrap(default_cors()) @@ -54,6 +49,7 @@ pub fn config(cfg: &mut web::ServiceConfig) { cfg.service( web::scope("/v3") .wrap(default_cors()) + .configure(analytics_event::config) .configure(limits::config) .configure(collections::config) .configure(images::config)