Skip to content

Commit

Permalink
Add groups list endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
fiji-flo committed Feb 14, 2020
1 parent 123c88a commit b0e068a
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 4 deletions.
1 change: 1 addition & 0 deletions migrations/2020-02-14-142048_groupslist/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP VIEW groups_list;
1 change: 1 addition & 0 deletions migrations/2020-02-14-142048_groupslist/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE VIEW groups_list AS SELECT groups.name, groups.typ, groups.trust, count(memberships.user_uuid) as members_count FROM groups JOIN memberships ON groups.group_id = memberships.group_id GROUP BY groups.group_id;
59 changes: 59 additions & 0 deletions openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,65 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/GenericError"
get:
summary: paginated groups
description: |
get paginated list of a groups
parameters:
- in: query
name: f
description: filter results based on name prefix
required: false
schema:
type: string
- in: query
name: by
description: order by
required: false
schema:
type: string
enum: ["MemberCount", "NameAsc", "NameDesc"]
- in: query
name: "n"
description: next page id (offset)
required: false
schema:
type: integer
default: 0
- in: query
name: s
description: size of the result
required: false
schema:
type: integer
default: 20
responses:
"200":
description: a page of members
content:
application/json:
schema:
type: object
properties:
members:
type: array
items:
$ref: "#/components/schemas/DisplayMember"
next:
type: integer
example: 20
"400":
description: bad request
content:
application/json:
schema:
$ref: "#/components/schemas/GenericError"
"403":
description: operation forbidden
content:
application/json:
schema:
$ref: "#/components/schemas/GenericError"
"/groups/api/v1/groups/{groupName}":
get:
summary: group information
Expand Down
34 changes: 31 additions & 3 deletions src/api/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::api::models::GroupInfo;
use crate::db::operations;
use crate::db::operations::models::GroupUpdate;
use crate::db::operations::models::NewGroup;
use crate::db::operations::models::SortGroupsBy;
use crate::db::types::*;
use crate::db::Pool;
use crate::utils::valid_group_name;
Expand All @@ -16,11 +17,34 @@ use actix_web::Responder;
use cis_client::CisClient;
use dino_park_gate::scope::ScopeAndUser;
use log::info;
use serde_derive::Deserialize;
use std::sync::Arc;

#[derive(Deserialize)]
struct ListGroupsQuery {
f: Option<String>,
#[serde(default)]
n: i64,
#[serde(default = "default_groups_list_size")]
s: i64,
#[serde(default)]
by: SortGroupsBy,
}

fn default_groups_list_size() -> i64 {
20
}

#[guard(Authenticated)]
async fn get_group(pool: web::Data<Pool>, group_name: web::Path<String>) -> impl Responder {
operations::groups::get_group(&pool, &group_name)
.map(|group| HttpResponse::Ok().json(group))
operations::groups::get_group(&pool, &group_name).map(|group| HttpResponse::Ok().json(group))
}

#[guard(Authenticated)]
async fn list_groups(pool: web::Data<Pool>, query: web::Query<ListGroupsQuery>) -> impl Responder {
let query = query.into_inner();
operations::groups::list_groups(&pool, query.f, query.by, query.s, query.n)
.map(|groups| HttpResponse::Ok().json(groups))
.map_err(ApiError::GenericBadRequest)
}

Expand Down Expand Up @@ -142,7 +166,11 @@ pub fn groups_app() -> impl HttpServiceFactory {
.max_age(3600)
.finish(),
)
.service(web::resource("").route(web::post().to(add_group)))
.service(
web::resource("")
.route(web::post().to(add_group))
.route(web::get().to(list_groups)),
)
.service(
web::resource("/{group_name}")
.route(web::get().to(get_group))
Expand Down
29 changes: 28 additions & 1 deletion src/db/internal/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ use crate::db::model::*;
use crate::db::operations::models::GroupUpdate;
use crate::db::operations::models::GroupWithTermsFlag;
use crate::db::operations::models::NewGroup;
use crate::db::operations::models::PaginatedGroupsLists;
use crate::db::operations::models::SortGroupsBy;
use crate::db::schema;
use crate::db::types::*;

use crate::db::views;
use diesel::dsl::exists;
use diesel::dsl::select;
use diesel::prelude::*;
use failure::Error;
use serde_json::Value;
use std::convert::TryFrom;
use uuid::Uuid;

pub fn get_group_with_terms_flag(
Expand Down Expand Up @@ -182,3 +185,27 @@ pub fn groups_for_user(connection: &PgConnection, user_uuid: &Uuid) -> Result<Ve
.get_results::<Group>(connection)
.map_err(Into::into)
}

pub fn list_groups(
connection: &PgConnection,
filter: Option<String>,
sort_by: SortGroupsBy,
limit: i64,
offset: i64,
) -> Result<PaginatedGroupsLists, Error> {
let mut query = views::groups_list::table.into_boxed();
if let Some(filter) = filter {
query = query.filter(views::groups_list::name.ilike(format!("{}%", filter)))
};
query = match sort_by {
SortGroupsBy::MembersCount => query.order(views::groups_list::members_count.desc()),
SortGroupsBy::NameAsc => query.order(views::groups_list::name.asc()),
SortGroupsBy::NameDesc => query.order(views::groups_list::name.desc()),
};
let groups: Vec<GroupsList> = query.offset(offset).limit(limit).get_results(connection)?;
let next = match i64::try_from(groups.len()) {
Ok(x) if x == limit => Some(offset + x),
_ => None,
};
Ok(PaginatedGroupsLists { groups, next })
}
8 changes: 8 additions & 0 deletions src/db/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ pub struct Invitation {
pub added_by: Uuid,
}

#[derive(Queryable, Serialize)]
pub struct GroupsList {
pub name: String,
pub typ: GroupType,
pub trust: TrustType,
pub member_count: i64,
}

#[derive(Insertable)]
#[table_name = "groups"]
pub struct InsertGroup {
Expand Down
13 changes: 13 additions & 0 deletions src/db/operations/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::db::operations;
use crate::db::operations::models::GroupUpdate;
use crate::db::operations::models::GroupWithTermsFlag;
use crate::db::operations::models::NewGroup;
use crate::db::operations::models::PaginatedGroupsLists;
use crate::db::operations::models::SortGroupsBy;
use crate::db::Pool;
use crate::error::PacksError;
use crate::rules::engine::CREATE_GROUP;
Expand Down Expand Up @@ -123,3 +125,14 @@ pub fn get_group_with_terms_flag(
let connection = pool.get()?;
internal::group::get_group_with_terms_flag(&connection, group_name)
}

pub fn list_groups(
pool: &Pool,
filter: Option<String>,
sort_by: SortGroupsBy,
limit: i64,
offset: i64,
) -> Result<PaginatedGroupsLists, Error> {
let connection = pool.get()?;
internal::group::list_groups(&connection, filter, sort_by, limit, offset)
}
20 changes: 20 additions & 0 deletions src/db/operations/models.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
use crate::db::model::Group;
use crate::db::model::GroupsList;
use crate::db::types::*;
use chrono::NaiveDateTime;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use uuid::Uuid;

#[derive(Deserialize)]
pub enum SortGroupsBy {
MembersCount,
NameAsc,
NameDesc,
}

impl Default for SortGroupsBy {
fn default() -> Self {
Self::MembersCount
}
}

#[derive(Deserialize)]
pub struct GroupUpdate {
pub description: Option<String>,
Expand Down Expand Up @@ -215,6 +229,12 @@ pub struct PaginatedDisplayMembersAndHost {
pub next: Option<i64>,
}

#[derive(Serialize)]
pub struct PaginatedGroupsLists {
pub groups: Vec<GroupsList>,
pub next: Option<i64>,
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
12 changes: 12 additions & 0 deletions src/db/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,15 @@ hosts_table!(hosts_ndaed, users_ndaed);
hosts_table!(hosts_vouched, users_vouched);
hosts_table!(hosts_authenticated, users_authenticated);
hosts_table!(hosts_public, users_public);

table! {
use diesel::sql_types::*;
use crate::db::types::*;

groups_list (name) {
name -> VarChar,
typ -> Group_type,
trust -> Trust_type,
members_count -> BigInt,
}
}

0 comments on commit b0e068a

Please sign in to comment.