~statianzo/classdojo

d89ee00a8288a859bcc2a9ebd145bdf3921c96c9 — Jason Staten 3 years ago fc85e48 master
POC works
3 files changed, 169 insertions(+), 12 deletions(-)

M .gitignore
A example/feed.json
M src/main.rs
M .gitignore => .gitignore +2 -0
@@ 1,2 1,4 @@
/target
**/*.rs.bk
.DS_Store
out

A example/feed.json => example/feed.json +106 -0
@@ 0,0 1,106 @@
{
  "_items": [
    {
      "_id": "111111111111111111111",
      "time": "2019-01-01T00:00:00.000Z",
      "targetId": "123targetit",
      "targetType": "school",
      "senderId": "123senderid",
      "pending": false,
      "private": false,
      "scheduled": false,
      "headerText": "Dr. Doctor",
      "headerSubtext": "The Academy",
      "headerAvatarURL": "https://images.classdojo.com/dojoprofilephotos/xyz.jpg",
      "senderName": "Dr. Doctor",
      "tags": [],
      "read": true,
      "likeButton": "unliked",
      "commentButton": "disabled",
      "canDelete": false,
      "canEdit": false,
      "readCount": 0,
      "likeCount": 5,
      "commentCount": 0,
      "type": "textAndAttachment",
      "contents": {
        "body": "What a great body this is",
        "attachments": [
          {
            "contentType": "image/jpeg",
            "path": "https://images.classdojo.com/dojophotos/def.jpg",
            "metadata": { "width": 1000, "height": 1000 },
            "type": "photo",
            "_id": "123attachmentid"
          }
        ],
        "sentLanguage": "en",
        "translation": null
      },
      "webview": {
        "url": "https://mw.classdojo.com/story/test",
        "approximateHeight": 100
      }
    }
  ],
  "_metadata": {
    "postsExist": true,
    "expiresAfter": 0,
    "availableTranslations": [
      "af",
      "am",
      "ar",
      "be",
      "bg",
      "bn",
      "ca",
      "cs",
      "cy",
      "da",
      "de",
      "el",
      "en",
      "es",
      "et",
      "eu",
      "fa",
      "fi",
      "fr",
      "ga",
      "gl",
      "hi",
      "hr",
      "hu",
      "id",
      "it",
      "ja",
      "kk",
      "ko",
      "lt",
      "lv",
      "ml",
      "ms",
      "nl",
      "pl",
      "pt",
      "ro",
      "ru",
      "sk",
      "sl",
      "sr",
      "sv",
      "sw",
      "ta",
      "te",
      "th",
      "tr",
      "uk",
      "vi",
      "zh-CN",
      "zh-TW",
      "zh",
      "zu"
    ]
  },
  "_links": {}
}

M src/main.rs => src/main.rs +61 -12
@@ 1,6 1,17 @@
use reqwest::Client;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::env;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::path::Path;

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct Credentials<'a> {
    login: &'a str,
    password: &'a str,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]


@@ 34,20 45,58 @@ struct Feed {
    items: Vec<FeedItem>,
}

fn authenticate() {}
fn fetch_feed(client: &Client) -> Result<Feed, reqwest::Error> {
    client
        .get("https://home.classdojo.com/api/storyFeed?includePrivate=true")
        .send()?
        .json::<Feed>()
}

fn authenticate(
    client: &Client,
    credentials: &Credentials,
) -> Result<reqwest::StatusCode, reqwest::Error> {
    let response = client
        .post("https://home.classdojo.com/api/session")
        .json(&credentials)
        .send()?;
    Ok(response.status())
}

fn fetch_attachment(client: &Client, attachment: &FeedAttachment) -> Result<(), Box<dyn Error>> {
    let raw_path = &format!("out/{}.jpg", attachment.id);
    let path = Path::new(raw_path);
    if path.exists() {
        return Ok(());
    }

    let mut file = File::create(path)?;
    let mut response = client.get(&attachment.path).send()?;
    response.copy_to(&mut file)?;
    Ok(())
}

fn process_feed(client: &Client, feed: Feed) {
    for item in feed.items {
        for attachment in item.contents.attachments {
            if let Err(e) = fetch_attachment(&client, &attachment) {
                println!("Failed to save attachment {}. {}", &attachment.id, e);
                return;
            }
        }
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let client = Client::builder().cookie_store(true).build()?;
    let feed: Feed = client
        .get("http://localhost:2015/feed.json")
        .send()?
        .json()?;
    println!("{:?}", feed);
    let feed2: Feed = client
        .get("http://localhost:2015/feed.json")
        .send()?
        .json()?;
    println!("{:?}", feed2);
    let credentials = Credentials {
        login: &env::var("CLASSDOJO_LOGIN")?,
        password: &env::var("CLASSDOJO_PASSWORD")?,
    };
    authenticate(&client, &credentials)?;
    let feed = fetch_feed(&client)?;
    fs::create_dir_all("out")?;
    process_feed(&client, feed);

    Ok(())
}