Fix some money bugs and add equalizeBalances
[hcoop/zz_old/portal.git] / init.sml
CommitLineData
8d347a33 1structure Init :> INIT =
2struct
3
4open Util Sql
5structure C = PgClient
6
7exception Access of string
8
2eae496b 9val urlPrefix = "http://users.hcoop.net/portal/"
453d7579 10val boardEmail = "board.fake@hcoop.net"
2eae496b 11
8d347a33 12fun conn () = C.conn "dbname='hcoop'"
13val close = C.close
14
15type user = {id : int, name : string, rname : string, bal : int, joined : C.timestamp}
16
17val db = ref (NONE : C.conn option)
18val user = ref (NONE : user option)
19
369e1577 20fun fromSql v =
21 if C.isNull v then
22 "NULL"
23 else
24 C.stringFromSql v
25
26fun rowError (tab, vs) = raise Fail ("Bad " ^ tab ^ "row: " ^ makeSet fromSql vs)
27
8d347a33 28fun getDb () = valOf (!db)
29
30fun mkUserRow [id, name, rname, bal, joined] =
31 {id = C.intFromSql id, name = C.stringFromSql name, rname = C.stringFromSql rname,
32 bal = C.intFromSql bal, joined = C.timestampFromSql joined}
369e1577 33 | mkUserRow row = rowError ("user", row)
8d347a33 34
35fun init () =
36 let
78304862 37 val _ = Util.init ()
38
8d347a33 39 val c = conn ()
40 in
41 C.dml c "BEGIN";
42 case Web.getCgi "REMOTE_USER" of
43 NONE => raise Fail "Not logged in"
44 | SOME name =>
45 (case C.oneOrNoRows c ($`SELECT id, name, rname, bal, joined
46 FROM WebUser
47 WHERE name=^(C.stringToSql name)`) of
48 NONE => raise Fail "User not found"
49 | SOME r => user := SOME (mkUserRow r));
50 db := SOME c
51 end
52
53fun done () =
54 let
55 val db = getDb ()
56 in
57 C.dml db "COMMIT";
58 close db
59 end
60
61fun getUser () = valOf (!user)
62fun getUserId () = #id (getUser ())
63fun getUserName () = #name (getUser ())
64
65fun lookupUser id =
66 mkUserRow (C.oneRow (getDb ()) ($`SELECT id, name, rname, bal, joined
67 FROM WebUser
68 WHERE id = ^(C.intToSql id)`))
69
70fun listUsers () =
71 C.map (getDb ()) mkUserRow ($`SELECT id, name, rname, bal, joined
72 FROM WebUser
73 ORDER BY name`)
74
75fun nextSeq (db, seq) =
76 case C.oneRow db ($`SELECT nextval('^(seq)')`) of
369e1577 77 [id] => C.intFromSql id
8d347a33 78 | _ => raise Fail "Bad next sequence val"
79
80fun addUser (name, rname, bal) =
81 let
82 val db = getDb ()
83 val id = nextSeq (db, "WebUserSeq")
84 in
85 C.dml db ($`INSERT INTO WebUser (id, name, rname, bal, joined)
369e1577 86 VALUES (^(C.intToSql id), ^(C.stringToSql name), ^(C.stringToSql rname), ^(C.intToSql bal), CURRENT_TIMESTAMP)`);
87 id
8d347a33 88 end
89
90fun modUser (user : user) =
91 let
92 val db = getDb ()
93 in
94 ignore (C.dml db ($`UPDATE WebUser SET
95 name = ^(C.stringToSql (#name user)), rname = ^(C.stringToSql (#rname user)),
96 bal = ^(C.intToSql (#bal user))
97 WHERE id = ^(C.intToSql (#id user))`))
98 end
99
100fun deleteUser id =
101 C.dml (getDb ()) ($`DELETE FROM WebUser WHERE id = ^(C.intToSql id)`)
102
103fun validUsername name =
104 size name <= 10
105 andalso CharVector.all Char.isAlpha name
106
107fun userNameToId name =
108 case C.oneOrNoRows (getDb ()) ($`SELECT id FROM WebUser WHERE name = ^(C.stringToSql name)`) of
109 SOME [id] => SOME (C.intFromSql id)
110 | _ => NONE
111
4b8df0b1 112fun dateString () =
113 case C.oneRow (getDb ()) "SELECT CURRENT_DATE" of
114 [d] => C.stringFromSql d
115 | r => rowError ("dateString", r)
116
8d347a33 117end