-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add route for searching events (#144)
* feat: add route for searching events * chore: generate TS types * fix: small fixes here and there * chore: rename * chore: rename (2) * fix: regen types
- Loading branch information
1 parent
038304f
commit ad97707
Showing
20 changed files
with
512 additions
and
4 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | ||
|
||
/** | ||
* Query parameters for searching on a date time | ||
*/ | ||
export type DateTimeQuery = { | ||
/** | ||
* Optional "greater than or equal" query (UTC) | ||
*/ | ||
gte?: Date | ||
/** | ||
* Optional "less than or equal" query (UTC) | ||
*/ | ||
lte?: Date | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | ||
|
||
/** | ||
* Query parameters for searching on an ID | ||
*/ | ||
export type IDQuery = { | ||
/** | ||
* Optional String (equality test) | ||
* This is not a UUID, but a string as we allow any type of ID in this field | ||
*/ | ||
eq?: string | ||
/** | ||
* Optional bool (existence test) | ||
* If "eq" is provided, this field is ignored | ||
*/ | ||
exists?: boolean | ||
} |
12 changes: 12 additions & 0 deletions
12
clients/javascript/lib/gen_types/SearchEventsAPIResponse.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | ||
import type { CalendarEventDTO } from './CalendarEventDTO' | ||
|
||
/** | ||
* API response for getting events by calendars | ||
*/ | ||
export type SearchEventsAPIResponse = { | ||
/** | ||
* List of calendar events retrieved | ||
*/ | ||
events: Array<CalendarEventDTO> | ||
} |
44 changes: 44 additions & 0 deletions
44
clients/javascript/lib/gen_types/SearchEventsRequestBody.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. | ||
import type { DateTimeQuery } from './DateTimeQuery' | ||
import type { ID } from './ID' | ||
import type { IDQuery } from './IDQuery' | ||
import type { JsonValue } from './serde_json/JsonValue' | ||
|
||
/** | ||
* Query parameters for searching events | ||
*/ | ||
export type SearchEventsRequestBody = { | ||
/** | ||
* User ID | ||
*/ | ||
userId: ID | ||
/** | ||
* Optional list of calendar UUIDs | ||
* If not provided, all calendars will be used | ||
*/ | ||
calendarIds?: Array<ID> | ||
/** | ||
* Optional query on parent ID | ||
*/ | ||
parentId?: IDQuery | ||
/** | ||
* Optional query on start time - "lower than or equal", or "great than or equal" (UTC) | ||
*/ | ||
startTime?: DateTimeQuery | ||
/** | ||
* Optional query on end time - "lower than or equal", or "great than or equal" (UTC) | ||
*/ | ||
endTime?: DateTimeQuery | ||
/** | ||
* Optional list of event status | ||
*/ | ||
status?: Array<string> | ||
/** | ||
* Optioanl query on updated at - "lower than or equal", or "great than or equal" (UTC) | ||
*/ | ||
updatedAt?: DateTimeQuery | ||
/** | ||
* Optional list of metadata key-value pairs | ||
*/ | ||
metadata?: JsonValue | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
use actix_web::{web, HttpRequest, HttpResponse}; | ||
use nittei_api_structs::{dtos::CalendarEventDTO, search_events::*}; | ||
use nittei_domain::{DateTimeQuery, IDQuery, ID}; | ||
use nittei_infra::{NitteiContext, SearchEventsParams}; | ||
|
||
use crate::{ | ||
error::NitteiError, | ||
shared::{ | ||
auth::protect_account_route, | ||
usecase::{execute, UseCase}, | ||
}, | ||
}; | ||
|
||
pub async fn search_events_controller( | ||
http_req: HttpRequest, | ||
body: actix_web_validator::Json<RequestBody>, | ||
ctx: web::Data<NitteiContext>, | ||
) -> Result<HttpResponse, NitteiError> { | ||
let account = protect_account_route(&http_req, &ctx).await?; | ||
|
||
let body = body.0; | ||
let usecase = SearchEventsUseCase { | ||
account_id: account.id, | ||
user_id: body.user_id, | ||
calendar_ids: body.calendar_ids, | ||
parent_id: body.parent_id, | ||
start_time: body.start_time, | ||
end_time: body.end_time, | ||
status: body.status, | ||
updated_at: body.updated_at, | ||
metadata: body.metadata, | ||
}; | ||
|
||
execute(usecase, &ctx) | ||
.await | ||
.map(|events| HttpResponse::Ok().json(APIResponse::new(events.events))) | ||
.map_err(NitteiError::from) | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct SearchEventsUseCase { | ||
/// Account ID | ||
pub account_id: ID, | ||
|
||
/// User ID | ||
pub user_id: ID, | ||
|
||
/// Optional list of calendar UUIDs | ||
/// If not provided, all calendars will be used | ||
pub calendar_ids: Option<Vec<ID>>, | ||
|
||
/// Optional query on parent ID | ||
pub parent_id: Option<IDQuery>, | ||
|
||
/// Optional query on start time - "lower than or equal", or "great than or equal" (UTC) | ||
pub start_time: Option<DateTimeQuery>, | ||
|
||
/// Optional query on end time - "lower than or equal", or "great than or equal" (UTC) | ||
pub end_time: Option<DateTimeQuery>, | ||
|
||
/// Optional list of event status | ||
pub status: Option<Vec<String>>, | ||
|
||
/// Optioanl query on updated at - "lower than or equal", or "great than or equal" (UTC) | ||
pub updated_at: Option<DateTimeQuery>, | ||
|
||
/// Optional list of metadata key-value pairs | ||
pub metadata: Option<serde_json::Value>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct UseCaseResponse { | ||
pub events: Vec<CalendarEventDTO>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum UseCaseError { | ||
InternalError, | ||
BadRequest(String), | ||
NotFound(String, String), | ||
} | ||
|
||
impl From<UseCaseError> for NitteiError { | ||
fn from(e: UseCaseError) -> Self { | ||
match e { | ||
UseCaseError::InternalError => Self::InternalError, | ||
UseCaseError::BadRequest(msg) => Self::BadClientData(msg), | ||
UseCaseError::NotFound(entity, event_id) => Self::NotFound(format!( | ||
"The {} with id: {}, was not found.", | ||
entity, event_id | ||
)), | ||
} | ||
} | ||
} | ||
|
||
#[async_trait::async_trait(?Send)] | ||
impl UseCase for SearchEventsUseCase { | ||
type Response = UseCaseResponse; | ||
|
||
type Error = UseCaseError; | ||
|
||
const NAME: &'static str = "SearchEvents"; | ||
|
||
async fn execute(&mut self, ctx: &NitteiContext) -> Result<UseCaseResponse, UseCaseError> { | ||
if let Some(calendar_ids) = &self.calendar_ids { | ||
if calendar_ids.is_empty() { | ||
return Err(UseCaseError::BadRequest( | ||
"calendar_ids cannot be empty".into(), | ||
)); | ||
} | ||
|
||
let calendars = ctx | ||
.repos | ||
.calendars | ||
.find_multiple(calendar_ids.iter().collect()) | ||
.await | ||
.map_err(|_| UseCaseError::InternalError)?; | ||
|
||
// Check that all calendars exist and belong to the same account | ||
if calendars.is_empty() | ||
|| calendars.len() != calendar_ids.len() | ||
|| !calendars | ||
.iter() | ||
.all(|cal| cal.account_id == self.account_id) | ||
{ | ||
return Err(UseCaseError::NotFound( | ||
"Calendars not found".to_string(), | ||
calendar_ids | ||
.iter() | ||
.map(|c| c.to_string()) | ||
.collect::<Vec<String>>() | ||
.join(","), | ||
)); | ||
} | ||
} | ||
|
||
let res = ctx | ||
.repos | ||
.events | ||
.search_events(SearchEventsParams { | ||
user_id: self.user_id.clone(), | ||
calendar_ids: self.calendar_ids.clone(), | ||
parent_id: self.parent_id.clone(), | ||
start_time: self.start_time.clone(), | ||
end_time: self.end_time.clone(), | ||
status: self.status.clone(), | ||
updated_at: self.updated_at.clone(), | ||
metadata: self.metadata.clone(), | ||
}) | ||
.await; | ||
|
||
match res { | ||
Ok(events) => Ok(UseCaseResponse { | ||
events: events.into_iter().map(CalendarEventDTO::new).collect(), | ||
}), | ||
Err(_) => Err(UseCaseError::InternalError), | ||
} | ||
} | ||
} |
Oops, something went wrong.