structure Gen :> GEN =
struct
structure C = PgClient
structure IntKey = struct
type ord_key = int
val compare = Int.compare
end
structure NM = BinaryMapFn(IntKey)
val outputDir = "/var/www/dyn/"
fun generate () =
let
val db = C.conn "dbname='hcoop_hcoop'"
fun header (outf, title) =
(TextIO.output (outf, "
\n\n Member: | ")
val _ = TextIO.output (outf, name)
val _ = TextIO.output (outf, " |
\n Name: | ")
val _ = TextIO.output (outf, rname)
val _ = TextIO.output (outf, " |
\n Joined: | ")
val _ = TextIO.output (outf, Date.toString (Date.fromTimeLocal joined))
fun doLocation [id] = C.intFromSql id
| doLocation _ = raise Fail "Bad location row"
val locations = C.map db doLocation (String.concat ["SELECT id FROM Location JOIN Lives ON loc = id AND usr = ",
Int.toString id])
fun printLocation id =
let
val (name, parent) =
case C.oneRow db ("SELECT name, parent FROM Location WHERE id = " ^ Int.toString id) of
[name, parent] => (C.stringFromSql name, if C.isNull parent then NONE else SOME (C.intFromSql parent))
| _ => raise Fail "Bad printLocation row"
in
case parent of
NONE => ()
| SOME parent => (printLocation parent;
TextIO.output (outf, " : "));
TextIO.output (outf, name)
end
val first = ref true
fun appLocation id =
(if !first then
first := false
else
TextIO.output (outf, ", ");
printLocation id)
val _ = case locations of
[] => ()
| _ =>
(TextIO.output (outf, " |
\n\n Locations: | ");
app appLocation locations;
TextIO.output (outf, " |
\n"))
fun doLink [url, title, descr] = (C.stringFromSql url, C.stringFromSql title, C.stringFromSql descr)
| doLink _ = raise Fail "Bad link row"
val links = C.map db doLink (String.concat ["SELECT url, title, descr FROM Link WHERE usr = ",
Int.toString id,
" ORDER BY title"])
fun appLink (url, title, descr) =
(TextIO.output (outf, " | ");
TextIO.output (outf, Web.html title);
TextIO.output (outf, "");
if descr <> "" then
TextIO.output (outf, ": ")
else
();
TextIO.output (outf, Web.html descr);
TextIO.output (outf, " |
\n"))
val _ = case links of
[] => ()
| _ =>
(TextIO.output (outf, "
\n\n Hosted sites |
\n");
app appLink links)
fun doContact [v, name, url, urlPrefix, urlPostfix] =
(C.stringFromSql v, C.stringFromSql name,
if C.boolFromSql url then SOME (C.stringFromSql urlPrefix, C.stringFromSql urlPostfix) else NONE)
| doContact _ = raise Fail "Bad contact row"
val contacts = C.map db doContact (String.concat ["SELECT v, name, url, urlPrefix, urlPostfix",
" FROM Contact JOIN ContactKind ON knd = ContactKind.id",
" WHERE priv = 0",
" AND usr = ",
Int.toString id,
" ORDER BY name, v"])
fun appContact (v, name, url) =
let
val link =
case url of
SOME (pre, post) => String.concat ["", Web.html v, ""]
| NONE => v
in
TextIO.output (outf, " ");
TextIO.output (outf, Web.html name);
TextIO.output (outf, ": | \n");
TextIO.output (outf, link);
TextIO.output (outf, " |
\n")
end
val _ = case contacts of
[] => ()
| _ =>
(TextIO.output (outf, "
\n\n Contact information |
\n");
app appContact contacts)
in
TextIO.output (outf, "
\n");
footer outf;
TextIO.closeOut outf
end
end
| doOne _ = raise Fail "Bad member row"
in
ignore (OS.Process.system ("/bin/rm " ^ outputDir ^ "member/*.html"));
C.app db doOne "SELECT id, name, rname, joined, usr FROM WebUserPaying LEFT OUTER JOIN DirectoryPref ON usr = id"
end
fun genLocations () =
let
val outf = TextIO.openOut (outputDir ^ "locs.html")
val _ = header (outf, "Where members live")
fun countResidents () =
let
fun mkLivesRow [loc, usr] =
{loc = C.intFromSql loc, usr = C.intFromSql usr}
| mkLivesRow row = raise Fail "Bad lives row"
fun folder (row, count) =
let
fun addToParents (id, count) =
let
val count = NM.insert (count, id, (case NM.find (count, id) of
NONE => 1
| SOME n => n+1))
in
case C.oneRow db ("SELECT parent FROM Location WHERE id = " ^ C.intToSql id) of
[p] => if C.isNull p then
count
else
addToParents (C.intFromSql p, count)
| r => raise Fail "Bad addToParents row"
end
val lives = mkLivesRow row
in
addToParents (#loc lives, count)
end
in
C.fold db folder NM.empty "SELECT loc, usr FROM Lives"
end
val res = countResidents ()
fun locationTree root =
let
fun doOne [id, name] =
let
val id = C.intFromSql id
val name = C.stringFromSql name
in
TextIO.output (outf, "