Join script should rule out retired usernames
[bpt/portal.git] / app.sml
CommitLineData
a90da8b1
AC
1structure App :> APP =
2struct
3
4open Init Sql Util
5
6datatype status =
7 CONFIRMING
8 | PENDING
9 | ACCEPTED
10 | REJECTED
6f91863c 11 | ADDED
96bd398e 12 | BEING_ADDED
a90da8b1
AC
13
14val statusFromInt =
15 fn 0 => CONFIRMING
16 | 1 => PENDING
17 | 2 => ACCEPTED
18 | 3 => REJECTED
6f91863c 19 | 4 => ADDED
96bd398e 20 | 5 => BEING_ADDED
a90da8b1
AC
21 | _ => raise C.Sql "Bad status"
22
23val statusToInt =
24 fn CONFIRMING => 0
25 | PENDING => 1
26 | ACCEPTED => 2
27 | REJECTED => 3
6f91863c 28 | ADDED => 4
96bd398e 29 | BEING_ADDED => 5
a90da8b1
AC
30
31fun statusFromSql v = statusFromInt (C.intFromSql v)
32fun statusToSql s = C.intToSql (statusToInt s)
33
f3f3ad24 34type app = { id : int, name : string, rname : string, gname : string option, email : string,
a90da8b1 35 forward : bool, uses : string, other : string,
f3f3ad24 36 passwd : string, status : status, applied : C.timestamp, ipaddr : string option,
6f91863c 37 confirmed : C.timestamp option, decided : C.timestamp option,
d5f8418b
AC
38 msg : string, unix_passwd : string,
39 paypal : string option, checkout : string option }
a90da8b1 40
f3f3ad24 41fun mkAppRow [id, name, rname, gname, email, forward, uses, other, passwd, status,
d5f8418b 42 applied, ipaddr, confirmed, decided, msg, unix_passwd, paypal, checkout] =
a90da8b1 43 { id = C.intFromSql id, name = C.stringFromSql name, rname = C.stringFromSql rname,
d5f8418b 44 gname = Init.nullableFromSql C.stringFromSql gname,
a90da8b1
AC
45 email = C.stringFromSql email, forward = C.boolFromSql forward,
46 uses = C.stringFromSql uses, other = C.stringFromSql other, passwd = C.stringFromSql passwd,
6f91863c 47 status = statusFromSql status, applied = C.timestampFromSql applied,
d5f8418b
AC
48 ipaddr = Init.nullableFromSql C.stringFromSql ipaddr,
49 confirmed = Init.nullableFromSql C.timestampFromSql confirmed,
50 decided = Init.nullableFromSql C.timestampFromSql decided,
51 msg = C.stringFromSql msg, unix_passwd = C.stringFromSql unix_passwd,
52 paypal = Init.nullableFromSql C.stringFromSql paypal,
53 checkout = Init.nullableFromSql C.stringFromSql checkout}
a90da8b1
AC
54 | mkAppRow r = rowError ("app", r)
55
56fun lookupApp id =
a2d53da2 57 case C.oneOrNoRows (getDb ()) ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided,
d5f8418b 58 msg, unix_passwd, paypal, checkout
6f91863c
AC
59 FROM MemberApp
60 WHERE id = ^(C.intToSql id)`) of
a90da8b1
AC
61 SOME row => mkAppRow row
62 | NONE => raise Fail "Membership application not found"
63
96bd398e 64fun listApps statuses =
a2d53da2 65 C.map (getDb ()) mkAppRow ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided,
d5f8418b 66 msg, unix_passwd, paypal, checkout
6f91863c 67 FROM MemberApp
96bd398e 68 WHERE status IN (^(String.concatWith "," (map statusToSql statuses)))
38bfcd20 69 AND NOT (status = 2 AND decided < CURRENT_TIMESTAMP - INTERVAL '1 MONTH')
6f91863c
AC
70 ORDER BY applied`)
71
72fun mkVoteRow [id, name] = (C.intFromSql id, C.stringFromSql name)
73 | mkVoteRow row = rowError ("app.vote", row)
74
75fun votes id = C.map (getDb ()) mkVoteRow ($`SELECT usr, name
76 FROM AppVote JOIN WebUser ON usr = id
f3f3ad24 77 WHERE AppVote.app = ^(C.intToSql id)
6f91863c
AC
78 ORDER BY name`)
79
80fun vote (usr, app) = ignore (C.dml (getDb ()) ($`INSERT INTO AppVote (app, usr)
81 VALUES (^(C.intToSql app), ^(C.intToSql usr))`))
82
83fun unvote (usr, app) = ignore (C.dml (getDb ()) ($`DELETE FROM AppVote WHERE app = ^(C.intToSql app) AND usr = ^(C.intToSql usr)`))
84
85fun deny (app, msg) =
86 let
87 val entry = lookupApp app
88 val _ = C.dml (getDb ()) ($`UPDATE MemberApp
89 SET status = 3, msg = ^(C.stringToSql msg), decided = CURRENT_TIMESTAMP
90 WHERE id = ^(C.intToSql app)`)
91
92 val mail = Mail.mopen ()
93 in
93f77ca7
AC
94 Mail.mwrite (mail, "From: Hcoop Application System <join");
95 Mail.mwrite (mail, emailSuffix);
96 Mail.mwrite (mail, ">\nTo: ");
6f91863c
AC
97 Mail.mwrite (mail, #email entry);
98 Mail.mwrite (mail, "\nCc: ");
99 Mail.mwrite (mail, boardEmail);
100 Mail.mwrite (mail, "\nSubject: Application denied\n\nYour application for membership has been denied. Reason:\n\n");
101 Mail.mwrite (mail, msg);
102 OS.Process.isSuccess (Mail.mclose mail)
103 end
104
105fun approve (app, msg) =
106 let
107 val entry = lookupApp app
108 val _ = C.dml (getDb ()) ($`UPDATE MemberApp
109 SET status = 2, msg = ^(C.stringToSql msg), decided = CURRENT_TIMESTAMP
110 WHERE id = ^(C.intToSql app)`)
111
112 val mail = Mail.mopen ()
113 in
b90b0980 114 Mail.mwrite (mail, "To: ");
6f91863c 115 Mail.mwrite (mail, #email entry);
b90b0980
AC
116 Mail.mwrite (mail, "\n");
117 Mail.mwrite (mail, Util.readFile "/home/hcoop/portal/welcome.txt");
6f91863c
AC
118 Mail.mwrite (mail, msg);
119 OS.Process.isSuccess (Mail.mclose mail)
120 end
121
96bd398e 122fun preAdd app =
688bf30c
AC
123 let
124 val _ = C.dml (getDb ()) ($`UPDATE MemberApp
64ec9551 125 SET status = 5
688bf30c
AC
126 WHERE id = ^(C.intToSql app)`)
127
128 val app = lookupApp app
129
130 val outf = TextIO.openOut (Config.passwordFiles ^ #name app)
131 in
132 TextIO.output (outf, #unix_passwd app);
26d9b4fe 133 TextIO.output1 (outf, #"\n");
688bf30c
AC
134 TextIO.closeOut outf
135 end
136
64ec9551 137fun add app =
ccac9b41
AC
138 let
139 val appR = lookupApp app
140 in
141 ignore (C.dml (getDb ()) ($`UPDATE MemberApp
142 SET status = 4
143 WHERE id = ^(C.intToSql app)`));
144 OS.FileSys.remove (Config.passwordFiles ^ #name appR)
145 end
64ec9551 146
688bf30c
AC
147fun welcome app =
148 let
149 val app = lookupApp app
150
151 val mail = Mail.mopen ()
152 in
153 Mail.mwrite (mail, "To: ");
154 Mail.mwrite (mail, #email app);
155 Mail.mwrite (mail, "\n");
156 Mail.mwrite (mail, Util.readFile "/home/hcoop/portal/paid.txt");
157 ignore (Mail.mclose mail)
158 end
98a5f121
AC
159
160fun abortAdd app =
161 ignore (C.dml (getDb ()) ($`UPDATE MemberApp
162 SET status = 2
163 WHERE id = ^(C.intToSql app)`))
164
f3f3ad24
AC
165fun readFile fname =
166 let
167 val inf = TextIO.openIn fname
168
169 fun readLines lines =
170 case TextIO.inputLine inf of
171 NONE => String.concat (List.rev lines)
172 | SOME line => readLines (line :: lines)
173 in
174 readLines []
175 before TextIO.closeIn inf
176 end
177
37cec107
AC
178fun readTosBody () = readFile "/home/hcoop/public_html/tos.body.html"
179fun readTosAgree () = readFile "/home/hcoop/public_html/tos.agree.html"
180fun readTosMinorAgree () = readFile "/home/hcoop/public_html/tos.agree.minor.html"
f3f3ad24 181
d5f8418b
AC
182fun searchPaypal paypal =
183 C.map (getDb ()) mkAppRow ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided,
184 msg, unix_passwd, paypal, checkout
185 FROM MemberApp
9953bee7 186 WHERE paypal = ^(C.stringToSql (normEmail paypal))
d5f8418b
AC
187 AND status = 2
188 AND decided >= CURRENT_TIMESTAMP - INTERVAL '1 MONTH'
189 ORDER BY applied`)
190
191fun searchCheckout checkout =
192 C.map (getDb ()) mkAppRow ($`SELECT id, name, rname, gname, email, forward, uses, other, passwd, status, applied, ipaddr, confirmed, decided,
193 msg, unix_passwd, paypal, checkout
194 FROM MemberApp
9953bee7 195 WHERE checkout = ^(C.stringToSql (normEmail checkout))
d5f8418b
AC
196 AND status = 2
197 AND decided >= CURRENT_TIMESTAMP - INTERVAL '1 MONTH'
198 ORDER BY applied`)
199
93f77ca7 200end