-
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.
feat: Add tasks from Epitaf's API (#3)
* feat: Add tasks from Epitaf's API * refresh everything every 6 hours and better env handling
- Loading branch information
Showing
9 changed files
with
225 additions
and
14 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
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,71 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::db::DatabaseConnection; | ||
use crate::data::{DataResult, DataError}; | ||
use crate::user::User; | ||
use crate::user::epitaf::{Task, fetch_tasks}; | ||
|
||
#[derive(Clone, Serialize, Deserialize)] | ||
struct PromoTask { | ||
#[serde(rename = "_key")] | ||
promo: String, | ||
tasks: Vec<Task> | ||
} | ||
|
||
pub async fn get_tasks(db: &DatabaseConnection, user: &User) -> DataResult<Vec<Task>> { | ||
let all = get_promos_tasks(db, user).await?; | ||
Ok(all.tasks) | ||
} | ||
|
||
pub async fn refresh_tasks_db(db: &DatabaseConnection) -> DataResult<()> { | ||
let tasks = fetch_tasks().await; | ||
match tasks { | ||
Ok(t) => { | ||
let mut sorted_tasks: Vec<PromoTask> = Vec::new(); | ||
for task in t { | ||
if task.visibility.ne("promotion".into()) { | ||
continue; | ||
} | ||
let check_promo = sorted_tasks | ||
.iter() | ||
.position(|t| t.promo == task.promotion.to_string()); | ||
if let Some(p) = check_promo { | ||
sorted_tasks[p].tasks.push(task); | ||
} else { | ||
sorted_tasks.push( | ||
PromoTask { | ||
promo: task.promotion.to_string(), | ||
tasks: Vec::new() | ||
} | ||
); | ||
if let Some (pt) = sorted_tasks.last_mut() { | ||
pt.tasks.push(task); | ||
} | ||
} | ||
} | ||
for st in sorted_tasks { | ||
db.add_or_replace("tasks", st).await?; | ||
} | ||
return Ok(()) | ||
}, | ||
Err(error) => { | ||
return Err(DataError::EpitafError { error }); | ||
} | ||
} | ||
} | ||
|
||
async fn get_promos_tasks(db: &DatabaseConnection, user: &User) -> DataResult<PromoTask> { | ||
match db.get::<PromoTask>("tasks", &user.cri_user.promo).await? { | ||
Some(m) => Ok(m), | ||
None => { | ||
let promo_task = PromoTask { | ||
promo: user.cri_user.promo.clone(), | ||
tasks: Vec::new() | ||
}; | ||
|
||
db.add("tasks", &promo_task).await?; | ||
|
||
Ok(promo_task) | ||
} | ||
} | ||
} |
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,95 @@ | ||
use chrono::{DateTime, Utc}; | ||
use serde::{Deserialize, Serialize}; | ||
use failure::Fail; | ||
use reqwest::{Client as HttpClient, Error as HttpError}; | ||
|
||
use crate::config::CONFIG; | ||
|
||
#[derive(Clone, Serialize, Deserialize)] | ||
pub struct Task { | ||
pub created_at: DateTime<Utc>, | ||
pub updated_at: DateTime<Utc>, | ||
pub short_id: String, | ||
pub visibility: String, | ||
pub promotion: u16, | ||
pub semester: Option<String>, | ||
pub class: Option<String>, | ||
pub region: Option<String>, | ||
pub title: String, | ||
pub subject: String, | ||
pub content: String, | ||
pub due_date: DateTime<Utc>, | ||
pub created_by_login: String, | ||
pub created_by: String, | ||
pub updated_by_login: Option<String>, | ||
pub updated_by: Option<String>, | ||
} | ||
|
||
#[derive(Deserialize)] | ||
struct LoginResult { | ||
token: String | ||
} | ||
|
||
type EpitafResult<T> = Result<T, EpitafError>; | ||
|
||
pub async fn fetch_tasks() -> EpitafResult<Vec<Task>> { | ||
let jwt = get_jwt().await?; | ||
|
||
let http = HttpClient::new(); | ||
let url = format!("{}/tasks", CONFIG.epitaf_url); | ||
let res = http.get(&url) | ||
.header("Accept", "application/json") | ||
.bearer_auth(jwt) | ||
.send().await? | ||
.text().await?; | ||
|
||
let value: Vec<Task> = serde_json::from_str(&res) | ||
.map_err(move |e| EpitafError::RemoteError { | ||
method: "get".into(), | ||
url, | ||
request: String::new(), | ||
response: res, | ||
error: e | ||
})?; | ||
|
||
Ok(value) | ||
} | ||
|
||
async fn get_jwt() -> EpitafResult<String> { | ||
let http = HttpClient::new(); | ||
let url = format!("{}/users/callback", CONFIG.epitaf_url); | ||
let res = http.post(&url) | ||
.bearer_auth(&CONFIG.epitaf_token) | ||
.send().await? | ||
.text().await?; | ||
|
||
let value: LoginResult = serde_json::from_str(&res) | ||
.map_err(move |e| EpitafError::RemoteError { | ||
method: "post".into(), | ||
url, | ||
request: String::new(), | ||
response: res, | ||
error: e | ||
})?; | ||
|
||
Ok(value.token) | ||
} | ||
|
||
#[derive(Fail, Debug)] | ||
pub enum EpitafError { | ||
#[fail(display = "HTTP error during request")] | ||
HttpError { | ||
error: HttpError | ||
}, | ||
|
||
#[fail(display = "Microsoft request was rejected")] | ||
RemoteError { | ||
method: String, | ||
url: String, | ||
request: String, | ||
response: String, | ||
error: serde_json::Error | ||
} | ||
} | ||
|
||
from_error!(reqwest::Error, EpitafError, EpitafError::HttpError); |
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,8 @@ | ||
pub fn is_env_enable(env_name: &str) -> bool { | ||
match std::env::var(env_name) { | ||
Ok(s) => { | ||
vec!["1", "true", "yes", "oui"].contains(&s.to_lowercase().as_str()) | ||
}, | ||
Err(_) => false | ||
} | ||
} |