Some initial work on organizations, nothing works yet

This commit is contained in:
Daniel García 2018-02-17 22:30:19 +01:00
parent d6a1a9b274
commit 1bc346688c
7 changed files with 357 additions and 12 deletions

View File

@ -0,0 +1,8 @@
DROP TABLE collections;
DROP TABLE organizations;
DROP TABLE users_collections;
DROP TABLE users_organizations;

View File

@ -0,0 +1,29 @@
CREATE TABLE collections (
uuid TEXT NOT NULL PRIMARY KEY,
org_uuid TEXT NOT NULL REFERENCES organizations (uuid),
name TEXT NOT NULL
);
CREATE TABLE organizations (
uuid TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
billing_email TEXT NOT NULL
);
CREATE TABLE users_collections (
user_uuid TEXT NOT NULL REFERENCES users (uuid),
collection_uuid TEXT NOT NULL REFERENCES collections (uuid),
PRIMARY KEY (user_uuid, collection_uuid)
);
CREATE TABLE users_organizations (
user_uuid TEXT NOT NULL REFERENCES users (uuid),
org_uuid TEXT NOT NULL REFERENCES organizations (uuid),
key TEXT NOT NULL,
status INTEGER NOT NULL,
type INTEGER NOT NULL,
PRIMARY KEY (user_uuid, org_uuid)
);

View File

@ -1,11 +1,13 @@
mod accounts; mod accounts;
mod ciphers; mod ciphers;
mod folders; mod folders;
mod organizations;
mod two_factor; mod two_factor;
use self::accounts::*; use self::accounts::*;
use self::ciphers::*; use self::ciphers::*;
use self::folders::*; use self::folders::*;
use self::organizations::*;
use self::two_factor::*; use self::two_factor::*;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
@ -49,7 +51,7 @@ pub fn routes() -> Vec<Route> {
activate_authenticator, activate_authenticator,
disable_authenticator, disable_authenticator,
get_collections, get_user_collections,
clear_device_token, clear_device_token,
put_device_token, put_device_token,
@ -72,17 +74,6 @@ use db::DbConn;
use api::JsonResult; use api::JsonResult;
use auth::Headers; use auth::Headers;
// GET /api/collections?writeOnly=false
#[get("/collections")]
fn get_collections() -> JsonResult {
Ok(Json(json!({
"Data": [],
"Object": "list"
})))
}
#[put("/devices/identifier/<uuid>/clear-token")] #[put("/devices/identifier/<uuid>/clear-token")]
fn clear_device_token(uuid: String, conn: DbConn) -> JsonResult { fn clear_device_token(uuid: String, conn: DbConn) -> JsonResult {
err!("Not implemented") err!("Not implemented")

View File

@ -0,0 +1,85 @@
use rocket_contrib::{Json, Value};
use db::DbConn;
use db::models::*;
use api::{JsonResult, EmptyResult};
use auth::Headers;
#[post("/organizations", data = "<data>")]
fn create_organization(headers: Headers, data: Json<Value>, conn: DbConn) -> JsonResult {
/*
Data is a JSON Object with the following entries
billingEmail <email>
collectionName <encrypted_collection_name>
key <key>
name <unencrypted_name>
planType free
*/
// We need to add the following key to the users jwt claims
// orgowner: "<org-id>"
// This function returns organization.to_json();
err!("Not implemented")
}
// GET /api/collections?writeOnly=false
#[get("/collections")]
fn get_user_collections(headers: Headers, conn: DbConn) -> JsonResult {
// let collections_json = get_user_collections().map(|c|c.to_json());
Ok(Json(json!({
"Data": [],
"Object": "list"
})))
}
#[get("/organizations/<org_id>/collections")]
fn get_org_collections(org_id: String, headers: Headers, conn: DbConn) -> JsonResult {
// let org = get_org_by_id(org_id)
// let collections_json = org.collections().map(|c|c.to_json());
Ok(Json(json!({
"Data": [],
"Object": "list"
})))
}
#[get("/organizations/<org_id>/collections/<coll_id>/users")]
fn get_collection_users(org_id: String, coll_id: String, headers: Headers, conn: DbConn) -> JsonResult {
// Get org and collection, check that collection is from org
// Get the users from collection
/*
The elements from the data array to return have the following structure
{
OrganizationUserId: <id>
AccessAll: true
Name: <user_name>
Email: <user_email>
Type: 0
Status: 2
ReadOnly: false
Object: collectionUser
}
*/
Ok(Json(json!({
"Data": [],
"Object": "list"
})))
}
//********************************************************************************************
/*
We need to modify 'GET /api/profile' to return the users organizations, instead of []
The elements from that array come from organization.to_json_profile()
*/

View File

@ -0,0 +1,73 @@
use chrono::{NaiveDateTime, Utc};
use serde_json::Value as JsonValue;
use uuid::Uuid;
use super::Organization;
#[derive(Debug, Identifiable, Queryable, Insertable, Associations)]
#[table_name = "collections"]
#[belongs_to(Organization, foreign_key = "org_uuid")]
#[primary_key(uuid)]
pub struct Collection {
pub uuid: String,
pub org_uuid: String,
pub name: String,
}
/// Local methods
impl Collection {
pub fn new(org_uuid: String, name: String) -> Self {
let now = Utc::now().naive_utc();
Self {
uuid: Uuid::new_v4().to_string(),
org_uuid,
name,
}
}
pub fn to_json(&self) -> JsonValue {
json!({
"Id": self.uuid,
"OrganizationId": self.org_uuid,
"Name": self.name,
"Object": "collection",
})
}
}
use diesel;
use diesel::prelude::*;
use db::DbConn;
use db::schema::collections;
/// Database methods
impl Collection {
pub fn save(&mut self, conn: &DbConn) -> bool {
self.updated_at = Utc::now().naive_utc();
match diesel::replace_into(collections::table)
.values(&*self)
.execute(&**conn) {
Ok(1) => true, // One row inserted
_ => false,
}
}
pub fn delete(self, conn: &DbConn) -> bool {
match diesel::delete(collections::table.filter(
collections::uuid.eq(self.uuid)))
.execute(&**conn) {
Ok(1) => true, // One row deleted
_ => false,
}
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
collections::table
.filter(collections::uuid.eq(uuid))
.first::<Self>(&**conn).ok()
}
}

View File

@ -0,0 +1,116 @@
use chrono::{NaiveDateTime, Utc};
use serde_json::Value as JsonValue;
use uuid::Uuid;
#[derive(Debug, Identifiable, Queryable, Insertable)]
#[table_name = "organizations"]
#[primary_key(uuid)]
pub struct Organization {
pub uuid: String,
pub name: String,
pub billing_email: String,
pub key: String,
}
/// Local methods
impl Organization {
pub fn new(name: String, billing_email: String, key: String) -> Self {
let now = Utc::now().naive_utc();
Self {
uuid: Uuid::new_v4().to_string(),
name,
billing_email,
key,
}
}
pub fn to_json(&self) -> JsonValue {
json!({
"Id": self.uuid,
"Name": self.name,
"BusinessName": null,
"BusinessAddress1": null,
"BusinessAddress2": null,
"BusinessAddress3": null,
"BusinessCountry": null,
"BusinessTaxNumber": null,
"BillingEmail":self.billing_email,
"Plan": "Free",
"PlanType": 0, // Free plan
"Seats": 10,
"MaxCollections": 10,
"UseGroups": false,
"UseDirectory": false,
"UseEvents": false,
"UseTotp": false,
"Object": "organization",
})
}
pub fn to_json_profile(&self) -> JsonValue {
json!({
"Id": self.uuid,
"Name": self.name,
"Seats": 10,
"MaxCollections": 10,
"UseGroups": false,
"UseDirectory": false,
"UseEvents": false,
"UseTotp": false,
"MaxStorageGb": null,
// These are probably per user
"Key": self.key,
"Status": 2, // Confirmed
"Type": 0, // Owner
"Enabled": true,
"Object": "profileOrganization",
})
}
}
use diesel;
use diesel::prelude::*;
use db::DbConn;
use db::schema::organizations;
/// Database methods
impl Organization {
pub fn save(&mut self, conn: &DbConn) -> bool {
self.updated_at = Utc::now().naive_utc();
match diesel::replace_into(organizations::table)
.values(&*self)
.execute(&**conn) {
Ok(1) => true, // One row inserted
_ => false,
}
}
pub fn delete(self, conn: &DbConn) -> bool {
match diesel::delete(organizations::table.filter(
organizations::uuid.eq(self.uuid)))
.execute(&**conn) {
Ok(1) => true, // One row deleted
_ => false,
}
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
organizations::table
.filter(organizations::uuid.eq(uuid))
.first::<Self>(&**conn).ok()
}
}

View File

@ -22,6 +22,14 @@ table! {
} }
} }
table! {
collections (uuid) {
uuid -> Text,
org_uuid -> Text,
name -> Text,
}
}
table! { table! {
devices (uuid) { devices (uuid) {
uuid -> Text, uuid -> Text,
@ -46,6 +54,14 @@ table! {
} }
} }
table! {
organizations (uuid) {
uuid -> Text,
name -> Text,
billing_email -> Text,
}
}
table! { table! {
users (uuid) { users (uuid) {
uuid -> Text, uuid -> Text,
@ -68,16 +84,43 @@ table! {
} }
} }
table! {
users_collections (user_uuid, collection_uuid) {
user_uuid -> Text,
collection_uuid -> Text,
}
}
table! {
users_organizations (user_uuid, org_uuid) {
user_uuid -> Text,
org_uuid -> Text,
key -> Text,
status -> Integer,
#[sql_name = "type"]
type_ -> Integer,
}
}
joinable!(attachments -> ciphers (cipher_uuid)); joinable!(attachments -> ciphers (cipher_uuid));
joinable!(ciphers -> folders (folder_uuid)); joinable!(ciphers -> folders (folder_uuid));
joinable!(ciphers -> users (user_uuid)); joinable!(ciphers -> users (user_uuid));
joinable!(collections -> organizations (org_uuid));
joinable!(devices -> users (user_uuid)); joinable!(devices -> users (user_uuid));
joinable!(folders -> users (user_uuid)); joinable!(folders -> users (user_uuid));
joinable!(users_collections -> collections (collection_uuid));
joinable!(users_collections -> users (user_uuid));
joinable!(users_organizations -> organizations (org_uuid));
joinable!(users_organizations -> users (user_uuid));
allow_tables_to_appear_in_same_query!( allow_tables_to_appear_in_same_query!(
attachments, attachments,
ciphers, ciphers,
collections,
devices, devices,
folders, folders,
organizations,
users, users,
users_collections,
users_organizations,
); );