Secondary sort by name on pledge stats
[hcoop/portal.git] / init.sml
CommitLineData
208e2cbc
AC
1structure Init :> INIT =
2struct
3
dda99898 4open Util Sql Config
208e2cbc
AC
5structure C = PgClient
6
7exception Access of string
f3f3ad24 8exception NeedTos
208e2cbc 9
dda99898 10fun conn () = C.conn dbstring
208e2cbc
AC
11val close = C.close
12
f3f3ad24 13type user = {id : int, name : string, rname : string, bal : int, joined : C.timestamp,
aaa50197 14 app : int, shares : int}
208e2cbc
AC
15
16val db = ref (NONE : C.conn option)
17val user = ref (NONE : user option)
18
ee587f7f
AC
19fun fromSql v =
20 if C.isNull v then
21 "NULL"
22 else
23 C.stringFromSql v
24
25fun rowError (tab, vs) = raise Fail ("Bad " ^ tab ^ "row: " ^ makeSet fromSql vs)
26
208e2cbc
AC
27fun getDb () = valOf (!db)
28
aaa50197 29fun mkUserRow [id, name, rname, bal, joined, app, shares] =
208e2cbc 30 {id = C.intFromSql id, name = C.stringFromSql name, rname = C.stringFromSql rname,
f3f3ad24 31 bal = C.intFromSql bal, joined = C.timestampFromSql joined,
aaa50197 32 app = C.intFromSql app, shares = C.intFromSql shares}
ee587f7f 33 | mkUserRow row = rowError ("user", row)
208e2cbc
AC
34
35fun init () =
36 let
9d1c0e98
AC
37 val _ = Util.init ()
38
208e2cbc
AC
39 val c = conn ()
40 in
f3f3ad24 41 db := SOME c;
208e2cbc
AC
42 C.dml c "BEGIN";
43 case Web.getCgi "REMOTE_USER" of
44 NONE => raise Fail "Not logged in"
45 | SOME name =>
f660f7dd
AC
46 let
47 val name =
48 if String.isSuffix kerberosSuffix name then
49 String.substring (name, 0, size name - size kerberosSuffix)
50 else
51 name
52 in
53 case C.oneOrNoRows c ($`SELECT id, name, rname, bal, joined, app, shares
54 FROM WebUserActive
55 WHERE name=^(C.stringToSql name)`) of
56 NONE => raise Fail "User not found"
57 | SOME r =>
58 let
59 val r = mkUserRow r
60 in
61 user := SOME r;
62 case C.oneOrNoRows c ($`SELECT ipaddr
f3f3ad24
AC
63 FROM MemberApp
64 WHERE id = ^(C.intToSql (#app r))
f660f7dd
AC
65 AND ipaddr IS NOT NULL`) of
66 NONE =>
67 if Web.getParam "agree" = "on" then
68 (case Web.getCgi "REMOTE_ADDR" of
69 NONE => raise Fail "REMOTE_ADDR not set"
70 | SOME ra =>
71 ignore (C.dml c ($`UPDATE MemberApp
f3f3ad24 72 SET ipaddr = ^(C.stringToSql ra),
f660f7dd
AC
73 applied = CURRENT_TIMESTAMP
74 WHERE id = ^(C.intToSql (#app r))`)))
75 else
76 raise NeedTos
77 | _ => ()
78 end
79 end
208e2cbc
AC
80 end
81
82fun done () =
83 let
84 val db = getDb ()
85 in
86 C.dml db "COMMIT";
87 close db
88 end
89
90fun getUser () = valOf (!user)
91fun getUserId () = #id (getUser ())
92fun getUserName () = #name (getUser ())
93
94fun lookupUser id =
aaa50197 95 mkUserRow (C.oneRow (getDb ()) ($`SELECT id, name, rname, bal, joined, app, shares
208e2cbc
AC
96 FROM WebUser
97 WHERE id = ^(C.intToSql id)`))
98
99fun listUsers () =
aaa50197 100 C.map (getDb ()) mkUserRow ($`SELECT id, name, rname, bal, joined, app, shares
208e2cbc
AC
101 FROM WebUser
102 ORDER BY name`)
103
104fun nextSeq (db, seq) =
105 case C.oneRow db ($`SELECT nextval('^(seq)')`) of
ee587f7f 106 [id] => C.intFromSql id
208e2cbc
AC
107 | _ => raise Fail "Bad next sequence val"
108
aaa50197 109fun addUser (name, rname, bal, app, shares) =
208e2cbc
AC
110 let
111 val db = getDb ()
112 val id = nextSeq (db, "WebUserSeq")
113 in
aaa50197
AC
114 C.dml db ($`INSERT INTO WebUser (id, name, rname, bal, joined, app, shares)
115 VALUES (^(C.intToSql id), ^(C.stringToSql name), ^(C.stringToSql rname), ^(C.intToSql bal),
116 CURRENT_TIMESTAMP, ^(C.intToSql app), ^(C.intToSql shares))`);
ee587f7f 117 id
208e2cbc
AC
118 end
119
120fun modUser (user : user) =
121 let
122 val db = getDb ()
123 in
124 ignore (C.dml db ($`UPDATE WebUser SET
125 name = ^(C.stringToSql (#name user)), rname = ^(C.stringToSql (#rname user)),
aaa50197
AC
126 bal = ^(C.intToSql (#bal user)), app = ^(C.intToSql (#app user)),
127 shares = ^(C.intToSql (#shares user))
208e2cbc
AC
128 WHERE id = ^(C.intToSql (#id user))`))
129 end
130
aaa50197
AC
131fun byPledge () =
132 C.map (getDb ()) mkUserRow ($`SELECT id, name, rname, bal, joined, app, shares
133 FROM WebUser
134 WHERE shares > 1
d90048bd 135 ORDER BY shares DESC, name`)
aaa50197 136
208e2cbc
AC
137fun deleteUser id =
138 C.dml (getDb ()) ($`DELETE FROM WebUser WHERE id = ^(C.intToSql id)`)
139
140fun validUsername name =
141 size name <= 10
03fc7566
AC
142 andalso size name > 0
143 andalso Char.isLower (String.sub (name, 0))
144 andalso CharVector.all Char.isAlphaNum name
208e2cbc
AC
145
146fun userNameToId name =
147 case C.oneOrNoRows (getDb ()) ($`SELECT id FROM WebUser WHERE name = ^(C.stringToSql name)`) of
148 SOME [id] => SOME (C.intFromSql id)
149 | _ => NONE
150
98a5f121
AC
151fun dateString () =
152 case C.oneRow (getDb ()) "SELECT CURRENT_DATE" of
153 [d] => C.stringFromSql d
154 | r => rowError ("dateString", r)
155
f3f3ad24
AC
156fun grandfatherUsers () =
157 let
158 val db = getDb ()
159
160 fun mkApp [id, name, rname] =
161 let
162 val id = C.intFromSql id
163 val name = C.stringFromSql name
164 val rname = C.stringFromSql rname
165
166 val aid = nextSeq (db, "MemberAppSeq")
167 in
168 ignore (C.dml db ($`INSERT INTO MemberApp (id, name, rname, gname, email, forward, uses, other,
169 passwd, status, applied, confirmed, decided, msg)
170 VALUES (^(C.intToSql aid), ^(C.stringToSql name), ^(C.stringToSql rname),
93f77ca7 171 NULL, '^name^(emailSuffix)', FALSE, 'GRANDFATHERED', 'GRANDFATHERED',
f3f3ad24
AC
172 'GRANDFATHERED', 4, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
173 CURRENT_TIMESTAMP, 'GRANDFATHERED')`));
174 ignore (C.dml db ($`UPDATE WebUser SET app = ^(C.intToSql aid) WHERE id = ^(C.intToSql id)`))
175 end
176 in
177 C.app db mkApp "SELECT id, name, rname FROM WebUser WHERE app IS NULL"
178 end
18eeb749
AC
179
180type node = {id : int, name : string, descr : string, debian : string}
181
182fun mkNodeRow [id, name, descr, debian] =
183 {id = C.intFromSql id, name = C.stringFromSql name, descr = C.stringFromSql descr,
184 debian = C.stringFromSql debian}
185 | mkNodeRow row = rowError ("node", row)
186
187fun listNodes () =
188 C.map (getDb ()) mkNodeRow ($`SELECT id, name, descr, debian
189 FROM WebNode
190 ORDER BY name`)
191
192fun nodeName id =
193 case C.oneRow (getDb ()) ($`SELECT name
194 FROM WebNode
195 WHERE id = ^(C.intToSql id)`) of
196 [name] => C.stringFromSql name
197 | row => rowError ("nodeName", row)
198
199fun nodeDebian id =
200 case C.oneRow (getDb ()) ($`SELECT debian
201 FROM WebNode
202 WHERE id = ^(C.intToSql id)`) of
203 [debian] => C.stringFromSql debian
204 | row => rowError ("nodeDebian", row)
205
93f77ca7 206end