From 38bedbaaea3b11b469cfbb25f0bb9aa792d4ef7c Mon Sep 17 00:00:00 2001
From: Paul Makles <paulmakles@gmail.com>
Date: Tue, 2 Feb 2021 19:09:13 +0000
Subject: [PATCH] Add Gravatar support.

---
 Cargo.lock                             | 16 +++++-
 Cargo.toml                             |  4 +-
 src/routes/root.rs                     |  2 +-
 src/routes/users/get_avatar.rs         | 69 ++++++++++++++++----------
 src/routes/users/get_default_avatar.rs | 29 +++++++++++
 src/routes/users/mod.rs                |  2 +
 6 files changed, 94 insertions(+), 28 deletions(-)
 create mode 100644 src/routes/users/get_default_avatar.rs

diff --git a/Cargo.lock b/Cargo.lock
index b0fded2..3d006ee 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1409,6 +1409,12 @@ dependencies = [
  "opaque-debug 0.2.3",
 ]
 
+[[package]]
+name = "md5"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
+
 [[package]]
 name = "memchr"
 version = "2.3.4"
@@ -2365,7 +2371,7 @@ dependencies = [
 
 [[package]]
 name = "revolt"
-version = "0.3.3"
+version = "0.3.3-alpha.0"
 dependencies = [
  "async-std",
  "async-tungstenite",
@@ -2381,6 +2387,7 @@ dependencies = [
  "lettre",
  "log",
  "many-to-many",
+ "md5",
  "mongodb",
  "num_enum",
  "once_cell",
@@ -2397,6 +2404,7 @@ dependencies = [
  "snafu",
  "time 0.2.25",
  "ulid",
+ "urlencoding",
  "validator",
 ]
 
@@ -3398,6 +3406,12 @@ dependencies = [
  "percent-encoding",
 ]
 
+[[package]]
+name = "urlencoding"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9232eb53352b4442e40d7900465dfc534e8cb2dc8f18656fcb2ac16112b5593"
+
 [[package]]
 name = "utf-8"
 version = "0.7.5"
diff --git a/Cargo.toml b/Cargo.toml
index 80fbcb6..eb0080f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "revolt"
-version = "0.3.3"
+version = "0.3.3-alpha.0"
 authors = ["Paul Makles <paulmakles@gmail.com>"]
 edition = "2018"
 
@@ -33,11 +33,13 @@ serde_json = "1.0.57"
 bitfield = "0.13.2"
 
 reqwest = { version = "0.10.8", features = ["json"] }
+urlencoding = "1.1.1"
 lazy_static = "1.4.0"
 num_enum = "0.5.1"
 chrono = "0.4.15"
 time = "0.2.16"
 rand = "0.7.3"
+md5 = "0.7.0"
 regex = "1"
 
 lettre = "0.10.0-alpha.1"
diff --git a/src/routes/root.rs b/src/routes/root.rs
index 7c613f9..aa67259 100644
--- a/src/routes/root.rs
+++ b/src/routes/root.rs
@@ -8,7 +8,7 @@ use rocket_contrib::json::JsonValue;
 #[get("/")]
 pub async fn root() -> JsonValue {
     json!({
-        "revolt": "0.3.2",
+        "revolt": "0.3.3-alpha.0",
         "features": {
             "registration": !*DISABLE_REGISTRATION,
             "captcha": {
diff --git a/src/routes/users/get_avatar.rs b/src/routes/users/get_avatar.rs
index 4e5859f..e85e806 100644
--- a/src/routes/users/get_avatar.rs
+++ b/src/routes/users/get_avatar.rs
@@ -1,29 +1,48 @@
-use rocket::response::NamedFile;
-use std::path::Path;
+use mongodb::options::FindOneOptions;
+use rocket::response::Redirect;
+use mongodb::bson::doc;
+use urlencoding;
+use md5;
 
-use crate::database::Ref;
+use crate::util::result::{Error, Result};
+use crate::util::variables::PUBLIC_URL;
+use crate::database::*;
 
 #[get("/<target>/avatar")]
-pub async fn req(target: Ref) -> Option<NamedFile> {
-    match target.id.chars().nth(25).unwrap() {
-        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => {
-            NamedFile::open(Path::new("assets/user_red.png")).await.ok()
-        }
-        '8' | '9' | 'A' | 'C' | 'B' | 'D' | 'E' | 'F' => {
-            NamedFile::open(Path::new("assets/user_green.png"))
-                .await
-                .ok()
-        }
-        'G' | 'H' | 'J' | 'K' | 'M' | 'N' | 'P' | 'Q' => {
-            NamedFile::open(Path::new("assets/user_blue.png"))
-                .await
-                .ok()
-        }
-        'R' | 'S' | 'T' | 'V' | 'W' | 'X' | 'Y' | 'Z' => {
-            NamedFile::open(Path::new("assets/user_yellow.png"))
-                .await
-                .ok()
-        }
-        _ => unreachable!(),
-    }
+pub async fn req(target: Ref) -> Result<Redirect> {
+    let doc = get_collection("accounts")
+        .find_one(
+            doc! {
+                "_id": &target.id
+            },
+            FindOneOptions::builder()
+                .projection(doc! { "email": 1 })
+                .build()
+        )
+        .await
+        .map_err(|_| Error::DatabaseError { operation: "find_one", with: "user" })?
+        .ok_or_else(|| Error::UnknownUser)?;
+    
+    let email = doc
+        .get_str("email")
+        .map_err(|_| Error::DatabaseError { operation: "get_str(email)", with: "user" })?
+        .to_lowercase();
+
+        let url = format!(
+            "https://www.gravatar.com/avatar/{:x}?s=128&d={}",
+            md5::compute(email),
+            urlencoding::encode(
+                &format!(
+                    "{}/users/{}/default_avatar",
+                    *PUBLIC_URL,
+                    &target.id
+                )
+            )
+        );
+
+        dbg!(&url);
+
+    Ok(
+        Redirect::to(url)
+    )
 }
diff --git a/src/routes/users/get_default_avatar.rs b/src/routes/users/get_default_avatar.rs
new file mode 100644
index 0000000..4e46c73
--- /dev/null
+++ b/src/routes/users/get_default_avatar.rs
@@ -0,0 +1,29 @@
+use rocket::response::NamedFile;
+use std::path::Path;
+
+use crate::database::Ref;
+
+#[get("/<target>/default_avatar")]
+pub async fn req(target: Ref) -> Option<NamedFile> {
+    match target.id.chars().nth(25).unwrap() {
+        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => {
+            NamedFile::open(Path::new("assets/user_red.png")).await.ok()
+        }
+        '8' | '9' | 'A' | 'C' | 'B' | 'D' | 'E' | 'F' => {
+            NamedFile::open(Path::new("assets/user_green.png"))
+                .await
+                .ok()
+        }
+        'G' | 'H' | 'J' | 'K' | 'M' | 'N' | 'P' | 'Q' => {
+            NamedFile::open(Path::new("assets/user_blue.png"))
+                .await
+                .ok()
+        }
+        'R' | 'S' | 'T' | 'V' | 'W' | 'X' | 'Y' | 'Z' => {
+            NamedFile::open(Path::new("assets/user_yellow.png"))
+                .await
+                .ok()
+        }
+        _ => unreachable!(),
+    }
+}
diff --git a/src/routes/users/mod.rs b/src/routes/users/mod.rs
index b80ce7d..2a0cd2f 100644
--- a/src/routes/users/mod.rs
+++ b/src/routes/users/mod.rs
@@ -7,6 +7,7 @@ mod fetch_relationship;
 mod fetch_relationships;
 mod fetch_user;
 mod get_avatar;
+mod get_default_avatar;
 mod open_dm;
 mod remove_friend;
 mod unblock_user;
@@ -15,6 +16,7 @@ pub fn routes() -> Vec<Route> {
     routes![
         // User Information
         fetch_user::req,
+        get_default_avatar::req,
         get_avatar::req,
         // Direct Messaging
         fetch_dms::req,
-- 
GitLab