Skip to content

Commit

Permalink
stats
Browse files Browse the repository at this point in the history
  • Loading branch information
istudyatuni committed Jun 12, 2024
1 parent 9d0d80c commit 9767d5e
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 6 deletions.
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ DATABASE_URL=data.db

JWT_SECRET=
ALLOW_NEW_REGISTER=true
# ADMIN_API=/admin
2 changes: 1 addition & 1 deletion docs/api/environments/kotync.bru
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
vars {
base: http://localhost:8081
base: http://localhost:8080
}
vars:secret [
token
Expand Down
11 changes: 11 additions & 0 deletions docs/api/get stats.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
meta {
name: get stats
type: http
seq: 8
}

get {
url: {{base}}/admin/stats
body: none
auth: none
}
2 changes: 2 additions & 0 deletions docs/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ services:
DATABASE_NAME: kotatsu_db
JWT_SECRET: SECRET
ALLOW_NEW_REGISTER: true
# ADMIN_API: /ADMIN
# RUST_LOG: info
ports:
- 8081:8080
Expand All @@ -50,6 +51,7 @@ services:
DATABASE_URL: /app/data/data.db
JWT_SECRET: SECRET
ALLOW_NEW_REGISTER: true
# ADMIN_API: /ADMIN
# RUST_LOG: info
ports:
- 8081:8080
Expand Down
4 changes: 2 additions & 2 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ docker run -d -p 8081:8080 \

### Note on MySQL

*_When using `docker`_*
***When using `docker`***

You should allow your mysql user to connect from `172.17.0.2`\*. To do this, connect to mysql under root user (via `sudo mysql`), and execute:

Expand All @@ -59,7 +59,7 @@ GRANT ALL PRIVILEGES ON kotatsu_db.* TO 'some_user'@'172.17.0.%';

After that, set `DATABASE_HOST=172.17.0.1`.

*_When using `docker compose`_*
***When using `docker compose`***

MySQL user is created on startup with all permissions, if you want to set more granular permissions, you should allow user to connect from within docker network. To do this, first run `docker compose up -d db`, then connect to mariadb under root user (via `sudo mysql` or `sudo mariadb`), and execute:

Expand Down
8 changes: 8 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub struct Conf {
pub jwt: ConfJWT,
#[config(env = "ALLOW_NEW_REGISTER", default = true)]
pub allow_new_register: bool,
#[config(env = "ADMIN_API")]
pub admin_api: Option<String>,
}

#[derive(Debug, Clone, confique::Config)]
Expand Down Expand Up @@ -78,6 +80,12 @@ impl Display for Conf {
f.pad(&self.jwt.audience)?;
f.pad("\n allow_new_register: ")?;
self.allow_new_register.fmt(f)?;
f.pad("\n admin_api: ")?;
if let Some(admin_api) = &self.admin_api {
f.pad(admin_api)?;
} else {
f.pad("[empty]")?;
}

Ok(())
}
Expand Down
17 changes: 17 additions & 0 deletions src/db/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use diesel::{mysql::Mysql as Backend, prelude::MysqlConnection as DbConnection};
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};

use crate::config::ConfDB;
use crate::models::admin::DBStats;
use crate::models::common::HistoryPackage;
use crate::models::db::{History, MangaTags};
use crate::models::{
Expand Down Expand Up @@ -356,6 +357,22 @@ impl DB {
}
}

// admin
impl DB {
pub fn stats(&self) -> Result<DBStats> {
use super::schema::manga::table as manga;
use super::schema::users::table as users;

let conn = &mut self.pool()?;
let users_count: i64 = users.count().get_result(conn)?;
let manga_count: i64 = manga.count().get_result(conn)?;
Ok(DBStats {
users_count: users_count as u32,
manga_count: manga_count as u64,
})
}
}

fn migrate(conn: &mut impl MigrationHarness<Backend>) -> Result<()> {
conn.run_pending_migrations(MIGRATIONS)
.map_err(|e| anyhow!("failed to run migrations: {e}"))?;
Expand Down
13 changes: 11 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ async fn main() -> Result<()> {
fn rocket(config: Conf, db: DB) -> Result<Rocket<Build>> {
CONFIG.get_or_init(|| config.clone());

let rocket = rocket::build()
let mut rocket = rocket::build()
.configure(rocket::Config {
port: 8080,
address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
..Default::default()
})
.manage(config)
.manage(config.clone())
.manage(db)
.mount(
"/",
Expand All @@ -81,6 +81,15 @@ fn rocket(config: Conf, db: DB) -> Result<Rocket<Build>> {
routes::resource::get_history,
],
);

if let Some(admin) = &config.admin_api {
if !admin.starts_with('/') {
log::error!("ADMIN_API should start with /");
return Err(anyhow!("invalid env, exiting"));
}
rocket = rocket.mount(admin, routes![routes::admin::stats]);
}

Ok(rocket)
}

Expand Down
8 changes: 8 additions & 0 deletions src/models/admin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use serde::Serialize;

#[derive(Debug, Serialize)]
#[cfg_attr(test, derive(serde::Deserialize))]
pub struct DBStats {
pub users_count: u32,
pub manga_count: u64,
}
1 change: 1 addition & 0 deletions src/models/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use unicode_segmentation::UnicodeSegmentation;

pub mod admin;
pub mod common;
pub mod db;
pub mod request;
Expand Down
15 changes: 15 additions & 0 deletions src/routes/admin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use rocket::{get, http::Status, serde::json::Json, State};

use crate::{db::conn::DB, models::admin::DBStats};

use super::{Response, ResponseData};

#[get("/stats")]
pub fn stats(db: &State<DB>) -> Response<Json<DBStats>> {
let stats = db.stats().map_err(|e| {
log::error!("failed to load stats: {e}");
ResponseData::Status(Status::InternalServerError)
})?;

Ok(ResponseData::Body(Json(stats)))
}
1 change: 1 addition & 0 deletions src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
request::{ApiToken, AuthError},
};

pub mod admin;
pub mod base;
pub mod resource;

Expand Down
47 changes: 46 additions & 1 deletion src/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ use rocket::{

use crate::{
current_timestamp,
models::{common, request, response},
models::{admin::DBStats, common, request, response},
routes,
};

use utils::*;

static ADMIN: Origin<'static> = uri!("/admin");
static RESOURCE: Origin<'static> = uri!("/resource");

#[test]
Expand Down Expand Up @@ -319,6 +320,49 @@ fn test_get_manga() -> Result<()> {
Ok(())
}

#[test]
fn test_empty_stats() -> Result<()> {
let client = prepare_client()?;

let resp = client
.get(uri!(ADMIN.clone(), routes::admin::stats))
.dispatch();
assert_eq!(resp.status(), Status::Ok);
let resp: DBStats = resp.into_json().unwrap();

assert_eq!(resp.users_count, 0);
assert_eq!(resp.manga_count, 0);

Ok(())
}

#[test]
fn test_stats() -> Result<()> {
let client = prepare_client()?;
let auth = make_user(&client);

let data = data::favourites_package();

let resp = client
.post(uri!(RESOURCE.clone(), routes::resource::save_favourites))
.json(&data)
.header(Header::new(AUTHORIZATION.as_str(), auth))
.dispatch();

assert_eq!(resp.status(), Status::Ok);

let resp = client
.get(uri!(ADMIN.clone(), routes::admin::stats))
.dispatch();
assert_eq!(resp.status(), Status::Ok);
let resp: DBStats = resp.into_json().unwrap();

assert_eq!(resp.users_count, 1);
assert_eq!(resp.manga_count, 1);

Ok(())
}

mod data {
use crate::{
current_timestamp,
Expand Down Expand Up @@ -475,6 +519,7 @@ pub mod utils {
audience: "http://example.com/resource".to_string(),
},
allow_new_register,
admin_api: Some("/admin".to_string()),
};
Ok(Client::untracked(rocket(config, db)?)?)
}
Expand Down

0 comments on commit 9767d5e

Please sign in to comment.