<commit_before>extern crate crypto;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;

use std::fmt;

fn hmac_sha1(key: &[u8], message: &[u8]) -> Vec<u8> {
    let mut hmac = Hmac::new(Sha1::new(), key);

    for i in message.iter() {
        hmac.input(&[*i])
    }

    let result = hmac.result();
    result.code().to_vec()
}

fn offset(b: &[u8]) -> usize {
    (b.last().unwrap() & 0xf) as usize
}

fn sbits(bits: &[u8]) -> u32 {
    let offset = offset(bits);

    let mut val: u32 = 0;
    val += bits[offset + 3] as u32;
    val += (bits[offset + 2] as u32) << 8;
    val += (bits[offset + 1] as u32) << 16;
    val += ((bits[offset] as u32) & 0x7f) << 24;
    val
}

pub struct HotpOutput {
    pub code: u32,
    pub length: usize,
}

impl fmt::Display for HotpOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0length$}", self.code, length = self.length)
    }
}

pub fn hotp(desired_code_length: usize, key: &[u8], counter: &[u8]) -> HotpOutput {
    let hmac_value = hmac_sha1(key, counter);
    let dbc = sbits(hmac_value.as_slice());
    HotpOutput{ code: dbc % 10u32.pow(desired_code_length as u32), length: desired_code_length }
}
<commit_msg>Add docstring for rusthotp::hotp.<commit_after>extern crate crypto;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;

use std::fmt;

/// This implementation of HMAC-Based One Time Passwords proceeds in three
/// stages, as per [RFC 4226](https://www.ietf.org/rfc/rfc4226.txt):
///
/// 1. Generate an HMAC-SHA-1 value given a shared secret `key` and a
/// moving factor `counter` that *should* change on every use
/// 2. Extraction of a 4-byte value from the SHA-1 digest
/// 3. Deriving a final HOTP value between 0 and
/// 10^{`desired_code_length`}-1 from the 4-byte value extracted
/// in the last step.
///
/// Note that it is the responsibility of the caller to:
///
/// * Fulfill the precondition that `counter` is an 8-byte value
/// * Increment the counter accordingly per invocation
///
/// # Examples
///
/// To generate an HOTP value between 0 and 10^8 - 1, given the shared
/// secret ASCII key `"Hello world!"` and current counter `0`:
///
/// ```
/// rusthotp::hotp(8, "Hello world!".as_bytes(), [0; 8]);
/// ```
pub fn hotp(desired_code_length: usize, key: &[u8], counter: &[u8]) -> HotpOutput {
    let hmac_value = hmac_sha1(key, counter);
    let dbc = sbits(hmac_value.as_slice());
    HotpOutput{ code: dbc % 10u32.pow(desired_code_length as u32), length: desired_code_length }
}

fn hmac_sha1(key: &[u8], message: &[u8]) -> Vec<u8> {
    let mut hmac = Hmac::new(Sha1::new(), key);

    for i in message.iter() {
        hmac.input(&[*i])
    }

    let result = hmac.result();
    result.code().to_vec()
}

fn offset(b: &[u8]) -> usize {
    (b.last().unwrap() & 0xf) as usize
}

fn sbits(bits: &[u8]) -> u32 {
    let offset = offset(bits);

    let mut val: u32 = 0;
    val += bits[offset + 3] as u32;
    val += (bits[offset + 2] as u32) << 8;
    val += (bits[offset + 1] as u32) << 16;
    val += ((bits[offset] as u32) & 0x7f) << 24;
    val
}

pub struct HotpOutput {
    pub code: u32,
    pub length: usize,
}

impl fmt::Display for HotpOutput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0length$}", self.code, length = self.length)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate bzip2;
extern crate libc;
extern crate pkg_config;
extern crate tar;

use bzip2::reader::{BzDecompressor};
use std::collections::{BTreeSet};
use std::env;
use std::ffi::{OsString};
use std::fs;
use std::fs::{OpenOptions};
use std::io;
use std::io::{ErrorKind};
use std::iter::{FromIterator};
use std::path::{Path, PathBuf};
use std::process::{Command};
use std::vec::{Vec};
use tar::{Archive};

const BUNDLED_PCRE_VERSION: &'static str = "8.37";

fn main() {
    match pkg_config::Config::new().atleast_version("8.20").find("libpcre") {
        Ok(pkg_config_lib) => {
            for link_pathbuf in pkg_config_lib.link_paths {
                println!("cargo:rustc-link-search=native={}", link_pathbuf.as_path().display());
            }
        },
        Err(_) => {
            let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
            let out_dir = env::var("OUT_DIR").unwrap();

            let ext_pathbuf = Path::new(&cargo_manifest_dir).join("ext");

            let pcre_tbz2_pathbuf = ext_pathbuf.join(format!("pcre-{}.tar.bz2", BUNDLED_PCRE_VERSION));
            let pcre_tbz2_f = OpenOptions::new().read(true).open(pcre_tbz2_pathbuf).unwrap();
            let decompressor = BzDecompressor::new(pcre_tbz2_f);

            let mut archive = Archive::new(decompressor);
            // Keep track of which directory paths have already been created.
            let mut created_paths: BTreeSet<OsString> = BTreeSet::new();
            for file in archive.files_mut().unwrap() {
                let mut file = file.unwrap();
                let filename = String::from(file.filename().unwrap());

                let mut path_parts: Vec<&str> = filename.split('/').collect();
                let filename = path_parts.pop().unwrap();
                let parent_pathbuf = Path::new(&out_dir).join(PathBuf::from_iter(path_parts.iter()));
                if !path_parts.is_empty() {
                    if created_paths.insert(parent_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir_all(&parent_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory and parents: {}", parent_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                }

                let out_pathbuf = parent_pathbuf.join(&filename);
                if filename.is_empty() {
                    if created_paths.insert(out_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir(&out_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory: {}", out_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                } else {
                    let mut f = OpenOptions::new().write(true).create(true).open(&out_pathbuf).unwrap();
                    if let Err(e) = io::copy(&mut file, &mut f) {
                        panic!("failed to extract {} to {}: {}", filename, out_pathbuf.as_path().display(), e);
                    }
                }
                if cfg!(unix) {
                    // TODO Use `std::fs::Permissions` when `std::os::unix::fs::PermissionsExt` is stable.
                    use std::ffi::{CString};
                    use std::os::unix::ffi::{OsStringExt};
                    let out_pathbuf_cstring = CString::new(out_pathbuf.as_os_str().to_os_string().into_vec()).unwrap();
                    let mode = file.mode().unwrap();
                    unsafe {
                        libc::chmod(out_pathbuf_cstring.as_ptr(), mode as libc::mode_t);
                    }
                }
            }

            let pcre_pathbuf = Path::new(&out_dir).join(format!("pcre-{}", BUNDLED_PCRE_VERSION));

            let mut cmd = Command::new("cmake");
            cmd.arg(".");
            cmd.arg("-DBUILD_SHARED_LIBS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRECPP=OFF");
            cmd.arg("-DPCRE_BUILD_PCREGREP=OFF");
            cmd.arg("-DPCRE_BUILD_TESTS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRE8=ON");
            cmd.arg("-DPCRE_SUPPORT_JIT=ON");
            cmd.arg("-DPCRE_SUPPORT_UTF=ON");
            cmd.arg("-DPCRE_SUPPORT_UNICODE_PROPERTIES=ON");
            cmd.current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake . -DBUILD_SHARED_LIBS=OFF ...` did not run successfully.");
            }

            let mut cmd = Command::new("cmake");
            cmd.arg("--build").arg(".").current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake --build .` did not run successfully.");
            }

            println!("cargo:rustc-link-search=native={}", pcre_pathbuf.as_path().display());
        }
    };
}
<commit_msg>Try specifying -fPIC in CMAKE_C_FLAGS<commit_after>// Copyright 2015 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate bzip2;
extern crate libc;
extern crate pkg_config;
extern crate tar;

use bzip2::reader::{BzDecompressor};
use std::collections::{BTreeSet};
use std::env;
use std::ffi::{OsString};
use std::fs;
use std::fs::{OpenOptions};
use std::io;
use std::io::{ErrorKind};
use std::iter::{FromIterator};
use std::path::{Path, PathBuf};
use std::process::{Command};
use std::vec::{Vec};
use tar::{Archive};

const BUNDLED_PCRE_VERSION: &'static str = "8.37";

fn main() {
    match pkg_config::Config::new().atleast_version("8.20").find("libpcre") {
        Ok(pkg_config_lib) => {
            for link_pathbuf in pkg_config_lib.link_paths {
                println!("cargo:rustc-link-search=native={}", link_pathbuf.as_path().display());
            }
        },
        Err(_) => {
            let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
            let out_dir = env::var("OUT_DIR").unwrap();

            let ext_pathbuf = Path::new(&cargo_manifest_dir).join("ext");

            let pcre_tbz2_pathbuf = ext_pathbuf.join(format!("pcre-{}.tar.bz2", BUNDLED_PCRE_VERSION));
            let pcre_tbz2_f = OpenOptions::new().read(true).open(pcre_tbz2_pathbuf).unwrap();
            let decompressor = BzDecompressor::new(pcre_tbz2_f);

            let mut archive = Archive::new(decompressor);
            // Keep track of which directory paths have already been created.
            let mut created_paths: BTreeSet<OsString> = BTreeSet::new();
            for file in archive.files_mut().unwrap() {
                let mut file = file.unwrap();
                let filename = String::from(file.filename().unwrap());

                let mut path_parts: Vec<&str> = filename.split('/').collect();
                let filename = path_parts.pop().unwrap();
                let parent_pathbuf = Path::new(&out_dir).join(PathBuf::from_iter(path_parts.iter()));
                if !path_parts.is_empty() {
                    if created_paths.insert(parent_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir_all(&parent_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory and parents: {}", parent_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                }

                let out_pathbuf = parent_pathbuf.join(&filename);
                if filename.is_empty() {
                    if created_paths.insert(out_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir(&out_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory: {}", out_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                } else {
                    let mut f = OpenOptions::new().write(true).create(true).open(&out_pathbuf).unwrap();
                    if let Err(e) = io::copy(&mut file, &mut f) {
                        panic!("failed to extract {} to {}: {}", filename, out_pathbuf.as_path().display(), e);
                    }
                }
                if cfg!(unix) {
                    // TODO Use `std::fs::Permissions` when `std::os::unix::fs::PermissionsExt` is stable.
                    use std::ffi::{CString};
                    use std::os::unix::ffi::{OsStringExt};
                    let out_pathbuf_cstring = CString::new(out_pathbuf.as_os_str().to_os_string().into_vec()).unwrap();
                    let mode = file.mode().unwrap();
                    unsafe {
                        libc::chmod(out_pathbuf_cstring.as_ptr(), mode as libc::mode_t);
                    }
                }
            }

            let pcre_pathbuf = Path::new(&out_dir).join(format!("pcre-{}", BUNDLED_PCRE_VERSION));

            let mut cmd = Command::new("cmake");
            cmd.arg(".");
            cmd.arg("-DCMAKE_C_FLAGS=-fPIC");
            cmd.arg("-DBUILD_SHARED_LIBS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRECPP=OFF");
            cmd.arg("-DPCRE_BUILD_PCREGREP=OFF");
            cmd.arg("-DPCRE_BUILD_TESTS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRE8=ON");
            cmd.arg("-DPCRE_SUPPORT_JIT=ON");
            cmd.arg("-DPCRE_SUPPORT_UTF=ON");
            cmd.arg("-DPCRE_SUPPORT_UNICODE_PROPERTIES=ON");
            cmd.current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake . -DBUILD_SHARED_LIBS=OFF ...` did not run successfully.");
            }

            let mut cmd = Command::new("cmake");
            cmd.arg("--build").arg(".").current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake --build .` did not run successfully.");
            }

            println!("cargo:rustc-link-search=native={}", pcre_pathbuf.as_path().display());
        }
    };
}
<|endoftext|>


<commit_before>use std::io;
use std::path::Path;

use chrono::{DateTime, Utc};
use epub::doc::EpubDoc;

pub struct Epub {
    data: EpubDoc,
}

impl Epub {
    pub fn new(path: &Path) -> Result<Epub, io::Error> {
        Ok(Epub { data: EpubDoc::new(path)? })
    }

    pub fn get_author(&self) -> Option<Vec<String>> {
        self.data.mdata("creator")
            .map(|string| string.split(',')
                .map(|str| str.trim())
                .map(|str| str.to_string())
                .collect::<Vec<_>>())
    }

    pub fn get_title(&self) -> Option<String> {
        self.data.mdata("title")
    }

    pub fn get_publisher(&self) -> Option<String> {
        self.data.mdata("publisher")
    }

    pub fn get_publish_date(&self) -> Option<DateTime<Utc>> {
        self.data.metadata.get("date")?.iter()
            .filter_map(|str| DateTime::parse_from_rfc3339(str.as_str()).ok())
            .map(|dt| dt.with_timezone(&Utc))
            .next()
    }

    pub fn get_imprint(&self) -> Option<String> {
        None
    }

    pub fn get_description(&self) -> Option<String> {
        self.data.mdata("description")
    }

    pub fn get_subject(&self) -> Option<Vec<String>> {
        self.data.metadata.get("subject").cloned()
    }

    pub fn get_asin(&self) -> Option<String> {
        None
    }

    pub fn get_isbn(&self) -> Option<String> {
        None
    }
}<commit_msg>Replace ? with unwrap<commit_after>use std::io;
use std::path::Path;

use chrono::{DateTime, Utc};
use epub::doc::EpubDoc;

pub struct Epub {
    data: EpubDoc,
}

impl Epub {
    pub fn new(path: &Path) -> Result<Epub, io::Error> {
        Ok(Epub { data: EpubDoc::new(path).unwrap() })
    }

    pub fn get_author(&self) -> Option<Vec<String>> {
        self.data.mdata("creator")
            .map(|string| string.split(',')
                .map(|str| str.trim())
                .map(|str| str.to_string())
                .collect::<Vec<_>>())
    }

    pub fn get_title(&self) -> Option<String> {
        self.data.mdata("title")
    }

    pub fn get_publisher(&self) -> Option<String> {
        self.data.mdata("publisher")
    }

    pub fn get_publish_date(&self) -> Option<DateTime<Utc>> {
        self.data.metadata.get("date")?.iter()
            .filter_map(|str| DateTime::parse_from_rfc3339(str.as_str()).ok())
            .map(|dt| dt.with_timezone(&Utc))
            .next()
    }

    pub fn get_imprint(&self) -> Option<String> {
        None
    }

    pub fn get_description(&self) -> Option<String> {
        self.data.mdata("description")
    }

    pub fn get_subject(&self) -> Option<Vec<String>> {
        self.data.metadata.get("subject").cloned()
    }

    pub fn get_asin(&self) -> Option<String> {
        None
    }

    pub fn get_isbn(&self) -> Option<String> {
        None
    }
}<|endoftext|>


<commit_before>//! Parse a Rust source file into a `syn::File` and print out a debug
//! representation of the syntax tree.
//!
//! Use the following command from this directory to test this program by
//! running it on its own source code:
//!
//!     cargo run -- main.rs
//!
//! The output will begin with:
//!
//!     File {
//!         shebang: None,
//!         attrs: [
//!             Attribute {
//!                 pound_token: Pound,
//!                 style: Inner(
//!         ...
//!     }

use std::borrow::Cow;
use std::env;
use std::ffi::OsStr;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;

enum Error {
    IncorrectUsage,
    ReadFile(io::Error),
    ParseFile {
        error: syn::Error,
        filepath: PathBuf,
        source_code: String,
    },
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
            ReadFile(error) => write!(f, "Unable to read file: {}", error),
            ParseFile {
                error,
                filepath,
                source_code,
            } => render_location(f, error, filepath, source_code),
        }
    }
}

fn main() {
    if let Err(error) = try_main() {
        let _ = writeln!(io::stderr(), "{}", error);
        process::exit(1);
    }
}

fn try_main() -> Result<(), Error> {
    let mut args = env::args_os();
    let _ = args.next(); // executable name

    let filepath = match (args.next(), args.next()) {
        (Some(arg), None) => PathBuf::from(arg),
        _ => return Err(Error::IncorrectUsage),
    };

    let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?;
    let syntax = syn::parse_file(&code).map_err({
        |error| Error::ParseFile {
            error,
            filepath,
            source_code: code,
        }
    })?;
    println!("{:#?}", syntax);

    Ok(())
}

fn render_location(
    formatter: &mut fmt::Formatter,
    err: &syn::Error,
    filepath: &Path,
    code: &str,
) -> fmt::Result {
    let start = err.span().start();
    let mut end = err.span().end();

    if start.line == end.line && start.column == end.column {
        return Ok(());
    }

    let code_line = match code.lines().nth(start.line - 1) {
        Some(line) => line,
        None => return Ok(()),
    };

    if end.line > start.line {
        end.line = start.line;
        end.column = code_line.len();
    }

    let filename = filepath
        .file_name()
        .map(OsStr::to_string_lossy)
        .unwrap_or(Cow::Borrowed("main.rs"));

    write!(
        formatter,
        "\n\
         error: Syn unable to parse file\n\
         {indent}--> {filename}:{linenum}:{colnum}\n\
         {indent} | \n\
         {linenum} | {code}\n\
         {indent} | {offset}{underline} {message}\n\
         ",
        filename = filename,
        linenum = start.line,
        colnum = start.column,
        indent = " ".repeat(start.line.to_string().len()),
        code = code_line,
        offset = " ".repeat(start.column),
        underline = "^".repeat(end.column - start.column),
        message = err,
    )
}
<commit_msg>Add dump-syntax fallback error message<commit_after>//! Parse a Rust source file into a `syn::File` and print out a debug
//! representation of the syntax tree.
//!
//! Use the following command from this directory to test this program by
//! running it on its own source code:
//!
//!     cargo run -- main.rs
//!
//! The output will begin with:
//!
//!     File {
//!         shebang: None,
//!         attrs: [
//!             Attribute {
//!                 pound_token: Pound,
//!                 style: Inner(
//!         ...
//!     }

use std::borrow::Cow;
use std::env;
use std::ffi::OsStr;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;

enum Error {
    IncorrectUsage,
    ReadFile(io::Error),
    ParseFile {
        error: syn::Error,
        filepath: PathBuf,
        source_code: String,
    },
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
            ReadFile(error) => write!(f, "Unable to read file: {}", error),
            ParseFile {
                error,
                filepath,
                source_code,
            } => render_location(f, error, filepath, source_code),
        }
    }
}

fn main() {
    if let Err(error) = try_main() {
        let _ = writeln!(io::stderr(), "{}", error);
        process::exit(1);
    }
}

fn try_main() -> Result<(), Error> {
    let mut args = env::args_os();
    let _ = args.next(); // executable name

    let filepath = match (args.next(), args.next()) {
        (Some(arg), None) => PathBuf::from(arg),
        _ => return Err(Error::IncorrectUsage),
    };

    let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?;
    let syntax = syn::parse_file(&code).map_err({
        |error| Error::ParseFile {
            error,
            filepath,
            source_code: code,
        }
    })?;
    println!("{:#?}", syntax);

    Ok(())
}

fn render_location(
    formatter: &mut fmt::Formatter,
    err: &syn::Error,
    filepath: &Path,
    code: &str,
) -> fmt::Result {
    let start = err.span().start();
    let mut end = err.span().end();

    if start.line == end.line && start.column == end.column {
        return render_fallback(formatter, err);
    }

    let code_line = match code.lines().nth(start.line - 1) {
        Some(line) => line,
        None => return render_fallback(formatter, err),
    };

    if end.line > start.line {
        end.line = start.line;
        end.column = code_line.len();
    }

    let filename = filepath
        .file_name()
        .map(OsStr::to_string_lossy)
        .unwrap_or(Cow::Borrowed("main.rs"));

    write!(
        formatter,
        "\n\
         error: Syn unable to parse file\n\
         {indent}--> {filename}:{linenum}:{colnum}\n\
         {indent} | \n\
         {linenum} | {code}\n\
         {indent} | {offset}{underline} {message}\n\
         ",
        filename = filename,
        linenum = start.line,
        colnum = start.column,
        indent = " ".repeat(start.line.to_string().len()),
        code = code_line,
        offset = " ".repeat(start.column),
        underline = "^".repeat(end.column - start.column),
        message = err,
    )
}

fn render_fallback(formatter: &mut fmt::Formatter, err: &syn::Error) -> fmt::Result {
    write!(formatter, "Unable to parse file: {}", err)
}
<|endoftext|>


<commit_before><commit_msg>Adds support for `—plain` to `graph` sub-command<commit_after><|endoftext|>


<commit_before><commit_msg>mach: add pub to header, derp<commit_after><|endoftext|>


<commit_before>use super::*;
use xpath_reader::XpathReader;

/// Checks if there is an error in the document provided by the reader and
/// returns Ok if there
/// wasn't and Err parsing the MusicBrainz error if the API actually returned
/// an error.
pub fn check_response_error<'d, R>(reader: &'d R) -> Result<(), ClientError>
where
    R: XpathReader<'d>,
{
    match reader.read_vec::<String>("//error/text") {
        Ok(errs) => {
            if errs.len() > 0 {
                let text = errs.join("\n");
                Err(ClientErrorKind::MusicbrainzServerError(text).into())
            } else {
                Ok(())
            }
        }
        Err(_) => Ok(()),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use error_chain::ChainedError;
    use xpath_reader::XpathStrReader;

    const XML_ERR: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?>
<error>
  <text>Your requests are exceeding the allowable rate limit. Please see http://wiki.musicbrainz.org/XMLWebService for more information.</text>
  <text>For usage, please see: http://musicbrainz.org/development/mmd</text>
</error>"#;

    const XML_OK: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?><metadata xmlns="http://musicbrainz.org/ns/mmd-2.0#"><release-group type="Album" type-id="f529b476-6e62-324f-b0aa-1f3e33d313fc" id="23c74936-ad4f-45bb-8b6b-527d4aeaaad6"><title>A.I Complex</title><first-release-date>2014-07-26</first-release-date><primary-type id="f529b476-6e62-324f-b0aa-1f3e33d313fc">Album</primary-type></release-group></metadata>"#;

    #[test]
    fn error()
    {
        let context = ::util::musicbrainz_context();
        let reader = XpathStrReader::new(XML_ERR, &context).unwrap();

        let res = check_response_error(&reader);
        let err = res.err().unwrap();

        assert_eq!(err.description(), "MusicBrainz server error");
        // TODO FIXME currently this fails with RUST_BACKTRACE=1 as a backtrace is
        // generated and
        // appended to display, so we will have to come up with a better way to test
        // this or emit a
        // custom error instead of this "dynamic one".
        assert_eq!(err.display().to_string(), "Error: MusicBrainz server error: Your requests are exceeding the allowable rate limit. Please see http://wiki.musicbrainz.org/XMLWebService for more information.\nFor usage, please see: http://musicbrainz.org/development/mmd\n".to_string());
    }

    #[test]
    fn ok()
    {
        let context = ::util::musicbrainz_context();
        let reader = XpathStrReader::new(XML_OK, &context).unwrap();

        // should not raise error
        check_response_error(&reader).unwrap();
    }
}
<commit_msg>Fix test failure with RUST_BACKTRACE=1<commit_after>use super::*;
use xpath_reader::XpathReader;

/// Checks if there is an error in the document provided by the reader and
/// returns Ok if there
/// wasn't and Err parsing the MusicBrainz error if the API actually returned
/// an error.
pub fn check_response_error<'d, R>(reader: &'d R) -> Result<(), ClientError>
where
    R: XpathReader<'d>,
{
    match reader.read_vec::<String>("//error/text") {
        Ok(errs) => {
            if errs.len() > 0 {
                let text = errs.join("\n");
                Err(ClientErrorKind::MusicbrainzServerError(text).into())
            } else {
                Ok(())
            }
        }
        Err(_) => Ok(()),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use error_chain::ChainedError;
    use xpath_reader::XpathStrReader;

    const XML_ERR: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?>
<error>
  <text>Your requests are exceeding the allowable rate limit. Please see http://wiki.musicbrainz.org/XMLWebService for more information.</text>
  <text>For usage, please see: http://musicbrainz.org/development/mmd</text>
</error>"#;

    const XML_OK: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?><metadata xmlns="http://musicbrainz.org/ns/mmd-2.0#"><release-group type="Album" type-id="f529b476-6e62-324f-b0aa-1f3e33d313fc" id="23c74936-ad4f-45bb-8b6b-527d4aeaaad6"><title>A.I Complex</title><first-release-date>2014-07-26</first-release-date><primary-type id="f529b476-6e62-324f-b0aa-1f3e33d313fc">Album</primary-type></release-group></metadata>"#;

    #[test]
    fn error()
    {
        let context = ::util::musicbrainz_context();
        let reader = XpathStrReader::new(XML_ERR, &context).unwrap();

        let res = check_response_error(&reader);
        let err = res.err().unwrap();

        assert_eq!(err.description(), "MusicBrainz server error");

        // If backtraces are enabled `error-chain` will appends some backtrace
        // information to the end of the display string.
        if ::std::env::var("RUST_BACKTRACE").unwrap_or_else(|_| "".to_string()).as_str() == "1" {
            assert!(err.display().to_string().starts_with("Error: MusicBrainz server error: Your requests are exceeding the allowable rate limit. Please see http://wiki.musicbrainz.org/XMLWebService for more information.\nFor usage, please see: http://musicbrainz.org/development/mmd\n"));

        } else {
            assert_eq!(err.display().to_string(), "Error: MusicBrainz server error: Your requests are exceeding the allowable rate limit. Please see http://wiki.musicbrainz.org/XMLWebService for more information.\nFor usage, please see: http://musicbrainz.org/development/mmd\n".to_string());
        }
    }

    #[test]
    fn ok()
    {
        let context = ::util::musicbrainz_context();
        let reader = XpathStrReader::new(XML_OK, &context).unwrap();

        // should not raise error
        check_response_error(&reader).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate spectra;
#[cfg(feature = "websocket_server")] extern crate ws;

mod mode;
mod msg;
mod server;

use spectra::luminance::render_state::RenderState;
use spectra::luminance::tess::TessSliceIndex;
use spectra::render::framebuffer::Framebuffer2D;
use spectra::render::shader::program::{Program, ProgramKey};
use spectra::render::texture::TextureImage;
use spectra::sys::ignite::{Action, GraphicsContext, Ignite, Key, Surface, WindowEvent, WindowOpt};
use spectra::sys::res;
use spectra::render::fullscreen::Quad;
use std::sync::mpsc::Receiver;

use msg::Msg;
use mode::Mode;
use server::core::{Server, start_server};

#[cfg(not(feature = "websocket_server"))] use server::tcp::TcpServer;
#[cfg(feature = "websocket_server")] use server::ws::WSServer;

#[cfg(feature = "websocket_server")]
fn get_server() -> impl Server {
  WSServer
}

#[cfg(not(feature = "websocket_server"))]
fn get_server() -> impl Server {
  TcpServer
}

fn main() {
  match ignite!(960, 540, WindowOpt::default()) {
    Ok(ignite) => {
      deb!("created ignite");

      let rx = start_server(get_server());

      main_loop(ignite, rx);
      deb!("bye");
    }

    Err(e) => {
      err!("cannot create ignite: {}", e);
    }
  }
}

fn main_loop(mut ignite: Ignite, rx_msg: Receiver<Msg>) {
  let mut back_buffer = Framebuffer2D::back_buffer(ignite.surface().size());
  let clear_color = [0.8, 0.5, 0.5, 1.];

  let mut mode = Mode::default();
  let mut store: res::Store<Ignite> = res::Store::new(res::StoreOpt::default().set_root("data")).expect("resource store creation");

  // for shader toying
  let shadertoy_quad = Quad::new(ignite.surface());

  'l: loop {
    // read events
    for event in ignite.surface().poll_events() {
      match event {
        WindowEvent::Close | WindowEvent::Key(Key::Escape, _, Action::Release, _) => break 'l,

        WindowEvent::FramebufferSize(w, h) => {
          back_buffer = Framebuffer2D::back_buffer([w as u32, h as u32]);
        }
        _ => ()
      }
    }

    for msg in rx_msg.try_iter() {
      match msg {
        msg::Msg::Close => break 'l,

        // we’re asked to load a texture at a given position
        msg::Msg::LoadTexture(path) => {
          let _ = store.get::<_, TextureImage>(&res::FSKey::new(&path), &mut ignite);
        }

        msg::Msg::EmptyMode => {
          mode = Mode::Empty;
        }

        // we’re asked to load and use a shader program in fullscreen mode
        msg::Msg::ShaderToy(name) => {
          let pkey = ProgramKey::new(&name);

          if let Err(e) = store.get::<_, Program<(), (), ()>>(&pkey, &mut ignite) {
            err!("{:?}", e);
          } else {
            mode = Mode::ShaderToy(pkey);
          }
        }
      }
    }

    // perform the render
    let _t = ignite.time();

    let new_mode = match mode {
      Mode::Empty => {
        ignite.surface().pipeline_builder().pipeline(&back_buffer, clear_color, |_, _| {});
        None
      },

      Mode::ShaderToy(ref key) => {
        let program = store.get::<_, Program<(), (), ()>>(key, &mut ignite);

        if let Ok(ref program) = program {
          ignite.surface().pipeline_builder().pipeline(&back_buffer, clear_color, |_, shd_gate| {
            shd_gate.shade(&program.borrow(), |rdr_gate, _| {
              rdr_gate.render(RenderState::default(), |tess_gate| {
                tess_gate.render(ignite.surface(), shadertoy_quad.slice(..));
              });
            });
          });

          None
        } else {
          // fail to use shader toy, go back to empty mode
          Some(Mode::Empty)
        }
      }
    };

    if let Some(new_mode) = new_mode {
      mode = new_mode;
    }

    ignite.surface().swap_buffers();

    store.sync(&mut ignite);
  }
}
<commit_msg>(squash-me) Better conditional compilation!<commit_after>extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate spectra;
#[cfg(feature = "websocket_server")] extern crate ws;

mod mode;
mod msg;
mod server;

use spectra::luminance::render_state::RenderState;
use spectra::luminance::tess::TessSliceIndex;
use spectra::render::framebuffer::Framebuffer2D;
use spectra::render::shader::program::{Program, ProgramKey};
use spectra::render::texture::TextureImage;
use spectra::sys::ignite::{Action, GraphicsContext, Ignite, Key, Surface, WindowEvent, WindowOpt};
use spectra::sys::res;
use spectra::render::fullscreen::Quad;
use std::sync::mpsc::Receiver;

use msg::Msg;
use mode::Mode;
use server::core::{Server, start_server};

#[cfg(not(feature = "websocket_server"))] use server::tcp::TcpServer;
#[cfg(feature = "websocket_server")] use server::ws::WSServer;

fn get_server() -> impl Server {
  #[cfg(feature = "websocket_server")]
  {
    WSServer
  }

  #[cfg(not(feature = "websocket_server"))]
  {
    TcpServer
  }
}

fn main() {
  match ignite!(960, 540, WindowOpt::default()) {
    Ok(ignite) => {
      deb!("created ignite");

      let rx = start_server(get_server());

      main_loop(ignite, rx);
      deb!("bye");
    }

    Err(e) => {
      err!("cannot create ignite: {}", e);
    }
  }
}

fn main_loop(mut ignite: Ignite, rx_msg: Receiver<Msg>) {
  let mut back_buffer = Framebuffer2D::back_buffer(ignite.surface().size());
  let clear_color = [0.8, 0.5, 0.5, 1.];

  let mut mode = Mode::default();
  let mut store: res::Store<Ignite> = res::Store::new(res::StoreOpt::default().set_root("data")).expect("resource store creation");

  // for shader toying
  let shadertoy_quad = Quad::new(ignite.surface());

  'l: loop {
    // read events
    for event in ignite.surface().poll_events() {
      match event {
        WindowEvent::Close | WindowEvent::Key(Key::Escape, _, Action::Release, _) => break 'l,

        WindowEvent::FramebufferSize(w, h) => {
          back_buffer = Framebuffer2D::back_buffer([w as u32, h as u32]);
        }
        _ => ()
      }
    }

    for msg in rx_msg.try_iter() {
      match msg {
        msg::Msg::Close => break 'l,

        // we’re asked to load a texture at a given position
        msg::Msg::LoadTexture(path) => {
          let _ = store.get::<_, TextureImage>(&res::FSKey::new(&path), &mut ignite);
        }

        msg::Msg::EmptyMode => {
          mode = Mode::Empty;
        }

        // we’re asked to load and use a shader program in fullscreen mode
        msg::Msg::ShaderToy(name) => {
          let pkey = ProgramKey::new(&name);

          if let Err(e) = store.get::<_, Program<(), (), ()>>(&pkey, &mut ignite) {
            err!("{:?}", e);
          } else {
            mode = Mode::ShaderToy(pkey);
          }
        }
      }
    }

    // perform the render
    let _t = ignite.time();

    let new_mode = match mode {
      Mode::Empty => {
        ignite.surface().pipeline_builder().pipeline(&back_buffer, clear_color, |_, _| {});
        None
      },

      Mode::ShaderToy(ref key) => {
        let program = store.get::<_, Program<(), (), ()>>(key, &mut ignite);

        if let Ok(ref program) = program {
          ignite.surface().pipeline_builder().pipeline(&back_buffer, clear_color, |_, shd_gate| {
            shd_gate.shade(&program.borrow(), |rdr_gate, _| {
              rdr_gate.render(RenderState::default(), |tess_gate| {
                tess_gate.render(ignite.surface(), shadertoy_quad.slice(..));
              });
            });
          });

          None
        } else {
          // fail to use shader toy, go back to empty mode
          Some(Mode::Empty)
        }
      }
    };

    if let Some(new_mode) = new_mode {
      mode = new_mode;
    }

    ignite.surface().swap_buffers();

    store.sync(&mut ignite);
  }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![crate_id = "codegen#0.1"]

use std::os;
use std::io::BufferedWriter;
use std::io::File;
use std::io;
use std::io::UserDir;
use std::io::stdio::println;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
use std::vec::Vec;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = Vec::from_slice(os::args());
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args.get(2).clone());
            match mkdir_recursive(&output_dir, UserDir) {
                Err(e) => fail!("Could not create directory for generated sources: {:s}", e.desc),
                Ok(_) => {},
            };

            if "keycode.rs" == *args.get(1) {
                match keycode::generate(&output_dir) {
                    Ok(_) => {},
                    Err(e) => fail!("Could not automatically generate sources for keycodes: {:s}", e.desc),
                };
            } else if "scancode.rs" == *args.get(1) {
                match scancode::generate(&output_dir) {
                    Ok(_)    => {},
                    Err(e) => fail!("Could not automatically generate sources for scancodes: {:s}", e.desc),
                };
            } else {
                println!("unknown thing-to-generate '{}'", args.get(1));
                os::set_exit_status(1);
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args.get(0));
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Ok(writer) => BufferedWriter::new(writer),
        Err(e) => fail!("Unable to write file: {:s}", e.desc),
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>#![feature(macro_rules)]
#![crate_id = "codegen#0.1"]

use std::os;
use std::io::BufferedWriter;
use std::io::File;
use std::io;
use std::io::UserDir;
use std::io::stdio::println;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args.get(2).clone());
            match mkdir_recursive(&output_dir, UserDir) {
                Err(e) => fail!("Could not create directory for generated sources: {:s}", e.desc),
                Ok(_) => {},
            };

            if "keycode.rs" == *args.get(1) {
                match keycode::generate(&output_dir) {
                    Ok(_) => {},
                    Err(e) => fail!("Could not automatically generate sources for keycodes: {:s}", e.desc),
                };
            } else if "scancode.rs" == *args.get(1) {
                match scancode::generate(&output_dir) {
                    Ok(_)    => {},
                    Err(e) => fail!("Could not automatically generate sources for scancodes: {:s}", e.desc),
                };
            } else {
                println!("unknown thing-to-generate '{}'", args.get(1));
                os::set_exit_status(1);
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args.get(0));
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Ok(writer) => BufferedWriter::new(writer),
        Err(e) => fail!("Unable to write file: {:s}", e.desc),
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate orbclient;
extern crate orbimage;

use std::cmp::max;
use std::env;

use orbclient::{Color, Renderer, Window, EventOption, K_ESC};
use orbimage::Image;

fn event_loop(window: &mut Window){
    loop {
        for event in window.events() {
            if let EventOption::Key(key_event) = event.to_option() {
                if key_event.pressed && key_event.scancode == K_ESC {
                    return;
                }
            }
            if let EventOption::Quit(_) = event.to_option() {
                return;
            }
        }
    }
}

fn error_msg(window: &mut Window, msg: &str) {
    let mut x = 0;
    for c in msg.chars() {
        window.char(x, 0, c, Color::rgb(0, 0, 0));
        x += 8;
    }
}

fn main() {
    let url = match env::args().nth(1) {
        Some(arg) => arg,
        None => "none:".to_string(),
    };

    match Image::from_path(&url) {
        Ok(image) => {
            let mut window = Window::new(-1, -1, max(320, image.width()), max(32, image.height()),
                                         &("Viewer (".to_string() + &url + ")")).unwrap();

            let box_size = 4;
            for box_y in 0..window.height()/box_size {
                for box_x in 0..window.width()/box_size {
                    let color = if box_x % 2 == box_y % 2 {
                        Color::rgb(102, 102, 102)
                    }else{
                        Color::rgb(53, 53, 53)
                    };

                    window.rect((box_x * box_size) as i32, (box_y * box_size) as i32, box_size, box_size, color);
                }
            }

            image.draw(&mut window, 0, 0);
            window.sync();
            event_loop(&mut window);
        },
        Err(err) => {
            let mut window = Window::new(-1,
                                         -1,
                                         320,
                                         32,
                                         &("Viewer (".to_string() + &url + ")"))
                                 .unwrap();
            window.set(Color::rgb(255, 255, 255));
            error_msg(&mut window, &format!("{}", err));
            window.sync();
            event_loop(&mut window);
        }
    }
}
<commit_msg>Open background by default<commit_after>#![deny(warnings)]

extern crate orbclient;
extern crate orbimage;

use std::cmp::max;
use std::env;

use orbclient::{Color, Renderer, Window, EventOption, K_ESC};
use orbimage::Image;

fn event_loop(window: &mut Window){
    loop {
        for event in window.events() {
            if let EventOption::Key(key_event) = event.to_option() {
                if key_event.pressed && key_event.scancode == K_ESC {
                    return;
                }
            }
            if let EventOption::Quit(_) = event.to_option() {
                return;
            }
        }
    }
}

fn error_msg(window: &mut Window, msg: &str) {
    let mut x = 0;
    for c in msg.chars() {
        window.char(x, 0, c, Color::rgb(0, 0, 0));
        x += 8;
    }
}

fn main() {
    let url = match env::args().nth(1) {
        Some(arg) => arg,
        None => "/ui/background.png".to_string(),
    };

    match Image::from_path(&url) {
        Ok(image) => {
            let mut window = Window::new(-1, -1, max(320, image.width()), max(32, image.height()),
                                         &("Viewer (".to_string() + &url + ")")).unwrap();

            let box_size = 4;
            for box_y in 0..window.height()/box_size {
                for box_x in 0..window.width()/box_size {
                    let color = if box_x % 2 == box_y % 2 {
                        Color::rgb(102, 102, 102)
                    }else{
                        Color::rgb(53, 53, 53)
                    };

                    window.rect((box_x * box_size) as i32, (box_y * box_size) as i32, box_size, box_size, color);
                }
            }

            image.draw(&mut window, 0, 0);
            window.sync();
            event_loop(&mut window);
        },
        Err(err) => {
            let mut window = Window::new(-1,
                                         -1,
                                         320,
                                         32,
                                         &("Viewer (".to_string() + &url + ")"))
                                 .unwrap();
            window.set(Color::rgb(255, 255, 255));
            error_msg(&mut window, &format!("{}", err));
            window.sync();
            event_loop(&mut window);
        }
    }
}
<|endoftext|>


<commit_before>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

/// Handler called for the `/std`. Redirects to the official standard library docs.
pub fn std_redirector_handler(_req: &mut Request) -> IronResult<Response> {
    let url = Url::parse("https://doc.rust-lang.org/std/").unwrap();
    Ok(Response::with((status::Found, Redirect(url))))
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with("/") {
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let latest_version = latest_version(&crate_details.versions, &version);

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", latest_version.is_none())
        .set("latest_version", &latest_version.unwrap_or(String::new()))
        .to_resp("rustdoc")
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<commit_msg>Update std doc url to specifically link to stable.<commit_after>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

/// Handler called for the `/std`. Redirects to the official standard library docs.
pub fn std_redirector_handler(_req: &mut Request) -> IronResult<Response> {
    let url = Url::parse("https://doc.rust-lang.org/stable/std/").unwrap();
    Ok(Response::with((status::Found, Redirect(url))))
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with("/") {
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let latest_version = latest_version(&crate_details.versions, &version);

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", latest_version.is_none())
        .set("latest_version", &latest_version.unwrap_or(String::new()))
        .to_resp("rustdoc")
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<|endoftext|>


<commit_before>use std::old_io as io;
use std::sync::mpsc;

use std::path::Path as StdPath;

//================================================================================
// Misc typedefs:
//================================================================================
pub type Path = StdPath;
pub type NotifyResult<T> = io::IoResult<T>;
pub type R = NotifyResult<()>;

//================================================================================
// Recursion:
//================================================================================
pub type RecursionLimit = Option<usize>;
pub struct RecursionConfig<'a> {
	limit: RecursionLimit,
	filter: Fn( &Path ) -> bool + 'a
}

//================================================================================
// Events:
//================================================================================

mod operations;
use self::operations::Operations;

pub struct Event {
	pub path: Option<Path>,
	pub op: NotifyResult<Operations>,
}

pub type EventSender = mpsc::Sender<Event>;

//================================================================================
// Notifier trait:
//================================================================================
pub trait FsNotifier : Drop {
	fn new( sender: EventSender, recursion_limit: RecursionConfig, follow_symlinks: bool ) -> NotifyResult<Self>;

	fn add( &self, path: &Path, subscribe: Operations ) -> R;

	fn remove( &self, path: &Path ) -> R;

	fn start( &self ) -> R;

	fn stop( &self ) -> R;
}<commit_msg>modified FsNotifer, all cfg in one type.<commit_after>use std::old_io as io;
use std::sync::mpsc;

use std::path::Path as StdPath;

//================================================================================
// Misc typedefs:
//================================================================================
pub type Path = StdPath;
pub type NotifyResult<T> = io::IoResult<T>;
pub type R = NotifyResult<()>;

//================================================================================
// Configuration:
//================================================================================
pub type RecursionLimit = Option<usize>;
pub struct Configuration<'a> {
	subscribe: Operations,
	follow_symlinks: bool,
	recursion_limit: RecursionLimit,
	recursion_filter: Fn( &Path ) -> bool + 'a
}

//================================================================================
// Events:
//================================================================================

mod operations;
use self::operations::Operations;

pub struct Event {
	pub path: Option<Path>,
	pub op: NotifyResult<Operations>,
}

pub type EventSender = mpsc::Sender<Event>;

//================================================================================
// Notifier trait:
//================================================================================
pub trait FsNotifier : Drop {
	fn new( sender: EventSender, config: Configuration ) -> NotifyResult<Self>;

	fn add( &self, path: &Path ) -> R;

	fn remove( &self, path: &Path ) -> R;

	fn start( &self ) -> R;

	fn stop( &self ) -> R;
}<|endoftext|>


<commit_before>use diesel;
use diesel::prelude::*;

use rocket_contrib::{JSON, SerdeError};

use helpers::db::DB;
use validation::user::{UserSerializer, UserSettingsSerializer};

use schema::{users, pods, queues};
use schema::users::dsl::*;

use models::user::{UserModel, NewUser, ChangedUser};
use models::pod::{PodModel, NewPod};
use models::queue::{QueueModel, NewQueue};

use responses::{
    APIResponse,
    ok,
    created,
    conflict,
    bad_request,
    forbidden,
    unauthorized,
};

#[get("/info")]
pub fn info(current_user: UserModel) -> APIResponse {
    ok().data(json!(current_user))
}

#[post("/register", data = "<user_data>", format = "application/json")]
pub fn register(user_data: Result<JSON<UserSerializer>, SerdeError>, db: DB) -> APIResponse {

    match user_data {
        // Return specific error if invalid JSON has been sent.
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(data) =>  {
             // Check for existing user email
            let results = users.filter(email.eq(data.email.clone()))
                .first::<UserModel>(&*db);
            if results.is_ok() {
                return conflict().message("Nickname already taken.");
            }
             // Create new password hash
            let new_password_hash = UserModel::make_password_hash(data.password.as_str());

            // New user model for table insertion
            let new_user = NewUser {
                nickname: data.nickname.clone(),
                email: data.email.clone(),
                password_hash: new_password_hash,
            };

            // Insert user to get id for pod
            let user = diesel::insert(&new_user)
                .into(users::table)
                .get_result::<UserModel>(&*db)
                .expect("Error saving new user");

            // New pod
            let new_pod = NewPod {
                name: format!("{}'s Pod", user.nickname.clone()),
                user_id: user.id.clone(),
            };

            let pod = diesel::insert(&new_pod)
                .into(pods::table)
                .get_result::<PodModel>(&*db)
                .expect("Error creating pod");

            let new_queue = NewQueue {
                slots: 2,
                pod_id: Some(pod.id.clone()),
                base_id: None,
            };

            diesel::insert(&new_queue)
                .into(queues::table)
                .get_result::<QueueModel>(&*db)
                .expect("Error creating pod's queue");

            return created().message("User created.").data(json!(&user));
        }
    }
}

#[post("/settings", data = "<user_data>", format = "application/json")]
pub fn settings(current_user: UserModel, user_data: Result<JSON<UserSettingsSerializer>, SerdeError>, db: DB) -> APIResponse {

    // Return specific error if invalid JSON has been sent.
    match user_data {
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(data) =>  {
            let mut new_password_hash: Option<String> = None;
            match data.new_password.as_ref() {
                Some(new_password) => {
                    match data.password.as_ref() {
                        Some(old_password) => {
                            if !current_user.verify_password(old_password.as_str()) {
                                return unauthorized().message("Incorrect password.");
                            }
                            new_password_hash = Some(UserModel::make_password_hash(new_password.as_str()))
                        }
                        None => return forbidden().message("The current passwords needs to be \
                                    specified, if you want to change your password."),
                    }
                }
                None => (),
            };

            let changed_user = ChangedUser {
                nickname: data.nickname.clone(),
                email: data.email.clone(),
                password_hash: new_password_hash,
            };

            let user = diesel::update(users.filter(id.eq(current_user.id)))
                .set(&changed_user)
                .get_result::<UserModel>(&*db)
                .expect("Failed to update user.");

            ok().message("User data changed.").data(json!(&user))
        }
    }
}
<commit_msg>Comments<commit_after>use diesel;
use diesel::prelude::*;

use rocket_contrib::{JSON, SerdeError};

use helpers::db::DB;
use validation::user::{UserSerializer, UserSettingsSerializer};

use schema::{users, pods, queues};
use schema::users::dsl::*;

use models::user::{UserModel, NewUser, ChangedUser};
use models::pod::{PodModel, NewPod};
use models::queue::{QueueModel, NewQueue};

use responses::{
    APIResponse,
    ok,
    created,
    conflict,
    bad_request,
    forbidden,
    unauthorized,
};

#[get("/info")]
pub fn info(current_user: UserModel) -> APIResponse {
    ok().data(json!(current_user))
}

#[post("/register", data = "<user_data>", format = "application/json")]
pub fn register(user_data: Result<JSON<UserSerializer>, SerdeError>, db: DB) -> APIResponse {

    match user_data {
        // Return specific error if invalid JSON has been sent.
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(data) =>  {
             // Check for existing user email
            let results = users.filter(email.eq(data.email.clone()))
                .first::<UserModel>(&*db);
            if results.is_ok() {
                return conflict().message("Nickname already taken.");
            }
             // Create new password hash
            let new_password_hash = UserModel::make_password_hash(data.password.as_str());

            // New user model for table insertion
            let new_user = NewUser {
                nickname: data.nickname.clone(),
                email: data.email.clone(),
                password_hash: new_password_hash,
            };

            // Insert user to get id for pod
            let user = diesel::insert(&new_user)
                .into(users::table)
                .get_result::<UserModel>(&*db)
                .expect("Error saving new user");

            // New pod
            let new_pod = NewPod {
                name: format!("{}'s Pod", user.nickname.clone()),
                user_id: user.id.clone(),
            };

            let pod = diesel::insert(&new_pod)
                .into(pods::table)
                .get_result::<PodModel>(&*db)
                .expect("Error creating pod");

            let new_queue = NewQueue {
                slots: 2,
                pod_id: Some(pod.id.clone()),
                base_id: None,
            };

            diesel::insert(&new_queue)
                .into(queues::table)
                .get_result::<QueueModel>(&*db)
                .expect("Error creating pod's queue");

            return created().message("User created.").data(json!(&user));
        }
    }
}

#[post("/settings", data = "<user_data>", format = "application/json")]
pub fn settings(current_user: UserModel, user_data: Result<JSON<UserSettingsSerializer>, SerdeError>, db: DB) -> APIResponse {

    // Return specific error if invalid JSON has been sent.
    match user_data {
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(data) =>  {
            let mut new_password_hash: Option<String> = None;
            // Check if a new password is provided.
            // In case it is, we want the old password to verify the identity of the client.
            match data.new_password.as_ref() {
                Some(new_password) => {
                    match data.password.as_ref() {
                        Some(old_password) => {
                            if !current_user.verify_password(old_password.as_str()) {
                                return unauthorized().message("Incorrect password.");
                            }
                            new_password_hash = Some(UserModel::make_password_hash(new_password.as_str()))
                        }
                        None => return forbidden().message("The current passwords needs to be \
                                    specified, if you want to change your password."),
                    }
                }
                None => (),
            };

            let changed_user = ChangedUser {
                nickname: data.nickname.clone(),
                email: data.email.clone(),
                password_hash: new_password_hash,
            };

            let user = diesel::update(users.filter(id.eq(current_user.id)))
                .set(&changed_user)
                .get_result::<UserModel>(&*db)
                .expect("Failed to update user.");

            ok().message("User data changed.").data(json!(&user))
        }
    }
}
<|endoftext|>