1use rusqlite::Connection;
4use serde::{Deserialize, Serialize};
5use sha2::{Digest, Sha256};
6
7#[derive(Serialize, Deserialize, Clone, Debug)]
10pub struct User {
11 pub id: String,
12 pub email: String,
13 pub name: String,
14}
15
16#[derive(Serialize, Deserialize, Clone, Debug)]
17pub struct Team {
18 pub id: String,
19 pub name: String,
20 pub owner_id: String,
21 pub created_at: u64,
22}
23
24#[derive(Serialize, Deserialize, Clone, Debug)]
25pub struct TeamMember {
26 pub user_id: String,
27 pub role: String,
28 pub joined_at: u64,
29 pub name: String,
30 pub email: String,
31}
32
33#[derive(Serialize, Deserialize, Clone, Debug)]
34pub struct Invite {
35 pub token: String,
36 pub team_id: String,
37 pub team_name: String,
38}
39
40#[derive(Serialize, Deserialize, Clone, Debug)]
41pub struct Channel {
42 pub id: String,
43 pub name: String,
44 pub team_id: String,
45}
46
47pub fn init_hub_tables(conn: &Connection) {
51 conn.execute_batch(
52 "CREATE TABLE IF NOT EXISTS users (
53 id TEXT PRIMARY KEY,
54 email TEXT UNIQUE NOT NULL,
55 name TEXT NOT NULL,
56 created_at INTEGER NOT NULL
57 );
58
59 CREATE TABLE IF NOT EXISTS api_keys (
60 key_hash TEXT PRIMARY KEY,
61 user_id TEXT NOT NULL REFERENCES users(id),
62 label TEXT NOT NULL DEFAULT 'default',
63 created_at INTEGER NOT NULL
64 );
65
66 CREATE TABLE IF NOT EXISTS teams (
67 id TEXT PRIMARY KEY,
68 name TEXT UNIQUE NOT NULL,
69 owner_id TEXT NOT NULL REFERENCES users(id),
70 created_at INTEGER NOT NULL
71 );
72
73 CREATE TABLE IF NOT EXISTS team_members (
74 team_id TEXT NOT NULL REFERENCES teams(id),
75 user_id TEXT NOT NULL REFERENCES users(id),
76 role TEXT NOT NULL DEFAULT 'member',
77 joined_at INTEGER NOT NULL,
78 PRIMARY KEY (team_id, user_id)
79 );
80
81 CREATE TABLE IF NOT EXISTS invites (
82 token TEXT PRIMARY KEY,
83 team_id TEXT NOT NULL REFERENCES teams(id),
84 inviter_id TEXT NOT NULL REFERENCES users(id),
85 email TEXT,
86 created_at INTEGER NOT NULL,
87 used_at INTEGER
88 );
89
90 CREATE TABLE IF NOT EXISTS channels (
91 id TEXT PRIMARY KEY,
92 team_id TEXT NOT NULL REFERENCES teams(id),
93 name TEXT NOT NULL,
94 created_at INTEGER NOT NULL,
95 UNIQUE(team_id, name)
96 );",
97 )
98 .expect("Failed to create hub tables");
99
100 let _ = conn.execute_batch("ALTER TABLE messages ADD COLUMN team_id TEXT;");
103 let _ = conn.execute_batch("ALTER TABLE messages ADD COLUMN channel TEXT DEFAULT 'general';");
104}
105
106pub fn hash_api_key(key: &str) -> String {
110 let mut hasher = Sha256::new();
111 hasher.update(key.as_bytes());
112 hex::encode(hasher.finalize())
113}
114
115pub fn generate_api_key() -> String {
117 format!("ar_{}", uuid::Uuid::new_v4().to_string().replace('-', ""))
118}
119
120pub fn verify_api_key(conn: &Connection, key: &str) -> Option<User> {
122 let key_hash = hash_api_key(key);
123 conn.query_row(
124 "SELECT u.id, u.email, u.name
125 FROM api_keys ak
126 JOIN users u ON u.id = ak.user_id
127 WHERE ak.key_hash = ?1",
128 [&key_hash],
129 |row| {
130 Ok(User {
131 id: row.get(0)?,
132 email: row.get(1)?,
133 name: row.get(2)?,
134 })
135 },
136 )
137 .ok()
138}