jake kalstad 9 年之前
當前提交
60660ddc7b
共有 16 個文件被更改,包括 1514 次插入0 次删除
  1. 29 0
      Cargo.toml
  2. 58 0
      README.md
  3. 154 0
      e2e.js
  4. 148 0
      src/appointment.rs
  5. 7 0
      src/base.rs
  6. 31 0
      src/cache.rs
  7. 41 0
      src/db.rs
  8. 12 0
      src/echo.rs
  9. 101 0
      src/image.rs
  10. 5 0
      src/lib.rs
  11. 182 0
      src/main.rs
  12. 119 0
      src/price.rs
  13. 112 0
      src/product.rs
  14. 129 0
      src/session.rs
  15. 179 0
      src/sql.rs
  16. 207 0
      src/user.rs

+ 29 - 0
Cargo.toml

@@ -0,0 +1,29 @@
+[package]
+authors = ["jake"]
+name = "Rusty Rest"
+version = "0.1.0"
+
+[dependencies]
+bodyparser = "^0.4.1"
+futures = "^0.1.1"
+hyper = "^0.9.10"
+iron = "^0.4.0"
+memcached-rs = "^0.1.2"
+persistent = "^0.2.0"
+postgres = "^0.11.11"
+r2d2 = "*"
+r2d2_postgres = "*"
+r2d2_redis = { path = "../r2d2-redis" }
+redis = "*"
+regex = "^0.1.73"
+rmp = "^0.7.5"
+rustc-serialize = "^0.3"
+serde = "^0.8"
+serde_json = "^0.8"
+serde_derive = "^0.8"
+url = "^1.2.0"
+uuid = { version = "^0.3", features = ["serde", "v4"] }
+staticfile = "*"
+mount = "*"
+router = "*"
+

+ 58 - 0
README.md

@@ -0,0 +1,58 @@
+# USE MORE RUST
+  An implementation of a restful crud service in rust as a POC.
+![](http://i.imgur.com/nZBHDNp.gif)
+### Tech
+
+* [Postgressql]
+* [Redis]
+(cargo.toml is looking for r2d2-redis locally, snag a copy from -> https://github.com/sorccu/r2d2-redis)
+# API 
+### cargo run --verbose -- 3000 postgres://postgres:toor@127.0.0.1:5432/data 
+  User object represents both users and vendors
+```
+curl -XPOST 127.0.0.1:3000/user -H "application/json" -d '{"id":"","name":"jake","password":"super secret", "email":"jake@jake.com","phone":"1239567","active":1,"products":[]}'
+
+curl 127.0.0.1:3000/user/key-goes-here
+
+curl 127.0.0.1:3000/users
+```
+
+## product 
+  Product object represents a ... product
+```
+curl -XPOST 127.0.0.1:3000/product -H "application/json" -d '{"id":"", "name":"MOUNTAIN DEWWWW", "price":"", "images":[]}'
+
+curl 127.0.0.1:3000/product/key-goes-here
+
+curl 127.0.0.1:3000/products
+```
+
+## image 
+  Image objects for users and products
+```
+curl -XPOST 127.0.0.1:3000/image -H "application/json" -d '{"id":"", "name":"Super dope haircut", "url":"http://i.imgur.com/oOtZe.jpg"}'
+
+curl 127.0.0.1:3000/image/key-goes-here
+
+curl 127.0.0.1:3000/images
+```
+
+## price 
+  Price for products
+```
+curl -XPOST 127.0.0.1:3000/price -H "application/json" -d '{"id":"", "user_id":"xxx", "product_id":"zzzz", "currency_code":"USD", "price":34}'
+
+curl 127.0.0.1:3000/price/key-goes-here
+
+curl 127.0.0.1:3000/prices
+```
+
+## appointment 
+  Appointment to exchance goods/services
+```
+curl -XPOST 127.0.0.1:3000/appointment -H "application/json" -d '{"id":"", "name":"xxx", "time":147324123, "confirmed":true, "user_id":"xxxx", "vendor_id":"xxxx", "product_id":"xxxx", "price_id":"xxxx"}'
+
+curl 127.0.0.1:3000/appointment/key-goes-here
+
+curl 127.0.0.1:3000/appointments
+``` 

+ 154 - 0
e2e.js

@@ -0,0 +1,154 @@
+var http = require('http');
+
+var verbose = false;
+if (process.argv.length >= 2) {
+    verbose = process.argv[2] === "v" || process.argv[2] === "verbose";
+}
+
+function _get(host, path, callback) {
+    return http.get({
+        host: "127.0.0.1",
+        port: "3000",
+        path: "/" + path + "/",
+    }, function(response) {
+        var body = '';
+        response.on('data', function(d) {
+            body += d;
+        });
+        response.on('end', function() {
+            callback({ 
+                result: JSON.parse(body)
+            });
+        });
+    });
+};
+
+function _post(host, path, data, callback) {
+    var options = {
+        host: "127.0.0.1",
+        port: "3000",
+        path: "/"+path+"/",
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json'
+        }
+    };
+    var postReq = http.request(options, function(res) {
+        var body = '';
+        res.on('data', function(d) {
+            body += d;
+        });
+        res.on('end', function() {
+            callback({ 
+                result: JSON.parse(body)
+            });
+        });
+    });
+    postReq.write(JSON.stringify(data));
+    postReq.end();
+};
+
+function client(path) {
+    var ip = "localhost:3000";
+    return {
+        get: function(callback) {
+            _get(ip, path, callback);
+        },
+        post: function(data, callback) {
+            _post(ip, path, data, callback);
+        }
+    }
+}
+
+function result(pass, data, msg, raw) {
+    this.pass = pass;
+    this.data = data;
+    this.msg = msg;
+    this.raw = raw;
+    this.format = function() {
+        return (this.pass ? "Success ::" : "Fail    ::" ) +this.msg+ ":::"+
+                (verbose ? ("data: " + JSON.stringify(this.data)) + 
+                "raw: " + JSON.stringify(this.raw) : "");
+    };
+}
+
+function testInsert(data, svc_name, cb) {
+    var svc = client(svc_name);
+    if (data.length > 0) {
+        var results = [];
+        for (var i=0;i<data.length;i++) {
+            svc.post(data[i], function (res) {
+                var test_result = new result(res.result.id.length > 0, res.result, "Put " + svc_name, res)
+                results.push(test_result)
+                if (results.length == data.length) {
+                    cb({results:results})
+                }
+            })
+        }
+    } else {
+        svc.post(data, function (res) {
+            var test_result = new result(res.result.id.length > 0, res.result, "Put " + svc_name, res)
+            cb(test_result)
+        })
+    }
+}
+
+function testGet(svc_name, key, cb) {
+    var path = key.length == 0 ? svc_name+'s' : (svc_name + "/" + key )
+    var svc = client(path);
+    svc.get(function (res) {
+        var pass = res.result.length > 0 || (res.result.id.length > 0 && res.result.id == key)
+        var test_result = new result(pass, res.result, "Get " + svc_name, res)
+        cb(test_result)
+    })
+} 
+
+
+
+var user = {"id":"","name":"jake","lname":"jakeson","dob":"147324123","password":"super secret", "email":"jake@jake.com","phone":"1239567","active":1,"products":[]};
+var product = {"id":"", "name":"MOUNTAIN DEWWWW", "price":"", "images":[]};
+var products = [product, {"id":"", "name":"CRACK ROX", "price":"", "images":[]}];
+var image = {"id":"", "name":"Super dope haircut", "url":"http://i.imgur.com/oOtZe.jpg"};
+var price = {"id":"", "user_id":"xxx", "product_id":"zzzz", "currency_code":"USD", "price":34};
+var appointment = {"id":"", "name":"xxx", "time":147324123, "confirmed":true, "user_id":"xxxx", "vendor_id":"xxxx", "product_id":"xxxx", "price_id":"xxxx"};
+var session = {"id":"", "user_id":"1", "data":"{root:1}","created":""};
+
+function T(res) { for (var i=0;i<res.length;i++) { console.log(res[i].format()); }} 
+function TS(svc_name, data) { 
+    return function(callback) {
+        testInsert(data, svc_name, function (insertResult) {
+            if (insertResult.results) {
+                for (var i = 0; i < insertResult.results.length; i++) {
+                    testGet(svc_name, insertResult.results[i].data.id, function (getResult) {
+                        testGet(svc_name, "", function (getManyResult) {
+                            if (i == insertResult.results.length) {
+                                callback(insertResult.results.concat([getResult, getManyResult]))
+                            }
+                        });
+                    });
+                }
+            } else {
+                testGet(svc_name, insertResult.data.id, function (getResult) {
+                    testGet(svc_name, "", function (getManyResult) {
+                        callback([insertResult, getResult, getManyResult])
+                    });
+                });
+            }
+        });
+    }
+}
+
+http.get({
+        host: "127.0.0.1",
+        port: "3000",
+        path: "/reset",
+    }, function(response) {
+        TS("user", user)(T);
+        TS("image", image)(T);
+        TS("price", price)(T);
+        TS("product", product)(T);
+        TS("product", products)(T);
+        TS("appointment", appointment)(T);
+        TS("session", session)(T);
+});
+

+ 148 - 0
src/appointment.rs

@@ -0,0 +1,148 @@
+extern crate iron;
+
+extern crate bodyparser;
+extern crate persistent;
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate serde;
+extern crate serde_json;
+extern crate uuid;
+
+use uuid::Uuid;
+use serde::{Deserialize, Deserializer};
+
+use sql;
+use product;
+use db;
+
+use persistent::Read;
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+
+
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct Appointment {
+    id: String,
+    name: String,
+    time: i64,
+    confirmed: bool,
+    user_id: String,
+    vendor_id: String,
+    product_id: String,
+    price_id: String,
+}
+
+impl Appointment {
+    pub fn new(id: String,
+               name: String,
+               time: i64,
+               confirmed: bool,
+               user_id: String,
+               vendor_id: String,
+               product_id: String,
+               price_id: String)
+               -> Appointment {
+        Appointment {
+            id: id,
+            name: name,
+            time: time,
+            confirmed: confirmed,
+            user_id: user_id,
+            vendor_id: vendor_id,
+            product_id: product_id,
+            price_id: price_id,
+        }
+    }
+}
+pub fn put(req: &mut Request) -> IronResult<Response> {
+    let appointment = req.get::<bodyparser::Struct<Appointment>>();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match appointment {
+        Ok(Some(appointment)) => {
+            let pool = req.get::<Read<db::AppDb>>().unwrap();
+            let conn = pool.get().unwrap();
+            let isNew = appointment.id.len() == 0;
+            let new_id = match isNew {
+                true => Uuid::new_v4().to_string(),
+                _ => appointment.id.to_owned(),
+            };
+            conn.execute(sql::SQL_UPSERTAPPOINTMENT,
+                         &[&new_id,
+                           &appointment.name,
+                           &appointment.time,
+                           &appointment.confirmed,
+                           &appointment.user_id,
+                           &appointment.vendor_id,
+                           &appointment.product_id,
+                           &appointment.price_id])
+                .unwrap();
+            let resp = Appointment::new(new_id,
+                                        appointment.name,
+                                        appointment.time,
+                                        appointment.confirmed,
+                                        appointment.user_id,
+                                        appointment.vendor_id,
+                                        appointment.product_id,
+                                        appointment.price_id);
+            response = serde_json::to_string(&resp).unwrap();
+        }
+        Ok(None) => {
+            stat = status::BadRequest;
+        }
+        Err(err) => {
+            println!("{:?}", err);
+            stat = status::InternalServerError;
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get(req: &mut Request) -> IronResult<Response> {
+    let pool = req.get::<Read<db::AppDb>>().unwrap();
+    let path = req.url.path();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match path.len() >= 2 {
+        true => {
+            let id = req.url.path()[1];
+            let conn = pool.get().unwrap();
+            for row in conn.query(sql::SQL_GETAPPOINTMENT, &[&id]).unwrap().iter() {
+                let appointment = Appointment::new(row.get(0),
+                                                   row.get(1),
+                                                   row.get(2),
+                                                   row.get(3),
+                                                   row.get(4),
+                                                   row.get(5),
+                                                   row.get(6),
+                                                   row.get(7));
+                response = serde_json::to_string(&appointment).unwrap();
+            }
+        }
+        _ => {
+            stat = status::BadRequest;
+            response = String::from("No key found")
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get_all(req: &mut Request) -> IronResult<Response> {
+    let conn = req.get::<Read<db::AppDb>>().unwrap().get().unwrap();
+    let path = req.url.path();
+    let mut appointments = Vec::new();
+    for row in &conn.query(sql::SQL_GETAPPOINTMENTS, &[]).expect("Shit the bed") {
+        let appointment = Appointment::new(row.get(0),
+                                           row.get(1),
+                                           row.get(2),
+                                           row.get(3),
+                                           row.get(4),
+                                           row.get(5),
+                                           row.get(6),
+                                           row.get(7));
+        appointments.push(appointment);
+    }
+    Ok(Response::with((status::Ok, serde_json::to_string(&appointments).unwrap())))
+}

+ 7 - 0
src/base.rs

@@ -0,0 +1,7 @@
+
+use std::ascii::AsciiExt;
+
+pub fn url_fmt(method: &str, path: &str) -> String {
+    println!("{:?}", (path, method));
+    return method.to_ascii_lowercase() + "_" + path;
+}

+ 31 - 0
src/cache.rs

@@ -0,0 +1,31 @@
+#![feature(optin_builtin_traits)]
+extern crate futures;
+extern crate r2d2;
+extern crate r2d2_redis;
+extern crate redis;
+
+use iron::typemap::Key;
+
+use std;
+use r2d2::{Pool, PooledConnection, ManageConnection};
+use r2d2_redis::{RedisConnectionManager, Error};
+use redis::*;
+pub type RedisPool = Pool<RedisConnectionManager>;
+pub type RedisPooledConnection = PooledConnection<RedisConnectionManager>;
+
+pub struct AppRedis;
+impl Key for AppRedis {
+    type Value = RedisPool;
+}
+
+
+pub fn setup_connection_pool(cn_str: &str, pool_size: u32) -> RedisPool {
+    let manager = ::r2d2_redis::RedisConnectionManager::new(cn_str).unwrap();
+    let config = ::r2d2::Config::builder().pool_size(pool_size).build();
+    return r2d2::Pool::new(config, manager).unwrap();
+}
+
+pub fn set(conn: &RedisPooledConnection, key: String, data: String) {
+    let _: std::result::Result<String, redis::RedisError> = conn.set(key, data);
+
+}

+ 41 - 0
src/db.rs

@@ -0,0 +1,41 @@
+use sql;
+
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate postgres;
+use iron::typemap::Key;
+
+use std;
+use r2d2::{Pool, PooledConnection};
+use r2d2_postgres::PostgresConnectionManager;
+
+pub type PostgresPool = Pool<PostgresConnectionManager>;
+pub type PostgresPooledConnection = PooledConnection<PostgresConnectionManager>;
+
+pub struct AppDb;
+impl Key for AppDb {
+    type Value = PostgresPool;
+}
+fn print_type_of<T>(_: &T) {
+    println!("{}", unsafe { std::intrinsics::type_name::<T>() });
+}
+pub fn setup_connection_pool(cn_str: &str, pool_size: u32) -> PostgresPool {
+    let manager = ::r2d2_postgres::PostgresConnectionManager::new(cn_str,
+                                                                  ::r2d2_postgres::TlsMode::None)
+        .unwrap();
+    let config = ::r2d2::Config::builder().pool_size(pool_size).build();
+    let pool = ::r2d2::Pool::new(config, manager).unwrap();
+    let conn = pool.get().unwrap();
+    return pool;
+}
+
+pub fn scaffold_db(conn: &PostgresPooledConnection) {
+    conn.execute(sql::SQL_USERTABLE, &[]).unwrap();
+    conn.execute(sql::SQL_IMAGETABLE, &[]).unwrap();
+    conn.execute(sql::SQL_IMAGE_PRODUCTTABLE, &[]).unwrap();
+    conn.execute(sql::SQL_PRODUCTTABLE, &[]).unwrap();
+    conn.execute(sql::SQL_PRICETABLE, &[]).unwrap();
+    conn.execute(sql::SQL_APPOINTMENTTABLE, &[]).unwrap();
+    conn.execute(sql::SQL_SESSIONTABLE, &[]).unwrap();
+    conn.execute(sql::SQL_USER_PRODUCTTABLE, &[]).unwrap();
+}

+ 12 - 0
src/echo.rs

@@ -0,0 +1,12 @@
+extern crate iron;
+
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+
+pub fn echo(req: &mut Request) -> IronResult<Response> {
+    match req.url.path().len() == 2 {
+        true => Ok(Response::with((status::Ok, req.url.path()[1]))),
+        _ => Ok(Response::with((status::Ok, "ECHO! World!"))),
+    }
+}

+ 101 - 0
src/image.rs

@@ -0,0 +1,101 @@
+extern crate iron;
+
+extern crate bodyparser;
+extern crate persistent;
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate serde;
+extern crate serde_json;
+extern crate uuid;
+
+use uuid::Uuid;
+use serde::{Deserialize, Deserializer};
+
+use sql;
+use product;
+use db;
+
+use persistent::Read;
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+
+
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+struct Image {
+    id: String,
+    name: String,
+    url: String,
+}
+
+impl Image {
+    pub fn new(id: String, name: String, url: String) -> Image {
+        Image {
+            id: id,
+            name: name,
+            url: url,
+        }
+    }
+}
+pub fn put(req: &mut Request) -> IronResult<Response> {
+    let image = req.get::<bodyparser::Struct<Image>>();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match image {
+        Ok(Some(image)) => {
+            let pool = req.get::<Read<db::AppDb>>().unwrap();
+            let conn = pool.get().unwrap();
+            let isNew = image.id.len() == 0;
+            let new_id = match isNew {
+                true => Uuid::new_v4().to_string(),
+                _ => image.id.to_owned(),
+            };
+            conn.execute(sql::SQL_UPSERTIMAGE, &[&new_id, &image.name, &image.url])
+                .unwrap();
+            let resp = Image::new(new_id, image.name, image.url);
+            response = serde_json::to_string(&resp).unwrap();
+        }
+        Ok(None) => {
+            stat = status::BadRequest;
+        }
+        Err(err) => {
+            println!("{:?}", err);
+            stat = status::InternalServerError;
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get(req: &mut Request) -> IronResult<Response> {
+    let pool = req.get::<Read<db::AppDb>>().unwrap();
+    let path = req.url.path();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match path.len() >= 2 {
+        true => {
+            let id = req.url.path()[1];
+            let conn = pool.get().unwrap();
+            for row in conn.query(sql::SQL_GETIMAGE, &[&id]).unwrap().iter() {
+                let image = Image::new(row.get(0), row.get(1), row.get(2));
+                response = serde_json::to_string(&image).unwrap();
+            }
+        }
+        _ => {
+            stat = status::BadRequest;
+            response = String::from("No key found")
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get_all(req: &mut Request) -> IronResult<Response> {
+    let conn = req.get::<Read<db::AppDb>>().unwrap().get().unwrap();
+    let path = req.url.path();
+    let mut images = Vec::new();
+    for row in &conn.query(sql::SQL_GETIMAGES, &[]).expect("Shit the bed") {
+        let image = Image::new(row.get(0), row.get(1), row.get(2));
+        images.push(image);
+    }
+    Ok(Response::with((status::Ok, serde_json::to_string(&images).unwrap())))
+}

+ 5 - 0
src/lib.rs

@@ -0,0 +1,5 @@
+#[cfg(test)]
+mod test {
+    #[test]
+    fn it_works() {}
+}

+ 182 - 0
src/main.rs

@@ -0,0 +1,182 @@
+#![feature(custom_attribute)]
+#![feature(custom_derive, plugin)]
+#![feature(optin_builtin_traits)]
+#![feature(proc_macro)]
+#![feature(core_intrinsics)]
+
+mod sql;
+mod base;
+mod user;
+mod db;
+mod cache;
+mod product;
+mod session;
+mod echo;
+mod image;
+mod price;
+mod appointment;
+#[macro_use]
+extern crate serde_derive;
+
+extern crate iron;
+extern crate staticfile;
+extern crate router;
+
+extern crate bodyparser;
+extern crate persistent;
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate r2d2_redis;
+extern crate redis;
+
+extern crate serde;
+extern crate serde_json;
+extern crate uuid;
+extern crate futures;
+use std::ops::Deref;
+use futures::Future;
+use redis::Commands;
+use r2d2_redis::RedisConnectionManager;
+use uuid::Uuid;
+use serde::{Deserialize, Deserializer};
+use std::default::Default;
+use std::thread;
+use std::sync::Arc;
+use std::sync::RwLock;
+
+use router::Router;
+use mount::Mount;
+use staticfile::Static;
+use std::path::Path;
+use std::fs::File;
+use std::env;
+use persistent::{Read, Write};
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+use iron::AfterMiddleware;
+extern crate mount;
+struct App {
+    name: String,
+    version: String,
+}
+
+impl App {
+    pub fn new(name: String) -> App {
+        let version: String = match env::var("APP_VERSION") {
+            Ok(val) => val,
+            Err(_) => "0.0.0".to_string(),
+        };
+        App {
+            name: name,
+            version: version,
+        }
+    }
+
+    pub fn info(&self) -> String {
+        return self.name.to_string() + " | " + &self.version;
+    }
+}
+
+struct Location {
+    latitude: f64,
+    longitude: f64,
+    timestamp: f64,
+}
+
+fn reset(req: &mut Request) -> IronResult<Response> {
+    let pool = req.get::<Read<db::AppDb>>().unwrap();
+    let conn = pool.get().unwrap();
+    conn.query(sql::SQL_RESET, &[]);
+    Ok(Response::with((status::Ok, "DB-RESET")))
+
+}
+fn root(req: &mut Request, app: App) -> IronResult<Response> {
+    match req.url.path()[0] {
+        "health" => return health(req),
+        "reset" => return reset(req),
+        _ => return Ok(Response::with((status::Ok, app.info()))),
+    }
+}
+fn health(req: &mut Request) -> IronResult<Response> {
+    Ok(Response::with((status::Ok, "Alive and kickin it")))
+}
+
+
+fn get_router() -> fn(&mut Request) -> IronResult<Response> {
+    fn router(req: &mut Request) -> IronResult<Response> {
+        println!("{:?}", req.url.path());
+        let app = App::new("!HairParty!".to_string());
+        match base::url_fmt(req.method.as_ref(), req.url.path()[0]).as_str() {
+            "post_product" => return product::put(req),
+            "get_product" => return product::get(req),
+            "get_products" => return product::get_all(req),
+            "post_session" => return session::put(req),
+            "get_session" => return session::get(req),
+            "get_sessions" => return session::get_all(req),
+            "post_appointment" => return appointment::put(req),
+            "get_appointment" => return appointment::get(req),
+            "get_appointments" => return appointment::get_all(req),
+            "post_price" => return price::put(req),
+            "get_price" => return price::get(req),
+            "get_prices" => return price::get_all(req),
+            "post_image" => return image::put(req),
+            "get_image" => return image::get(req),
+            "get_images" => return image::get_all(req),
+            "post_user" => return user::put(req),
+            "get_user" => return user::get(req),
+            "get_users" => return user::get_all(req),
+            "post_login" => return user::login(req),
+            "echo" => return echo::echo(req),
+            _ => return root(req, app),
+        }
+    }
+    return router;
+}
+
+const MAX_BODY_LENGTH: usize = 1024 * 1024 * 10;
+
+struct CorsMiddleware;
+impl AfterMiddleware for CorsMiddleware {
+    fn after(&self, req: &mut Request, mut res: Response) -> IronResult<Response> {
+        let _ = res.headers.set_raw("access-control-allow-origin".to_string(),
+                                    vec![b"*".to_vec()]);
+        if req.method == iron::method::Method::Options {
+            let _ = res.headers.set_raw("access-control-allow-headers".to_string(),
+                                        vec![b"accept, content-type".to_vec()]);
+            let _ = res.headers.set_raw("access-control-allow-methods".to_string(),
+                                        vec![b"GET,POST,DELETE,OPTIONS,PATCH".to_vec()]);
+        }
+        res.headers.set(iron::headers::AccessControlAllowOrigin::Any);
+        Ok(res)
+    }
+}
+
+fn main() {
+    let args: Vec<_> = env::args().collect();
+    let mut port = String::from("");
+    let mut conn_string = String::from("");
+    if args.len() > 1 {
+        port = args[1].as_str().to_string();
+        conn_string = args[2].as_str().to_string();
+    } else {
+        panic!("{:?}", args);
+    }
+    println!("Connecting to postgres: {}", conn_string);
+    let postgres_pool = db::setup_connection_pool(&conn_string, 6);
+    let conn = postgres_pool.get().unwrap();
+    println!("Connected to postgres");
+    db::scaffold_db(&conn);
+    let redis_pool = cache::setup_connection_pool("redis://localhost", 6);
+    let mut assets_mount = Mount::new();
+    assets_mount.mount("/", get_router())
+        .mount("/assets/", Static::new(Path::new("../hairparty_web/")));
+    let mut middleware = Chain::new(assets_mount);
+    middleware.link(Read::<db::AppDb>::both(postgres_pool));
+    middleware.link(Read::<cache::AppRedis>::both(redis_pool));
+    middleware.link_before(Read::<bodyparser::MaxBodyLength>::one(MAX_BODY_LENGTH));
+    middleware.link_after(CorsMiddleware);
+    let listen = format!("0.0.0.0:{}", port);
+    println!("{:?}", listen);
+    Iron::new(middleware).http(listen.as_str()).unwrap();
+}

+ 119 - 0
src/price.rs

@@ -0,0 +1,119 @@
+extern crate iron;
+
+extern crate bodyparser;
+extern crate persistent;
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate serde;
+extern crate serde_json;
+extern crate uuid;
+
+use uuid::Uuid;
+use serde::{Deserialize, Deserializer};
+
+use sql;
+use product;
+use db;
+
+use persistent::Read;
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+struct Price {
+    id: String,
+    user_id: String,
+    product_id: String,
+    currency_code: String,
+    price: i32,
+}
+impl Price {
+    pub fn new(id: String,
+               user_id: String,
+               product_id: String,
+               currency_code: String,
+               price: i32)
+               -> Price {
+        Price {
+            id: id,
+            user_id: user_id,
+            product_id: product_id,
+            currency_code: currency_code,
+            price: price,
+        }
+    }
+}
+
+pub fn put(req: &mut Request) -> IronResult<Response> {
+    let price = req.get::<bodyparser::Struct<Price>>();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match price {
+        Ok(Some(price)) => {
+            let pool = req.get::<Read<db::AppDb>>().unwrap();
+            let conn = pool.get().unwrap();
+            let isNew = price.id.len() == 0;
+            let new_id = match isNew {
+                true => Uuid::new_v4().to_string(),
+                _ => price.id.to_owned(),
+            };
+            conn.execute(sql::SQL_UPSERTPRICE,
+                         &[&new_id,
+                           &price.user_id,
+                           &price.product_id,
+                           &price.currency_code,
+                           &price.price])
+                .unwrap();
+            let resp = Price::new(new_id,
+                                  price.user_id,
+                                  price.product_id,
+                                  price.currency_code,
+                                  price.price);
+            response = serde_json::to_string(&resp).unwrap();
+            // upsert images
+        }
+        Ok(None) => {
+            stat = status::BadRequest;
+        }
+        Err(err) => {
+            println!("{:?}", err);
+            stat = status::InternalServerError;
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get(req: &mut Request) -> IronResult<Response> {
+    let pool = req.get::<Read<db::AppDb>>().unwrap();
+    let path = req.url.path();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match path.len() >= 2 {
+        true => {
+            let id = req.url.path()[1];
+            let conn = pool.get().unwrap();
+            for row in conn.query(sql::SQL_GETPRICE, &[&id]).unwrap().iter() {
+                let price = Price::new(row.get(0), row.get(1), row.get(2), row.get(3), row.get(4));
+                response = serde_json::to_string(&price).unwrap();
+            }
+        }
+        _ => {
+            stat = status::BadRequest;
+            response = String::from("No key found")
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get_all(req: &mut Request) -> IronResult<Response> {
+    let conn = req.get::<Read<db::AppDb>>().unwrap().get().unwrap();
+    let path = req.url.path();
+    let mut prices = Vec::new();
+    for row in &conn.query(sql::SQL_GETPRICES, &[]).expect("Shit the bed") {
+        let price = Price::new(row.get(0), row.get(1), row.get(2), row.get(3), row.get(4));
+        prices.push(price);
+    }
+    Ok(Response::with((status::Ok, serde_json::to_string(&prices).unwrap())))
+}

+ 112 - 0
src/product.rs

@@ -0,0 +1,112 @@
+extern crate iron;
+
+extern crate bodyparser;
+extern crate persistent;
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate serde;
+extern crate serde_json;
+extern crate uuid;
+
+use uuid::Uuid;
+use serde::{Deserialize, Deserializer};
+
+use sql;
+use product;
+use db;
+
+use persistent::Read;
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+
+
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct Product {
+    id: String,
+    name: String,
+    images: Vec<String>,
+    price: String,
+}
+impl Product {
+    pub fn new(id: String, name: String, price: String, images: Vec<String>) -> Product {
+        Product {
+            id: id,
+            name: name,
+            images: images,
+            price: price,
+        }
+    }
+}
+pub fn put(req: &mut Request) -> IronResult<Response> {
+    let product = req.get::<bodyparser::Struct<Product>>();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match product {
+        Ok(Some(product)) => {
+            let pool = req.get::<Read<db::AppDb>>().unwrap();
+            let conn = pool.get().unwrap();
+            let isNew = product.id.len() == 0;
+            let new_id = match isNew {
+                true => Uuid::new_v4().to_string(),
+                _ => product.id.to_owned(),
+            };
+            conn.execute(sql::SQL_UPSERTPRODUCT,
+                         &[&new_id, &product.name, &product.price])
+                .unwrap();
+            let mut imgIds = product.images.to_owned();
+            for imgId in imgIds {
+                conn.execute(sql::SQL_UPSERTIMAGE_PRODUCT, &[&imgId, &new_id])
+                    .unwrap();
+            }
+            let resp = Product::new(new_id, product.name, product.price, product.images);
+            response = serde_json::to_string(&resp).unwrap();
+        }
+        Ok(None) => {
+            stat = status::BadRequest;
+        }
+        Err(err) => {
+            println!("{:?}", err);
+            stat = status::InternalServerError;
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get(req: &mut Request) -> IronResult<Response> {
+    let pool = req.get::<Read<db::AppDb>>().unwrap();
+    let path = req.url.path();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match path.len() >= 2 {
+        true => {
+            let id = req.url.path()[1];
+            let conn = pool.get().unwrap();
+            for row in conn.query(sql::SQL_GETPRODUCT, &[&id]).unwrap().iter() {
+                let mut prodResArray: String = row.get(3);
+                let mut productKeys = prodResArray.split(",").map(|s| s.to_string()).collect();
+                let product = Product::new(row.get(0), row.get(1), row.get(2), productKeys);
+                response = serde_json::to_string(&product).unwrap();
+            }
+        }
+        _ => {
+            stat = status::BadRequest;
+            response = String::from("No key found")
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get_all(req: &mut Request) -> IronResult<Response> {
+    let conn = req.get::<Read<db::AppDb>>().unwrap().get().unwrap();
+    let path = req.url.path();
+    let mut products = Vec::new();
+    for row in &conn.query(sql::SQL_GETPRODUCTS, &[]).expect("Shit the bed") {
+        let mut prodResArray: String = row.get(3);
+        let mut productKeys = prodResArray.split(",").map(|s| s.to_string()).collect();
+        let product = Product::new(row.get(0), row.get(1), row.get(2), productKeys);
+        products.push(product);
+    }
+    Ok(Response::with((status::Ok, serde_json::to_string(&products).unwrap())))
+}

+ 129 - 0
src/session.rs

@@ -0,0 +1,129 @@
+extern crate iron;
+
+extern crate bodyparser;
+extern crate persistent;
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate serde;
+extern crate serde_json;
+extern crate uuid;
+extern crate r2d2_redis;
+extern crate redis;
+
+use r2d2_redis::RedisConnectionManager;
+
+use redis::Commands;
+
+use std;
+use std::ops::Deref;
+
+use uuid::Uuid;
+use serde::{Deserialize, Deserializer};
+
+use sql;
+use product;
+use db;
+
+use cache;
+
+use persistent::Read;
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+use std::default::Default;
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct Session {
+    id: String,
+    user_id: String,
+    data: String,
+    created: String,
+}
+impl Session {
+    pub fn new(id: String, user_id: String, data: String, created: String) -> Session {
+        Session {
+            id: id,
+            user_id: user_id,
+            data: data,
+            created: created,
+        }
+    }
+}
+
+pub fn put(req: &mut Request) -> IronResult<Response> {
+    let session = req.get::<bodyparser::Struct<Session>>();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match session {
+        Ok(Some(session)) => {
+            let pool = req.get::<Read<db::AppDb>>().unwrap();
+            let redis = req.get::<Read<cache::AppRedis>>().unwrap();
+            let rConn = redis.get().unwrap();
+            let conn = pool.get().unwrap();
+            let isNew = session.id.len() == 0;
+            let new_id = match isNew {
+                true => Uuid::new_v4().to_string(),
+                _ => session.id.to_owned(),
+            };
+            conn.execute(sql::SQL_UPSERTSESSION,
+                         &[&new_id, &session.user_id, &session.data])
+                .unwrap();
+            let resp = Session::new(new_id, session.user_id, session.data, session.created);
+            response = serde_json::to_string(&resp).unwrap();
+
+            let _: std::result::Result<String, redis::RedisError> =
+                rConn.set(resp.id.as_str(), response.as_str());
+        }
+        Ok(None) => {
+            stat = status::BadRequest;
+        }
+        Err(err) => {
+            println!("{:?}", err);
+            stat = status::InternalServerError;
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get(req: &mut Request) -> IronResult<Response> {
+    let pool = req.get::<Read<db::AppDb>>().unwrap();
+    let redis = req.get::<Read<cache::AppRedis>>().unwrap();
+    let path = req.url.path();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match path.len() >= 2 {
+        true => {
+            let id = req.url.path()[1];
+            let conn = pool.get().unwrap();
+            let rConn = redis.get().unwrap();
+            let r: std::result::Result<String, redis::RedisError> = rConn.get(id);
+            match r {
+                Ok(value) => response = value,
+                Err(_) => {
+                    stat = status::BadRequest;
+                    response = String::from("Redis error retrieving session")
+                }
+            }
+            // for row in conn.query(sql::SQL_GETSESSION, &[&id]).unwrap().iter() {
+            //     let session = Session::new(row.get(0), row.get(1), row.get(2), row.get(3));
+            //     response = serde_json::to_string(&session).unwrap();
+            // }
+        }
+        _ => {
+            stat = status::BadRequest;
+            response = String::from("No key found")
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get_all(req: &mut Request) -> IronResult<Response> {
+    let conn = req.get::<Read<db::AppDb>>().unwrap().get().unwrap();
+    let path = req.url.path();
+    let mut sessions = Vec::new();
+    for row in &conn.query(sql::SQL_GETSESSIONS, &[]).expect("Shit the bed") {
+        let session = Session::new(row.get(0), row.get(1), row.get(2), row.get(3));
+        sessions.push(session);
+    }
+    Ok(Response::with((status::Ok, serde_json::to_string(&sessions).unwrap())))
+}

+ 179 - 0
src/sql.rs

@@ -0,0 +1,179 @@
+
+pub static SQL_USERTABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS users (
+    user_id varchar PRIMARY KEY,
+    name varchar NOT NULL,
+    lname varchar NOT NULL,
+    dob bigint NOT NULL,
+    password varchar NOT NULL,
+    email varchar NOT NULL,
+    phone varchar NOT NULL,
+    active integer NOT NULL DEFAULT '1',
+    created bigint NULL DEFAULT extract(epoch from now()),
+    updated bigint NULL
+);
+";
+pub static SQL_UPSERTUSER: &'static str =
+    "
+INSERT INTO users (user_id, name, lname, dob, password, email, phone, active) 
+VALUES ($1, \
+     $2, $3, cast($4 as bigint), crypt($5, gen_salt('md5')), $6, $7, $8) 
+ON CONFLICT (user_id) DO \
+     UPDATE SET name=$2,lname=$3,dob=cast($4 as bigint), password=crypt($5, gen_salt('md5')), \
+     email=$6, phone=$7, active=$8, updated=extract(epoch from now());
+";
+pub static SQL_GETUSER: &'static str = "SELECT u.user_id, name, lname, dob, email, phone, active, \
+                                        string_agg(up.product_id, ',') as products from users u \
+                                        left join user_to_product up on up.user_id=u.user_id \
+                                        where u.user_id=$1 group by u.user_id;";
+pub static SQL_GETUSERS: &'static str = "SELECT user_id, name, lname, dob, email, phone, active \
+                                         from users;";
+pub static SQL_USERAUTH: &'static str = "SELECT user_id, name, lname, dob, email, phone, active \
+                                         from users where password=crypt($1, password) AND \
+                                         email=$2;";
+
+pub static SQL_IMAGETABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS images (
+    id varchar PRIMARY KEY,
+    name varchar NOT NULL,
+    url varchar NOT NULL,
+    created bigint NOT NULL DEFAULT extract(epoch from now()),
+    updated bigint NULL
+);
+";
+pub static SQL_UPSERTIMAGE: &'static str = "
+INSERT INTO images (id, name, url) 
+VALUES ($1, $2, $3) 
+ON CONFLICT (id) DO UPDATE SET name=$2,url=$3,updated=extract(epoch from now());
+";
+pub static SQL_GETIMAGE: &'static str = "SELECT id, name, url from images where id =$1;";
+pub static SQL_GETIMAGES: &'static str = "SELECT id, name, url from images;";
+
+pub static SQL_IMAGE_PRODUCTTABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS image_product (
+    image_id varchar PRIMARY KEY,
+    product_id varchar NOT NULL,
+    created bigint NOT NULL DEFAULT extract(epoch from now()),
+    updated bigint NULL
+);
+";
+pub static SQL_UPSERTIMAGE_PRODUCT: &'static str = "
+INSERT INTO image_product (image_id, product_id) 
+VALUES ($1, $2) 
+ON CONFLICT (image_id) DO UPDATE SET image_id=$1,product_id=$2,updated=extract(epoch from now());
+";
+
+pub static SQL_PRODUCTTABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS products (
+    id varchar PRIMARY KEY,
+    name varchar NOT NULL,
+    price_id varchar NOT NULL,
+    created bigint NOT NULL DEFAULT extract(epoch from now()),
+    updated bigint NULL
+);
+";
+
+pub static SQL_UPSERTPRODUCT: &'static str = "
+INSERT INTO products (id, name, price_id) 
+VALUES ($1, $2, $3) 
+ON CONFLICT (id) DO UPDATE SET name=$2,price_id=$3,updated=extract(epoch from now());
+";
+pub static SQL_GETPRODUCT: &'static str =
+    "SELECT p.id, name, price_id, COALESCE(string_agg(ip.image_id, ','), '') as images from \
+     products p left join image_product ip ON ip.product_id = p.id where p.id =$1 group by p.id;";
+pub static SQL_GETPRODUCTS: &'static str =
+    "SELECT p.id, name, price_id, string_agg(ip.image_id, ',') as images from products p left \
+     join image_product ip ON ip.product_id = p.id group by p.id;";
+
+pub static SQL_PRICETABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS prices (
+    id varchar PRIMARY KEY,
+    user_id varchar NOT NULL,
+    product_id varchar NOT NULL,
+    currency_code varchar NOT NULL,
+    price integer NOT NULL,
+    created bigint NOT NULL DEFAULT extract(epoch from now()),
+    updated bigint NULL
+);
+";
+pub static SQL_UPSERTPRICE: &'static str =
+    "
+INSERT INTO prices (id, user_id, product_id, currency_code, price) 
+VALUES ($1, $2, $3, $4, \
+     $5) 
+ON CONFLICT (id) DO UPDATE SET \
+     user_id=$2,product_id=$3,currency_code=$4,price=$5,updated=extract(epoch from now());
+";
+
+pub static SQL_GETPRICE: &'static str = "SELECT id, user_id, product_id, currency_code, price \
+                                         from prices where id =$1;";
+pub static SQL_GETPRICES: &'static str = "SELECT id, user_id, product_id, currency_code, price \
+                                          from prices;";
+
+pub static SQL_APPOINTMENTTABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS appointments (
+    id varchar PRIMARY KEY,
+    name varchar NOT NULL,
+    time bigint NOT NULL,
+    confirmed bool NOT NULL,
+    user_id varchar NOT NULL,
+    vendor_id varchar NOT NULL,
+    product_id varchar NOT NULL,
+    price_id varchar NOT NULL,
+    created bigint NOT NULL DEFAULT extract(epoch from now()),
+    updated bigint NULL
+);
+";
+pub static SQL_UPSERTAPPOINTMENT: &'static str =
+    "
+INSERT INTO appointments (id, name, time, confirmed, user_id, vendor_id, product_id, \
+     price_id) 
+VALUES ($1, $2, $3, $4, $5, $6, $7, $8) 
+ON CONFLICT (id) DO UPDATE SET \
+     name=$2,time=$3,confirmed=$4,user_id=$5,vendor_id=$6,product_id=$7,price_id=$8, \
+     updated=extract(epoch from now());
+";
+
+pub static SQL_GETAPPOINTMENT: &'static str = "SELECT id, name, time, confirmed, user_id, \
+                                               vendor_id, product_id, price_id from appointments \
+                                               where id =$1;";
+pub static SQL_GETAPPOINTMENTS: &'static str = "SELECT id, name, time, confirmed, user_id, \
+                                                vendor_id, product_id, price_id from appointments;";
+
+pub static SQL_SESSIONTABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS sessions (
+    id varchar  PRIMARY KEY,
+    user_id     varchar NOT NULL,
+    data        varchar,
+    created     bigint NOT NULL DEFAULT extract(epoch from now())
+);
+";
+pub static SQL_UPSERTSESSION: &'static str = "
+INSERT INTO sessions (id, user_id, data) 
+VALUES ($1, $2, $3) 
+ON CONFLICT (id) DO UPDATE SET user_id=$2, data=$3;
+";
+pub static SQL_GETSESSION: &'static str = "SELECT id, user_id, data, (cast (created as varchar)) \
+                                           from sessions where id =$1;";
+pub static SQL_GETSESSIONS: &'static str = "SELECT id, user_id, data, (cast (created as varchar)) \
+                                            from sessions;";
+
+pub static SQL_USER_PRODUCTTABLE: &'static str = "
+CREATE TABLE IF NOT EXISTS user_to_product (
+    id varchar  PRIMARY KEY,
+    user_id varchar NOT NULL,
+    product_id varchar NOT NULL,
+    created bigint NOT NULL DEFAULT extract(epoch from now()),
+    updated bigint NULL
+);
+";
+
+pub static SQL_UPSERT_USER_PRODUCT: &'static str = "
+INSERT INTO user_to_product (id, user_id, product_id) 
+VALUES ($1, $2, $3) 
+ON CONFLICT (id) DO UPDATE SET user_id=$2, product_id=$3, updated=extract(epoch from now());
+";
+
+pub static SQL_RESET: &'static str = "
+TRUNCATE appointments, users, images, prices, products;
+";

+ 207 - 0
src/user.rs

@@ -0,0 +1,207 @@
+
+extern crate iron;
+
+extern crate bodyparser;
+extern crate persistent;
+extern crate r2d2;
+extern crate r2d2_postgres;
+extern crate serde;
+extern crate serde_json;
+extern crate uuid;
+
+
+use uuid::Uuid;
+use serde::{Deserialize, Deserializer};
+
+use sql;
+use product;
+use db;
+
+use persistent::Read;
+use iron::prelude::*;
+use iron::status;
+use iron::typemap::Key;
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+struct Login {
+    password: String,
+    email: String,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+struct User {
+    id: String,
+    name: String,
+    lname: String,
+    dob: i64,
+    password: String,
+    email: String,
+    phone: String,
+    active: i32,
+    products: Vec<String>,
+}
+impl User {
+    pub fn new(user_id: String,
+               name: String,
+               lname: String,
+               dob: i64,
+               email: String,
+               phone: String,
+               active: i32,
+               products: Vec<String>)
+               -> User {
+        User {
+            id: user_id,
+            name: name,
+            lname: lname,
+            dob: dob,
+            password: String::from(""),
+            email: email,
+            phone: phone,
+            active: active,
+            products: products,
+        }
+    }
+}
+
+
+pub fn put(req: &mut Request) -> IronResult<Response> {
+    let user = req.get::<bodyparser::Struct<User>>();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match user {
+        Ok(Some(user)) => {
+            let pool = req.get::<Read<db::AppDb>>().unwrap();
+            let conn = pool.get().unwrap();
+            let isNew = user.id.len() == 0;
+            let new_id = match isNew {
+                true => Uuid::new_v4().to_string(),
+                _ => user.id.to_owned(),
+            };
+            conn.execute(sql::SQL_UPSERTUSER,
+                         &[&new_id,
+                           &user.name,
+                           &user.lname,
+                           &user.dob,
+                           &user.password,
+                           &user.email,
+                           &user.phone,
+                           &user.active])
+                .unwrap();
+            let mut prodIds = user.products.to_owned();
+            for prodId in prodIds {
+                let new_lu_id = Uuid::new_v4().to_string();
+                conn.execute(sql::SQL_UPSERT_USER_PRODUCT,
+                             &[&new_lu_id, &new_id, &prodId])
+                    .unwrap();
+            }
+            let resp = User::new(new_id,
+                                 user.name,
+                                 user.lname,
+                                 user.dob,
+                                 user.email,
+                                 user.phone,
+                                 user.active,
+                                 user.products);
+            response = serde_json::to_string(&resp).unwrap();
+        }
+        Ok(None) => {
+            stat = status::BadRequest;
+        }
+        Err(err) => {
+            println!("{:?}", err);
+            stat = status::InternalServerError;
+        }
+    }
+
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get(req: &mut Request) -> IronResult<Response> {
+    let pool = req.get::<Read<db::AppDb>>().unwrap();
+    let path = req.url.path();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    println!("{:?}", req.url.path());
+    match path.len() >= 2 {
+        true => {
+            let id = req.url.path()[1];
+            let conn = pool.get().unwrap();
+            for row in conn.query(sql::SQL_GETUSER, &[&id]).unwrap().iter() {
+                let mut prodResArray: String = row.get(7);
+                let mut productKeys = prodResArray.split(",").map(|s| s.to_string()).collect();
+                let user = User::new(row.get(0),
+                                     row.get(1),
+                                     row.get(2),
+                                     row.get(3),
+                                     row.get(4),
+                                     row.get(5),
+                                     row.get(6),
+                                     productKeys);
+                response = serde_json::to_string(&user).unwrap();
+            }
+        }
+        _ => {
+            stat = status::BadRequest;
+            response = String::from("No key found")
+        }
+    }
+    Ok(Response::with((stat, response)))
+}
+
+pub fn get_all(req: &mut Request) -> IronResult<Response> {
+    let conn = req.get::<Read<db::AppDb>>().unwrap().get().unwrap();
+    let path = req.url.path();
+    let mut users = Vec::new();
+    for row in &conn.query(sql::SQL_GETUSERS, &[]).expect("Shit the bed") {
+        let mut products = Vec::new();
+        products.push("".to_string());
+        let user = User::new(row.get(0),
+                             row.get(1),
+                             row.get(2),
+                             row.get(3),
+                             row.get(4),
+                             row.get(5),
+                             row.get(6),
+                             products);
+        users.push(user);
+    }
+    Ok(Response::with((status::Ok, serde_json::to_string(&users).unwrap())))
+}
+
+pub fn login(req: &mut Request) -> IronResult<Response> {
+    let loginData = req.get::<bodyparser::Struct<Login>>();
+    let mut stat = status::Ok;
+    let mut response = String::from("");
+    match loginData {
+        Ok(Some(loginData)) => {
+            let pool = req.get::<Read<db::AppDb>>().unwrap();
+            let conn = pool.get().unwrap();
+            stat = status::Unauthorized;
+            for row in &conn.query(sql::SQL_USERAUTH, &[&loginData.password, &loginData.email])
+                .expect("Shit the bed") {
+                let mut products = Vec::new();
+                products.push("".to_string());
+                let user = User::new(row.get(0),
+                                     row.get(1),
+                                     row.get(2),
+                                     row.get(3),
+                                     row.get(4),
+                                     row.get(5),
+                                     row.get(6),
+                                     products);
+                stat = status::Ok;
+                response = serde_json::to_string(&user).unwrap();
+            }
+        }
+        Ok(None) => {
+            stat = status::BadRequest;
+        }
+        Err(err) => {
+            println!("{:?}", err);
+            stat = status::InternalServerError;
+        }
+    }
+
+    Ok(Response::with((stat, response)))
+}