Skip to content

Split krate and version functionality into submodules #1102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Oct 18, 2017
73 changes: 73 additions & 0 deletions src/krate/downloads.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! Endpoint for exposing crate download counts
//!
//! The enpoints for download a crate and exposing version specific
//! download counts are located in `krate::downloads`.

use std::cmp;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use diesel::prelude::*;

use db::RequestTransaction;
use download::{EncodableVersionDownload, VersionDownload};
use schema::*;
use util::{CargoResult, RequestUtils};
use Version;

use super::{to_char, Crate};

/// Handles the `GET /crates/:crate_id/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
use diesel::expression::dsl::*;
use diesel::types::BigInt;

let crate_name = &req.params()["crate_id"];
let conn = req.db_conn()?;
let krate = Crate::by_name(crate_name).first::<Crate>(&*conn)?;

let mut versions = Version::belonging_to(&krate).load::<Version>(&*conn)?;
versions.sort_by(|a, b| b.num.cmp(&a.num));
let (latest_five, rest) = versions.split_at(cmp::min(5, versions.len()));

let downloads = VersionDownload::belonging_to(latest_five)
.filter(version_downloads::date.gt(date(now - 90.days())))
.order(version_downloads::date.asc())
.load(&*conn)?
.into_iter()
.map(VersionDownload::encodable)
.collect::<Vec<_>>();

let sum_downloads = sql::<BigInt>("SUM(version_downloads.downloads)");
let extra = VersionDownload::belonging_to(rest)
.select((
to_char(version_downloads::date, "YYYY-MM-DD"),
sum_downloads,
))
.filter(version_downloads::date.gt(date(now - 90.days())))
.group_by(version_downloads::date)
.order(version_downloads::date.asc())
.load::<ExtraDownload>(&*conn)?;

#[derive(Serialize, Queryable)]
struct ExtraDownload {
date: String,
downloads: i64,
}
#[derive(Serialize)]
struct R {
version_downloads: Vec<EncodableVersionDownload>,
meta: Meta,
}
#[derive(Serialize)]
struct Meta {
extra_downloads: Vec<ExtraDownload>,
}
let meta = Meta {
extra_downloads: extra,
};
Ok(req.json(&R {
version_downloads: downloads,
meta: meta,
}))
}
68 changes: 68 additions & 0 deletions src/krate/follow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! Endpoints for managing a per user list of followed crates

use conduit::{Request, Response};
use conduit_router::RequestParams;
use diesel::associations::Identifiable;
use diesel::pg::upsert::*;
use diesel::prelude::*;
use diesel;

use db::RequestTransaction;
use schema::*;
use user::RequestUser;
use util::{CargoResult, RequestUtils};

use super::{Crate, Follow};

fn follow_target(req: &mut Request) -> CargoResult<Follow> {
let user = req.user()?;
let conn = req.db_conn()?;
let crate_name = &req.params()["crate_id"];
let crate_id = Crate::by_name(crate_name).select(crates::id).first(&*conn)?;
Ok(Follow {
user_id: user.id,
crate_id: crate_id,
})
}

/// Handles the `PUT /crates/:crate_id/follow` route.
pub fn follow(req: &mut Request) -> CargoResult<Response> {
let follow = follow_target(req)?;
let conn = req.db_conn()?;
diesel::insert(&follow.on_conflict_do_nothing())
.into(follows::table)
.execute(&*conn)?;
#[derive(Serialize)]
struct R {
ok: bool,
}
Ok(req.json(&R { ok: true }))
}

/// Handles the `DELETE /crates/:crate_id/follow` route.
pub fn unfollow(req: &mut Request) -> CargoResult<Response> {
let follow = follow_target(req)?;
let conn = req.db_conn()?;
diesel::delete(&follow).execute(&*conn)?;
#[derive(Serialize)]
struct R {
ok: bool,
}
Ok(req.json(&R { ok: true }))
}

/// Handles the `GET /crates/:crate_id/following` route.
pub fn following(req: &mut Request) -> CargoResult<Response> {
use diesel::expression::dsl::exists;

let follow = follow_target(req)?;
let conn = req.db_conn()?;
let following = diesel::select(exists(follows::table.find(follow.id()))).get_result(&*conn)?;
#[derive(Serialize)]
struct R {
following: bool,
}
Ok(req.json(&R {
following: following,
}))
}
Loading