-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from thoiberg/add-satori
Add Satori API
- Loading branch information
Showing
10 changed files
with
175 additions
and
2 deletions.
There are no files selected for viewing
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 |
---|---|---|
@@ -1,2 +1,3 @@ | ||
WANIKANI_API_TOKEN="<Token goes here>" | ||
BUNPRO_API_TOKEN="<Token goes here>" | ||
BUNPRO_API_TOKEN="<Token goes here>" | ||
SATORI_COOKIE="<Cookie goes here>" |
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,4 @@ | ||
pub mod data; | ||
pub mod request; | ||
|
||
pub use request::satori_handler; |
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,37 @@ | ||
use chrono::{DateTime, Utc}; | ||
|
||
#[derive(serde::Serialize)] | ||
pub struct SatoriData { | ||
data_updated_at: DateTime<Utc>, | ||
active_review_count: u32, | ||
new_card_count: u32, | ||
} | ||
|
||
impl SatoriData { | ||
pub fn new( | ||
current_cards: SatoriCurrentCardsResponse, | ||
new_cards: SatoriNewCardsResponse, | ||
) -> Self { | ||
Self { | ||
data_updated_at: Utc::now(), | ||
active_review_count: current_cards.result, | ||
new_card_count: new_cards.result, | ||
} | ||
} | ||
} | ||
|
||
#[derive(serde::Deserialize)] | ||
pub struct SatoriCurrentCardsResponse { | ||
result: u32, | ||
success: bool, | ||
message: Option<String>, | ||
exception: Option<String>, | ||
} | ||
|
||
#[derive(serde::Deserialize)] | ||
pub struct SatoriNewCardsResponse { | ||
result: u32, | ||
success: bool, | ||
message: Option<String>, | ||
exception: Option<String>, | ||
} |
6 changes: 6 additions & 0 deletions
6
backend/src/api/satori/fixtures/current_cards_with_no_reviews.json
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,6 @@ | ||
{ | ||
"result": 0, | ||
"success": true, | ||
"message": null, | ||
"exception": null | ||
} |
6 changes: 6 additions & 0 deletions
6
backend/src/api/satori/fixtures/current_cards_with_pending_reviews.json
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,6 @@ | ||
{ | ||
"result": 6, | ||
"success": true, | ||
"message": null, | ||
"exception": null | ||
} |
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,6 @@ | ||
{ | ||
"result": 0, | ||
"success": true, | ||
"message": null, | ||
"exception": null | ||
} |
6 changes: 6 additions & 0 deletions
6
backend/src/api/satori/fixtures/new_cards_with_pending_cards.json
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,6 @@ | ||
{ | ||
"result": 20, | ||
"success": true, | ||
"message": null, | ||
"exception": null | ||
} |
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,105 @@ | ||
use std::env; | ||
|
||
use axum::Json; | ||
use reqwest::{Client, StatusCode}; | ||
use tokio::try_join; | ||
|
||
use crate::api::{internal_error, ErrorResponse}; | ||
|
||
use super::data::{SatoriCurrentCardsResponse, SatoriData, SatoriNewCardsResponse}; | ||
|
||
pub async fn satori_handler() -> Result<Json<SatoriData>, (StatusCode, Json<ErrorResponse>)> { | ||
let current_cards = get_current_cards(); | ||
let new_cards = get_new_cards(); | ||
|
||
let (current_cards, new_cards) = try_join!(current_cards, new_cards).map_err(internal_error)?; | ||
|
||
let satori_data = SatoriData::new(current_cards, new_cards); | ||
|
||
Ok(Json(satori_data)) | ||
} | ||
|
||
async fn get_current_cards() -> anyhow::Result<SatoriCurrentCardsResponse> { | ||
let client = satori_client()?; | ||
|
||
client | ||
.get("https://www.satorireader.com/api/studylist/due/count") | ||
.send() | ||
.await? | ||
.text() | ||
.await | ||
.map(|body| serialize_current_cards_response(&body))? | ||
} | ||
|
||
fn serialize_current_cards_response(body: &str) -> anyhow::Result<SatoriCurrentCardsResponse> { | ||
let json_data: SatoriCurrentCardsResponse = serde_json::from_str(body)?; | ||
|
||
Ok(json_data) | ||
} | ||
|
||
async fn get_new_cards() -> anyhow::Result<SatoriNewCardsResponse> { | ||
let client = satori_client()?; | ||
|
||
client | ||
.get("https://www.satorireader.com/api/studylist/pending-auto-importable/count") | ||
.send() | ||
.await? | ||
.text() | ||
.await | ||
.map(|body| serialize_new_cards_response(&body))? | ||
} | ||
|
||
fn serialize_new_cards_response(body: &str) -> anyhow::Result<SatoriNewCardsResponse> { | ||
let json_data: SatoriNewCardsResponse = serde_json::from_str(body)?; | ||
|
||
Ok(json_data) | ||
} | ||
|
||
fn satori_client() -> anyhow::Result<Client> { | ||
let satori_cookie = env::var("SATORI_COOKIE")?; | ||
|
||
let mut headers = reqwest::header::HeaderMap::new(); | ||
headers.insert( | ||
"Cookie", | ||
format!("SessionToken={}", satori_cookie).parse().unwrap(), | ||
); | ||
|
||
Ok(Client::builder().default_headers(headers).build()?) | ||
} | ||
|
||
#[cfg(test)] | ||
mod test_super { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_current_cards_with_pending_reviews() { | ||
let json_string = include_str!("./fixtures/current_cards_with_pending_reviews.json"); | ||
let serialize_result = serialize_current_cards_response(json_string); | ||
|
||
assert!(serialize_result.is_ok()); | ||
} | ||
|
||
#[test] | ||
fn test_current_cards_with_no_reviews() { | ||
let json_string = include_str!("./fixtures/current_cards_with_no_reviews.json"); | ||
let serialize_result = serialize_current_cards_response(json_string); | ||
|
||
assert!(serialize_result.is_ok()); | ||
} | ||
|
||
#[test] | ||
fn test_new_card_with_pending_cards() { | ||
let json_string = include_str!("./fixtures/new_cards_with_pending_cards.json"); | ||
let serialized_result = serialize_new_cards_response(json_string); | ||
|
||
assert!(serialized_result.is_ok()); | ||
} | ||
|
||
#[test] | ||
fn test_new_card_with_no_cards() { | ||
let json_string = include_str!("./fixtures/new_cards_with_no_cards.json"); | ||
let serialized_result = serialize_new_cards_response(json_string); | ||
|
||
assert!(serialized_result.is_ok()); | ||
} | ||
} |
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