6 structure IntKey
= struct
8 val compare
= Int.compare
11 structure NM
= BinaryMapFn(IntKey
)
13 val outputDir
= "/afs/hcoop.net/user/h/hc/hcoop/public_html/"
17 val db
= C
.conn Config
.dbstring
19 fun procOutput (outf
, cmdline
) =
21 val proc
= Unix
.execute cmdline
22 val ins
= Unix
.textInstreamOf proc
25 case TextIO.inputLine ins
of
27 | SOME s
=> (TextIO.output (outf
, s
); loop ())
30 ignore (Unix
.reap proc
)
33 fun header (outf
, title
) =
34 (TextIO.output (outf
, "<!--#include file=\"header.html\" -->\n<div id=\"main\">");
35 TextIO.output (outf
, "<h2>" ^ title ^
"</h2>\n"))
37 fun footer outf
= TextIO.output (outf
, "</div>\n<!--#include file=\"footer.html\" -->\n");
39 fun genMemberList () =
41 val outf
= TextIO.openOut (outputDir ^
"members.shtml")
43 fun printOne ([name
, rname
, usr
], (total
, anon
)) =
45 val name
= C
.stringFromSql name
46 val rname
= C
.stringFromSql rname
47 val isAnon
= C
.isNull usr
50 (TextIO.output (outf
, "<tr> <td><a href=\"member/");
51 TextIO.output (outf
, name
);
52 TextIO.output (outf
, "\">");
53 TextIO.output (outf
, name
);
54 TextIO.output (outf
, "</a></td> <td>");
55 TextIO.output (outf
, rname
);
56 TextIO.output (outf
, "</td> </tr>\n"))
59 (total
+ 1, (if C
.isNull usr
then anon
+ 1 else anon
))
61 | printOne _
= raise Fail
"Bad printOne line"
63 val _
= header (outf
, "HCoop Member List")
64 val _
= TextIO.output (outf
, "<table>\n")
65 val (total
, anon
) = C
.fold db
printOne (0, 0)
66 "SELECT name, rname, usr FROM WebUserPaying LEFT OUTER JOIN DirectoryPref ON id = usr ORDER BY name"
68 TextIO.output (outf
, "</table><br><br>\n\nUnlisted members: ");
69 TextIO.output (outf
, Int.toString anon
);
70 TextIO.output (outf
, " out of ");
71 TextIO.output (outf
, Int.toString total
);
72 TextIO.output (outf
, " total.\n");
77 fun genMemberPages () =
79 fun doOne
[id
, name
, rname
, joined
, usr
] =
81 val id
= C
.intFromSql id
82 val name
= C
.stringFromSql name
83 val rname
= C
.stringFromSql rname
84 val joined
= C
.timestampFromSql joined
85 val anon
= C
.isNull usr
91 val outf
= TextIO.openOut (String.concat
[outputDir
, "member/", name
, ".shtml"])
93 val _
= header (outf
, "HCoop Member: " ^ name
)
94 val _
= TextIO.output (outf
, "<p><a href=\"/members\">Return to members directory</a></p>\n\n");
95 val _
= TextIO.output (outf
, "<table>\n<tr> <td align=\"right\"><b>Member</b>:</td> <td>")
96 val _
= TextIO.output (outf
, name
)
97 val _
= TextIO.output (outf
, "</td> </tr>\n<tr> <td align=\"right\"><b>Name</b>:</td> <td>")
98 val _
= TextIO.output (outf
, rname
)
99 val _
= TextIO.output (outf
, "</td> </tr>\n<tr> <td align=\"right\"><b>Joined</b>:</td> <td>")
100 val _
= TextIO.output (outf
, Date
.toString (Date
.fromTimeLocal joined
))
101 val _
= TextIO.output (outf
, "</td></tr>\n\n");
103 fun doLocation
[id
] = C
.intFromSql id
104 | doLocation _
= raise Fail
"Bad location row"
106 val locations
= C
.map db
doLocation (String.concat
["SELECT id FROM Location JOIN Lives ON loc = id AND usr = ",
109 fun printLocation id
=
112 case C
.oneRow
db ("SELECT name, parent FROM Location WHERE id = " ^
Int.toString id
) of
113 [name
, parent
] => (C
.stringFromSql name
, if C
.isNull parent
then NONE
else SOME (C
.intFromSql parent
))
114 | _
=> raise Fail
"Bad printLocation row"
118 | SOME parent
=> (printLocation parent
;
119 TextIO.output (outf
, " : "));
120 TextIO.output (outf
, name
)
129 TextIO.output (outf
, ", ");
132 val _
= case locations
of
135 (TextIO.output (outf
, "<tr> <td align=\"right\"><b>Locations</b>:</td> <td>");
136 app appLocation locations
;
137 TextIO.output (outf
, "</td> </tr>\n"))
139 fun doLink
[url
, title
, descr
] = (C
.stringFromSql url
, C
.stringFromSql title
, C
.stringFromSql descr
)
140 | doLink _
= raise Fail
"Bad link row"
142 val links
= C
.map db
doLink (String.concat
["SELECT url, title, descr FROM Link WHERE usr = ",
146 fun appLink (url
, title
, descr
) =
147 (TextIO.output (outf
, "<tr> <td></td> <td><b><a href=\"");
148 TextIO.output (outf
, Web
.html url
);
149 TextIO.output (outf
, "\">");
150 TextIO.output (outf
, Web
.html title
);
151 TextIO.output (outf
, "</a></b>");
153 TextIO.output (outf
, ": ")
156 TextIO.output (outf
, Web
.html descr
);
157 TextIO.output (outf
, "</td> </tr>\n"))
159 val _
= case links
of
162 (TextIO.output (outf
, "<tr> <td><b>Hosted sites</b></td> </tr>\n");
165 fun doContact
[v
, name
, url
, urlPrefix
, urlPostfix
] =
166 (C
.stringFromSql v
, C
.stringFromSql name
,
167 if C
.boolFromSql url
then SOME (C
.stringFromSql urlPrefix
, C
.stringFromSql urlPostfix
) else NONE
)
168 | doContact _
= raise Fail
"Bad contact row"
170 val contacts
= C
.map db
doContact (String.concat
["SELECT v, name, url, urlPrefix, urlPostfix",
171 " FROM Contact JOIN ContactKind ON knd = ContactKind.id",
175 " ORDER BY name, v"])
177 fun appContact (v
, name
, url
) =
181 SOME (pre
, post
) => String.concat
["<a href=\"", pre
, Web
.html v
, post
, "\">", Web
.html v
, "</a>"]
184 TextIO.output (outf
, "<tr> <td align=\"right\" valign=\"top\"><b>");
185 TextIO.output (outf
, Web
.html name
);
186 TextIO.output (outf
, "</b>:</td>\n<td>");
187 TextIO.output (outf
, link
);
188 TextIO.output (outf
, "</td> </tr>\n")
191 val _
= case contacts
of
194 (TextIO.output (outf
, "<tr> <td><b>Contact information</b></td> </tr>\n");
195 app appContact contacts
)
197 TextIO.output (outf
, "</table>\n");
202 | doOne _
= raise Fail
"Bad member row"
204 ignore (OS
.Process
.system ("/bin/rm " ^ outputDir ^
"member/*.shtml"));
205 C
.app db doOne
"SELECT id, name, rname, joined, usr FROM WebUserPaying LEFT OUTER JOIN DirectoryPref ON usr = id"
208 fun genLocations () =
210 val outf
= TextIO.openOut (outputDir ^
"locs.html")
212 val _
= header (outf
, "HCoop: Where members live")
214 fun countResidents () =
216 fun mkLivesRow
[loc
, usr
] =
217 {loc
= C
.intFromSql loc
, usr
= C
.intFromSql usr
}
218 | mkLivesRow row
= raise Fail
"Bad lives row"
220 fun folder (row
, count
) =
222 fun addToParents (id
, count
) =
224 val count
= NM
.insert (count
, id
, (case NM
.find (count
, id
) of
228 case C
.oneRow
db ("SELECT parent FROM Location WHERE id = " ^ C
.intToSql id
) of
229 [p
] => if C
.isNull p
then
232 addToParents (C
.intFromSql p
, count
)
233 | r
=> raise Fail
"Bad addToParents row"
236 val lives
= mkLivesRow row
238 addToParents (#loc lives
, count
)
241 C
.fold db folder NM
.empty
"SELECT loc, usr FROM Lives JOIN WebUserActive ON id = usr"
244 val res
= countResidents ()
246 fun locationTree root
=
248 fun doOne
[id
, name
] =
250 val id
= C
.intFromSql id
251 val name
= C
.stringFromSql name
253 case NM
.find (res
, id
) of
256 (TextIO.output (outf
, "<li> ");
257 TextIO.output (outf
, Web
.html name
);
258 TextIO.output (outf
, " (");
259 TextIO.output (outf
, Int.toString n
);
260 TextIO.output (outf
, ")");
261 TextIO.output (outf
, "</li>\n<ul>\n");
262 locationTree (SOME id
);
263 TextIO.output (outf
, "</ul>\n"))
265 | doOne _
= raise Fail
"Bad locationTree row"
267 C
.app db
doOne (String.concat
["SELECT id, name FROM Location WHERE parent ",
268 (case root
of NONE
=> "IS NULL" | SOME p
=> "= " ^
Int.toString p
),
279 val outf
= TextIO.openOut (outputDir ^
"sites.html")
281 (* val _
= header (outf
, "HCoop: Hosted sites") *)
283 fun doLink
[url
, title
, descr
, name
] = (C
.stringFromSql url
, C
.stringFromSql title
, C
.stringFromSql descr
, C
.stringFromSql name
)
284 | doLink _
= raise Fail
"Bad link' row"
286 val links
= C
.map db
doLink (String.concat
["SELECT url, title, descr, name FROM Link",
287 " JOIN WebUserPaying ON WebUserPaying.id = usr",
288 " JOIN DirectoryPref ON WebUserPaying.id = DirectoryPref.usr",
291 fun appLink (url
, title
, descr
, name
) =
292 (TextIO.output (outf
, "<tr> <td><a href=\"");
293 TextIO.output (outf
, Web
.html url
);
294 TextIO.output (outf
, "\">");
295 TextIO.output (outf
, Web
.html title
);
296 TextIO.output (outf
, "</a></td> <td>");
297 TextIO.output (outf
, Web
.html descr
);
298 TextIO.output (outf
, "</td> <td><a href=\"member/");
299 TextIO.output (outf
, name
);
300 TextIO.output (outf
, "\">");
301 TextIO.output (outf
, name
);
302 TextIO.output (outf
, "</a></td> </tr>\n"))
304 (* TextIO.output (outf
, "<table>\n"); *)
317 fun main _
= (generate ())
319 C
.Sql s
=> (print
"SQL exception: \n";
323 | Fail s
=> (print
"Fail: ";
327 | IO
.Io
{name
, function
, ...} => (print
"IO exception ";
333 | ex
=> (print
"Exception!\n";
334 List.app (fn s
=> print (s ^
"\n")) (SMLofNJ
.exnHistory ex
);