Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 26 additions & 43 deletions src/controllers/krate/follow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@ use crate::auth::AuthCheck;
use crate::controllers::helpers::ok_true;
use crate::models::{Crate, Follow};
use crate::schema::*;
use crate::tasks::spawn_blocking;
use crate::util::diesel::prelude::*;
use crate::util::diesel::Conn;
use crate::util::errors::{crate_not_found, AppResult};
use axum::extract::Path;
use axum::response::Response;
use axum::Json;
use diesel_async::async_connection_wrapper::AsyncConnectionWrapper;
use diesel::prelude::*;
use diesel_async::{AsyncPgConnection, RunQueryDsl};
use http::request::Parts;
use serde_json::Value;

fn follow_target(crate_name: &str, conn: &mut impl Conn, user_id: i32) -> AppResult<Follow> {
use diesel::RunQueryDsl;

async fn follow_target(
crate_name: &str,
conn: &mut AsyncPgConnection,
user_id: i32,
) -> AppResult<Follow> {
let crate_id = Crate::by_name(crate_name)
.select(crates::id)
.first(conn)
.await
.optional()?
.ok_or_else(|| crate_not_found(crate_name))?;

Expand All @@ -36,20 +37,14 @@ pub async fn follow(
) -> AppResult<Response> {
let mut conn = app.db_write().await?;
let user_id = AuthCheck::default().check(&req, &mut conn).await?.user_id();
spawn_blocking(move || {
use diesel::RunQueryDsl;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();

let follow = follow_target(&crate_name, conn, user_id)?;
diesel::insert_into(follows::table)
.values(&follow)
.on_conflict_do_nothing()
.execute(conn)?;

ok_true()
})
.await
let follow = follow_target(&crate_name, &mut conn, user_id).await?;
diesel::insert_into(follows::table)
.values(&follow)
.on_conflict_do_nothing()
.execute(&mut conn)
.await?;

ok_true()
}

/// Handles the `DELETE /crates/:crate_id/follow` route.
Expand All @@ -60,17 +55,10 @@ pub async fn unfollow(
) -> AppResult<Response> {
let mut conn = app.db_write().await?;
let user_id = AuthCheck::default().check(&req, &mut conn).await?.user_id();
spawn_blocking(move || {
use diesel::RunQueryDsl;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();
let follow = follow_target(&crate_name, &mut conn, user_id).await?;
diesel::delete(&follow).execute(&mut conn).await?;

let follow = follow_target(&crate_name, conn, user_id)?;
diesel::delete(&follow).execute(conn)?;

ok_true()
})
.await
ok_true()
}

/// Handles the `GET /crates/:crate_id/following` route.
Expand All @@ -79,23 +67,18 @@ pub async fn following(
Path(crate_name): Path<String>,
req: Parts,
) -> AppResult<Json<Value>> {
use diesel::dsl::exists;

let mut conn = app.db_read_prefer_primary().await?;
let user_id = AuthCheck::only_cookie()
.check(&req, &mut conn)
.await?
.user_id();
spawn_blocking(move || {
use diesel::RunQueryDsl;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();

use diesel::dsl::exists;

let follow = follow_target(&crate_name, conn, user_id)?;
let following =
diesel::select(exists(follows::table.find(follow.id()))).get_result::<bool>(conn)?;
let follow = follow_target(&crate_name, &mut conn, user_id).await?;
let following = diesel::select(exists(follows::table.find(follow.id())))
.get_result::<bool>(&mut conn)
.await?;

Ok(Json(json!({ "following": following })))
})
.await
Ok(Json(json!({ "following": following })))
}
104 changes: 44 additions & 60 deletions src/controllers/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,25 @@ pub async fn list(
Query(params): Query<GetParams>,
req: Parts,
) -> AppResult<Json<Value>> {
use diesel_async::RunQueryDsl;

let mut conn = app.db_read_prefer_primary().await?;
let auth = AuthCheck::only_cookie().check(&req, &mut conn).await?;
spawn_blocking(move || {
use diesel::RunQueryDsl;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();

let user = auth.user();
let user = auth.user();

let tokens: Vec<ApiToken> = ApiToken::belonging_to(user)
.select(ApiToken::as_select())
.filter(api_tokens::revoked.eq(false))
.filter(
api_tokens::expired_at.is_null().or(api_tokens::expired_at
.assume_not_null()
.gt(now - params.expired_days_interval())),
)
.order(api_tokens::id.desc())
.load(&mut conn)
.await?;

let tokens: Vec<ApiToken> = ApiToken::belonging_to(user)
.select(ApiToken::as_select())
.filter(api_tokens::revoked.eq(false))
.filter(
api_tokens::expired_at.is_null().or(api_tokens::expired_at
.assume_not_null()
.gt(now - params.expired_days_interval())),
)
.order(api_tokens::id.desc())
.load(conn)?;

Ok(Json(json!({ "api_tokens": tokens })))
})
.await
Ok(Json(json!({ "api_tokens": tokens })))
}

/// The incoming serialization format for the `ApiToken` model.
Expand Down Expand Up @@ -175,63 +171,51 @@ pub async fn new(

/// Handles the `GET /me/tokens/:id` route.
pub async fn show(app: AppState, Path(id): Path<i32>, req: Parts) -> AppResult<Json<Value>> {
use diesel_async::RunQueryDsl;

let mut conn = app.db_write().await?;
let auth = AuthCheck::default().check(&req, &mut conn).await?;
spawn_blocking(move || {
use diesel::RunQueryDsl;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();

let user = auth.user();
let token = ApiToken::belonging_to(user)
.find(id)
.select(ApiToken::as_select())
.first(conn)?;

Ok(Json(json!({ "api_token": token })))
})
.await
let user = auth.user();
let token = ApiToken::belonging_to(user)
.find(id)
.select(ApiToken::as_select())
.first(&mut conn)
.await?;

Ok(Json(json!({ "api_token": token })))
}

/// Handles the `DELETE /me/tokens/:id` route.
pub async fn revoke(app: AppState, Path(id): Path<i32>, req: Parts) -> AppResult<Json<Value>> {
use diesel_async::RunQueryDsl;

let mut conn = app.db_write().await?;
let auth = AuthCheck::default().check(&req, &mut conn).await?;
spawn_blocking(move || {
use diesel::RunQueryDsl;
let user = auth.user();
diesel::update(ApiToken::belonging_to(user).find(id))
.set(api_tokens::revoked.eq(true))
.execute(&mut conn)
.await?;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();

let user = auth.user();
diesel::update(ApiToken::belonging_to(user).find(id))
.set(api_tokens::revoked.eq(true))
.execute(conn)?;

Ok(Json(json!({})))
})
.await
Ok(Json(json!({})))
}

/// Handles the `DELETE /tokens/current` route.
pub async fn revoke_current(app: AppState, req: Parts) -> AppResult<Response> {
use diesel_async::RunQueryDsl;

let mut conn = app.db_write().await?;
let auth = AuthCheck::default().check(&req, &mut conn).await?;
spawn_blocking(move || {
use diesel::RunQueryDsl;
let api_token_id = auth
.api_token_id()
.ok_or_else(|| bad_request("token not provided"))?;

let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into();
diesel::update(api_tokens::table.filter(api_tokens::id.eq(api_token_id)))
.set(api_tokens::revoked.eq(true))
.execute(&mut conn)
.await?;

let api_token_id = auth
.api_token_id()
.ok_or_else(|| bad_request("token not provided"))?;

diesel::update(api_tokens::table.filter(api_tokens::id.eq(api_token_id)))
.set(api_tokens::revoked.eq(true))
.execute(conn)?;

Ok(StatusCode::NO_CONTENT.into_response())
})
.await
Ok(StatusCode::NO_CONTENT.into_response())
}

struct NewTokenEmail<'a> {
Expand Down
Loading