Skip to content

Commit

Permalink
fix: properly parse IDs + add test on TS client
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeDecMeetsMore committed Aug 7, 2024
1 parent 3e5c78b commit 51bf71c
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 11 deletions.
15 changes: 15 additions & 0 deletions scheduler/clients/javascript/lib/domain/calendarEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,18 @@ export interface CalendarEventInstance {
*/
busy: boolean
}

/**
* Calendar event with instances
*/
export type CalendarEventWithInstances = {
/**
* Event object
*/
event: CalendarEvent
/**
* List of instances of the event
* Especially useful for recurring events
*/
instances: CalendarEventInstance[]
}
69 changes: 67 additions & 2 deletions scheduler/clients/javascript/lib/userClient.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
import type { CalendarEventInstance } from './domain/calendarEvent'
import type {
CalendarEvent,
CalendarEventInstance,
CalendarEventWithInstances,
} from './domain/calendarEvent'
import { APIResponse, NettuBaseClient } from './baseClient'
import type { Metadata } from './domain/metadata'
import type { User } from './domain/user'
import type { IntegrationProvider, UUID } from '.'
import { convertInstanceDates } from './helpers/datesConverters'
import {
convertEventDates,
convertInstanceDates,
} from './helpers/datesConverters'

/**
* Request to get events of multiple calendars
*/
type GetEventsOfMultipleCalendars = {
/**
* List of calendar ids to get events from
*/
calendarIds: UUID[]
/**
* Start time of the period to get events
* @format Date in UTC
*/
startTime: Date
/**
* End time of the period to get events
* @format Date in UTC
*/
endTime: Date
}

/**
* Request to get a user's freebusy
Expand Down Expand Up @@ -96,6 +123,13 @@ type UserResponse = {
user: User
}

/**
* Response when getting events of multiple calendars
*/
type GetEventsOfMultipleCalendarsResponse = {
events: CalendarEventWithInstances[]
}

/**
* Client for the user endpoints
* This is an admin client (usually backend)
Expand Down Expand Up @@ -138,6 +172,37 @@ export class NettuUserClient extends NettuBaseClient {
return this.delete<UserResponse>(`/user/${userId}`)
}

public async getEventsOfMultipleCalendars(
userId: UUID,
req: GetEventsOfMultipleCalendars
): Promise<APIResponse<GetEventsOfMultipleCalendarsResponse>> {
const res = await this.get<GetEventsOfMultipleCalendarsResponse>(
`/user/${userId}/events`,
{
calendarIds: req.calendarIds.join(','),
startTime: req.startTime.toISOString(),
endTime: req.endTime.toISOString(),
}
)

if (!res.data) {
return res
}

return {
res: res.res,
status: res.status,
data: {
events: res.data.events.map(event => {
return {
event: convertEventDates(event.event),
instances: event.instances.map(convertInstanceDates),
}
}),
}
}
}

public async freebusy(
userId: UUID,
req: GetUserFeebusyReq
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,79 @@ describe('Requirements', () => {
})
})

describe('A user calendar can be queried for availability', () => {
describe('A user can see the events during a timespan of all his calendars', () => {
let user1: User | undefined
let user1Calendar1: Calendar | undefined
let user1Calendar2: Calendar | undefined
let user1Calendar1Event1: CalendarEvent | undefined
let user1Calendar2Event1: CalendarEvent | undefined

beforeAll(async () => {
const res = await client?.user.create()
if (!res?.data) {
throw new Error('User not created')
}
expect(res?.status).toBe(201)
user1 = res.data.user

if (!user1) {
throw new Error('No user')
}
const resCal1 = await client?.calendar.create(user1.id, {
timezone: 'Asia/Tokyo',
})
expect(resCal1?.status).toBe(201)
user1Calendar1 = resCal1?.data?.calendar

const resCal2 = await client?.calendar.create(user1.id, {
timezone: 'Asia/Tokyo',
})
expect(resCal2?.status).toBe(201)
user1Calendar2 = resCal2?.data?.calendar

if (!user1 || !user1Calendar1 || !user1Calendar2) {
throw new Error('No user or calendar')
}
const resEvent1 = await client?.events.create(user1.id, {
calendarId: user1Calendar1.id,
duration: 1000 * 60 * 60,
startTime: new Date(0),
busy: true,
})
expect(resEvent1?.status).toBe(201)
user1Calendar1Event1 = resEvent1?.data?.event

const resEvent2 = await client?.events.create(user1.id, {
calendarId: user1Calendar2.id,
duration: 1000 * 60 * 60,
startTime: new Date(1000 * 60 * 60),
busy: true,
})
expect(resEvent2?.status).toBe(201)
user1Calendar2Event1 = resEvent2?.data?.event
})

it('should list the events in the calendars', async () => {
if (!user1 || !user1Calendar1 || !user1Calendar2) {
throw new Error('One or both calendars are missing')
}
const startTime = new Date(10)
const endTime = new Date(1000 * 60 * 60 * 24 * 4)

const res = await client?.user.getEventsOfMultipleCalendars(user1.id, {
calendarIds: [user1Calendar1.id, user1Calendar2.id],
startTime,
endTime,
})
expect(res?.status).toBe(200)
expect(res?.data).toBeDefined()
expect(res?.data?.events.length).toBe(2)
expect(res?.data?.events[0].event.id).toEqual(user1Calendar1Event1?.id)
expect(res?.data?.events[1].event.id).toEqual(user1Calendar2Event1?.id)
})
})

describe('A user calendar can be queried for availability (freebusy)', () => {
let user1: User | undefined
let user1Calendar1: Calendar | undefined
let user1Calendar1Event1: CalendarEvent | undefined
Expand Down Expand Up @@ -376,11 +448,7 @@ describe('Requirements', () => {
})
})

describe('A user can be in groups', () => {
it.todo('To be implemented')
})

describe('Multiple calendars of the same user can be queried at once', () => {
describe('Multiple calendars of the same user can be queried at once (freebusy)', () => {
let user1: User | undefined
let user1Calendar1: Calendar | undefined
let user1Calendar1Event1: CalendarEvent | undefined
Expand Down
9 changes: 7 additions & 2 deletions scheduler/crates/api/src/event/get_events_by_calendars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ use crate::{

pub async fn get_events_by_calendars_controller(
http_req: HttpRequest,
mut query: web::Query<QueryParams>,
query: web::Query<QueryParams>,
ctx: web::Data<NettuContext>,
) -> Result<HttpResponse, NettuError> {
let account = protect_account_route(&http_req, &ctx).await?;

let calendar_ids = match &query.calendar_ids {
Some(ids) => ids.clone(),
None => vec![],
};

let usecase = GetEventsByCalendarsUseCase {
account_id: account.id,
calendar_ids: std::mem::take(&mut query.calendar_ids),
calendar_ids,
start_time: query.start_time,
end_time: query.end_time,
};
Expand Down
4 changes: 3 additions & 1 deletion scheduler/crates/api_structs/src/event/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ pub mod get_events_by_calendars {
use nettu_scheduler_domain::EventWithInstances;

use super::*;
use crate::helpers::deserialize_uuids_list::deserialize_stringified_uuids_list;

#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct QueryParams {
pub calendar_ids: Vec<ID>,
#[serde(default, deserialize_with = "deserialize_stringified_uuids_list")]
pub calendar_ids: Option<Vec<ID>>,
pub start_time: DateTime<Utc>,
pub end_time: DateTime<Utc>,
}
Expand Down

0 comments on commit 51bf71c

Please sign in to comment.