Skip to content

Commit 4c08832

Browse files
authored
Basic multi-user UI. r=fabrice (#505)
Basic multi-user UI. r=fabrice * Address nit s/to_owned/String::from
1 parent ba83e11 commit 4c08832

File tree

26 files changed

+671
-244
lines changed

26 files changed

+671
-244
lines changed

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ foxbox_taxonomy = { path = "components/taxonomy/" }
2828
openzwave-adapter = { path = "components/openzwave-adapter/" }
2929
tls = { path = "components/tls/" }
3030

31-
foxbox_users = { git = "https://github.com/fxbox/users.git", rev = "d4e5277" }
31+
foxbox_users = { git = "https://github.com/fxbox/users.git", rev = "ec53c3a" }
3232
iron-cors = { git = "https://github.com/fxbox/iron-cors.git", rev = "f397cd2" }
3333
multicast_dns = { git = "https://github.com/fxbox/multicast-dns.git", rev = "a6e4bcc" }
3434

components/core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ features = ["ssl"]
1717

1818
[dependencies]
1919
clippy = "0.0.71"
20-
foxbox_users = { git = "https://github.com/fxbox/users.git", rev = "d4e5277" }
20+
foxbox_users = { git = "https://github.com/fxbox/users.git", rev = "ec53c3a" }
2121
hyper = "0.8.1"
2222
libc = "0.2.7"
2323
log = "0.3"

components/taxonomy/src/api.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,13 @@ pub enum WatchEvent {
224224
#[derive(Debug, Clone, PartialEq)]
225225
pub enum User {
226226
None,
227-
Id(i32)
227+
Id(String)
228228
}
229229

230230
#[test]
231231
fn test_user_partialeq() {
232232
assert_eq!(User::None, User::None);
233-
assert_eq!(User::Id(1), User::Id(1));
233+
assert_eq!(User::Id(String::from("1")), User::Id(String::from("1")));
234234
}
235235

236236
impl<K> Parser<Targetted<K, Payload>> for Targetted<K, Payload> where K: Parser<K> + Clone {

components/thinkerbell/src/manager.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl<Env, T> ScriptManager<Env, T>
6464
/// id, // Record identifier. Primary key.
6565
/// source, // Script source. Defines the behavior of the rule.
6666
/// is_enabled, // Boolean flag that indicates if the rule is enabled or disabled.
67-
/// owner // User identifier (i32) of the owner of the rule. Defaults to no user (-1).
67+
/// owner // User identifier (String) of the owner of the rule. Defaults to no user.
6868
/// }
6969
///
7070
/// The database stores the raw script source, but only after the source has been parsed
@@ -76,7 +76,7 @@ impl<Env, T> ScriptManager<Env, T>
7676
id TEXT NOT NULL PRIMARY KEY,
7777
source TEXT NOT NULL,
7878
is_enabled BOOL NOT NULL DEFAULT 1,
79-
owner INTEGER NOT NULL DEFAULT -1
79+
owner TEXT
8080
)", &[]));
8181

8282
Ok(ScriptManager {
@@ -100,10 +100,11 @@ impl<Env, T> ScriptManager<Env, T>
100100
let id: Id<ScriptId> = Id::new(&id_string);
101101
let source: String = try!(row.get_checked(1));
102102
let is_enabled: bool = try!(row.get_checked(2));
103-
let owner_value: i32 = try!(row.get_checked(3));
104-
let owner: User = match owner_value {
105-
-1 => User::None,
106-
_ => User::Id(owner_value)
103+
let owner_value: String = try!(row.get_checked(3));
104+
let owner: User = if owner_value.is_empty() {
105+
User::None
106+
} else {
107+
User::Id(owner_value)
107108
};
108109

109110
if is_enabled {
@@ -120,15 +121,15 @@ impl<Env, T> ScriptManager<Env, T>
120121
/// Attempt to add a new script.
121122
/// The script will be executed and persisted to disk.
122123
/// The ID is chosen by the consumer and must be unique.
123-
/// The script may have (User::Id(i32)) or may not have a owner (User::None).
124+
/// The script may have (User::Id(String)) or may not have a owner (User::None).
124125
/// If the script has owner, this value will be propagated to Thinkerbell's
125126
/// adapter.
126127
pub fn put(&mut self, id: &Id<ScriptId>, source: &String, owner: &User) -> Result<(), Error> {
127128
try!(self.start_script(&id, &source, &owner));
128129

129-
let owner_value: i32 = match *owner {
130-
User::Id(id) => id,
131-
User::None => -1
130+
let owner_value: String = match *owner {
131+
User::Id(ref id) => id.clone(),
132+
User::None => String::from("")
132133
};
133134

134135
let connection = try!(rusqlite::Connection::open(&self.path));
@@ -215,10 +216,11 @@ impl<Env, T> ScriptManager<Env, T>
215216
let mut rows = try!(stmt.query(&[&id.to_string()]));
216217
let first_row = try!(try!(rows.nth(0).ok_or(Error::NoSuchScriptError)));
217218
let source = try!(first_row.get_checked(0));
218-
let owner_value = try!(first_row.get_checked(1));
219-
let owner = match owner_value {
220-
-1 => User::None,
221-
_ => User::Id(owner_value)
219+
let owner_value: String = try!(first_row.get_checked(1));
220+
let owner = if owner_value.is_empty() {
221+
User::None
222+
} else {
223+
User::Id(owner_value)
222224
};
223225
Ok((source, owner))
224226
}

components/thinkerbell/tests/test_manager.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ fn test_database_add_remove_script() {
4040

4141
println!("* Putting a recipe in the database. It should be reported as running.");
4242
let name = Id::<ScriptId>::new("Sample Ruleset");
43-
db.put(&name, &load_json("./examples/ruleset.json"), &User::Id(1)).unwrap();
43+
db.put(&name, &load_json("./examples/ruleset.json"), &User::Id(String::from("1"))).unwrap();
4444
assert_eq!(db.get_running_count(), 1);
4545

4646

4747
println!("* The recipe should have the user with which it was stored.");
4848
let (_, owner) = db.get_source_and_owner(&name).unwrap();
49-
assert_eq!(owner, User::Id(1));
49+
assert_eq!(owner, User::Id(String::from("1")));
5050

5151
println!("* Enable the recipe again. It should still be reported as running.");
5252
db.set_enabled(&name, true).unwrap();
@@ -65,10 +65,10 @@ fn test_database_add_remove_script() {
6565
assert_eq!(db.get_running_count(), 0);
6666

6767
println!("* Add again the recipe. It should be reported as running again.");
68-
db.put(&name, &load_json("./examples/ruleset.json"), &User::Id(1)).unwrap();
68+
db.put(&name, &load_json("./examples/ruleset.json"), &User::Id(String::from("1"))).unwrap();
6969
assert_eq!(db.get_running_count(), 1);
7070

7171
println!("* Overwrite the recipe. It should still be reported as running.");
72-
db.put(&name, &load_json("./examples/ruleset.json"), &User::Id(1)).unwrap();
72+
db.put(&name, &load_json("./examples/ruleset.json"), &User::Id(String::from("1"))).unwrap();
7373
assert_eq!(db.get_running_count(), 1);
7474
}

src/adapters/webpush/db.rs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//! issued a push notification on each of their subscriptions.
1919
//!
2020
21+
use foxbox_taxonomy::api::User;
2122
use super::Subscription;
2223
use libc::c_int;
2324
use rusqlite::{ self, Connection };
@@ -34,6 +35,13 @@ fn escape_option(opt: &Option<String>) -> Option<String> {
3435
};
3536
}
3637

38+
fn user_to_str(user: &User) -> String {
39+
match *user {
40+
User::Id(ref user) => user.clone(),
41+
User::None => String::from("")
42+
}
43+
}
44+
3745
pub struct WebPushDb {
3846
db: Connection,
3947
}
@@ -43,14 +51,14 @@ impl WebPushDb {
4351
pub fn new(path: &str) -> Self {
4452
let db = Connection::open(path).unwrap();
4553
db.execute("CREATE TABLE IF NOT EXISTS subscriptions (
46-
user_id INTEGER,
54+
user_id TEXT,
4755
push_uri TEXT NOT NULL UNIQUE,
4856
public_key TEXT NOT NULL,
4957
auth TEXT
5058
)", &[]).unwrap();
5159

5260
db.execute("CREATE TABLE IF NOT EXISTS resources (
53-
user_id INTEGER,
61+
user_id TEXT,
5462
resource TEXT NOT NULL
5563
)", &[]).unwrap();
5664

@@ -60,35 +68,36 @@ impl WebPushDb {
6068
}
6169

6270
/// Adds a new push subscription `sub` bound to the user `user_id`.
63-
pub fn subscribe(&self, user_id: i32, sub: &Subscription) -> rusqlite::Result<c_int> {
71+
pub fn subscribe(&self, user_id: &User, sub: &Subscription) -> rusqlite::Result<c_int> {
6472
self.db.execute("INSERT INTO subscriptions VALUES ($1, $2, $3, $4)",
65-
&[&user_id, &escape(&sub.push_uri), &escape(&sub.public_key), &escape_option(&sub.auth)]
73+
&[&escape(&user_to_str(user_id)), &escape(&sub.push_uri), &escape(&sub.public_key), &escape_option(&sub.auth)]
6674
)
6775
}
6876

6977
/// Removes an existing push subscription identified by `push_uri`.
70-
pub fn unsubscribe(&self, _: i32, push_uri: &str) -> rusqlite::Result<c_int> {
78+
pub fn unsubscribe(&self, _: &User, push_uri: &str) -> rusqlite::Result<c_int> {
7179
self.db.execute("DELETE FROM subscriptions WHERE push_uri=$1",
7280
&[&escape(push_uri)]
7381
)
7482
}
7583

7684
/// Sets the resources to subscribe to notifications for the user `user_id`.
77-
pub fn set_resources(&self, user_id: i32, resources: &[String]) -> rusqlite::Result<()> {
78-
try!(self.db.execute("DELETE FROM resources WHERE user_id=$1", &[&user_id]));
85+
pub fn set_resources(&self, user_id: &User, resources: &[String]) -> rusqlite::Result<()> {
86+
try!(self.db.execute("DELETE FROM resources WHERE user_id=$1",
87+
&[&user_to_str(user_id)]));
7988
for resource in resources.iter() {
8089
try!(self.db.execute("INSERT INTO resources VALUES ($1, $2)",
81-
&[&user_id, &escape(resource)]
90+
&[&escape(&user_to_str(user_id)), &escape(resource)]
8291
));
8392
}
8493
Ok(())
8594
}
8695

8796
/// Gets the resources subscribed to by the user `user_id`.
88-
pub fn get_resources(&self, user_id: i32) -> rusqlite::Result<Vec<String>> {
97+
pub fn get_resources(&self, user_id: &User) -> rusqlite::Result<Vec<String>> {
8998
let mut subs = Vec::new();
9099
let mut stmt = try!(self.db.prepare("SELECT resource FROM resources WHERE user_id=$1"));
91-
let rows = try!(stmt.query(&[&user_id]));
100+
let rows = try!(stmt.query(&[&user_to_str(user_id)]));
92101
let (count, _) = rows.size_hint();
93102
subs.reserve_exact(count);
94103
for result_row in rows {
@@ -99,10 +108,10 @@ impl WebPushDb {
99108
}
100109

101110
/// Gets the push subscriptions for the user `user_id`.
102-
pub fn get_subscriptions(&self, user_id: i32) -> rusqlite::Result<Vec<Subscription>> {
111+
pub fn get_subscriptions(&self, user_id: &User) -> rusqlite::Result<Vec<Subscription>> {
103112
let mut subs = Vec::new();
104113
let mut stmt = try!(self.db.prepare("SELECT push_uri, public_key, auth FROM subscriptions WHERE user_id=$1"));
105-
let rows = try!(stmt.query(&[&user_id]));
114+
let rows = try!(stmt.query(&[&user_to_str(user_id)]));
106115
let (count, _) = rows.size_hint();
107116
subs.reserve_exact(count);
108117
for result_row in rows {
@@ -159,64 +168,65 @@ pub fn remove_test_db() {
159168
#[cfg(test)]
160169
describe! tests {
161170
before_each {
171+
use foxbox_taxonomy::api::User;
162172
let db = WebPushDb::new(&get_db_environment());
163173
}
164174

165175
it "should manage subscription correctly" {
166176
use super::super::Subscription;
167177

168-
let subs0 = db.get_subscriptions(1).unwrap();
178+
let subs0 = db.get_subscriptions(&User::Id(String::from("1"))).unwrap();
169179
assert_eq!(subs0.len(), 0);
170180

171181
let sub = Subscription {
172182
push_uri: "test_push_uri".to_owned(),
173183
public_key: "test_public_key".to_owned(),
174184
auth: Some("test_auth".to_owned())
175185
};
176-
db.subscribe(1, &sub).unwrap();
186+
db.subscribe(&User::Id(String::from("1")), &sub).unwrap();
177187

178-
let subs1 = db.get_subscriptions(1).unwrap();
188+
let subs1 = db.get_subscriptions(&User::Id(String::from("1"))).unwrap();
179189
assert_eq!(subs1.len(), 1);
180190
assert_eq!(subs1[0], sub);
181191

182-
db.unsubscribe(1, &sub.push_uri).unwrap();
192+
db.unsubscribe(&User::Id(String::from("1")), &sub.push_uri).unwrap();
183193

184-
let subs2 = db.get_subscriptions(1).unwrap();
194+
let subs2 = db.get_subscriptions(&User::Id(String::from("1"))).unwrap();
185195
assert_eq!(subs2.len(), 0);
186196
}
187197

188198
it "should manage resources correctly" {
189-
let res0 = db.get_resources(1).unwrap();
199+
let res0 = db.get_resources(&User::Id(String::from("1"))).unwrap();
190200
assert_eq!(res0.len(), 0);
191201

192202
let res = vec!["resource1".to_owned(), "resource2".to_owned()];
193-
db.set_resources(1, &res).unwrap();
203+
db.set_resources(&User::Id(String::from("1")), &res).unwrap();
194204

195-
let res1 = db.get_resources(1).unwrap();
205+
let res1 = db.get_resources(&User::Id(String::from("1"))).unwrap();
196206
assert_eq!(res1.len(), 2);
197207
assert_eq!(res1[0], "resource1".to_owned());
198208
assert_eq!(res1[1], "resource2".to_owned());
199209

200-
db.set_resources(1, &[]).unwrap();
210+
db.set_resources(&User::Id(String::from("1")), &[]).unwrap();
201211

202-
let res2 = db.get_resources(1).unwrap();
212+
let res2 = db.get_resources(&User::Id(String::from("1"))).unwrap();
203213
assert_eq!(res2.len(), 0);
204214
}
205215

206216
it "should yield subscriptions given a resource" {
207217
use super::super::Subscription;
208218

209-
db.subscribe(1, &Subscription {
219+
db.subscribe(&User::Id(String::from("1")), &Subscription {
210220
push_uri: "u1_sub0_puri".to_owned(),
211221
public_key: "u1_sub0_pkey".to_owned(),
212222
auth: Some("u1_sub0_auth".to_owned())
213223
}).unwrap();
214-
db.subscribe(1, &Subscription {
224+
db.subscribe(&User::Id(String::from("1")), &Subscription {
215225
push_uri: "u1_sub1_puri".to_owned(),
216226
public_key: "u1_sub1_pkey".to_owned(),
217227
auth: None
218228
}).unwrap();
219-
db.subscribe(2, &Subscription {
229+
db.subscribe(&User::Id(String::from("2")), &Subscription {
220230
push_uri: "u2_sub0_puri".to_owned(),
221231
public_key: "u2_sub0_pkey".to_owned(),
222232
auth: Some("u2_sub0_auth".to_owned())
@@ -226,11 +236,11 @@ describe! tests {
226236
public_key: "u3_sub0_pkey".to_owned(),
227237
auth: Some("u3_sub0_auth".to_owned())
228238
};
229-
db.subscribe(3, &u3_sub0).unwrap();
239+
db.subscribe(&User::Id(String::from("3")), &u3_sub0).unwrap();
230240

231-
db.set_resources(1, &["res1".to_owned()]).unwrap();
232-
db.set_resources(2, &["res1".to_owned(), "res2".to_owned()]).unwrap();
233-
db.set_resources(3, &["res2".to_owned(), "res3".to_owned()]).unwrap();
241+
db.set_resources(&User::Id(String::from("1")), &["res1".to_owned()]).unwrap();
242+
db.set_resources(&User::Id(String::from("2")), &["res1".to_owned(), "res2".to_owned()]).unwrap();
243+
db.set_resources(&User::Id(String::from("3")), &["res2".to_owned(), "res3".to_owned()]).unwrap();
234244

235245
let subs1 = db.get_resource_subscriptions("res1").unwrap();
236246
assert_eq!(subs1.len(), 3);

0 commit comments

Comments
 (0)