App.add id %>
First, create this UNIX user:
-<blockquote><tt>adduser <% #name appl %> "<% #rname appl %>"<% if #forward appl then %>" <% #email appl %>"<% end %></tt></blockquote>
+<blockquote><tt>portal_adduser <% #name appl %> "<% #rname appl %>"<% if #forward appl then %>" <% #email appl %>"<% end %></tt></blockquote>
-<form action="users">
+<p>You should then run <tt>visudo</tt> to add <% #name appl %> to the <tt>MEMBERS</tt> group. If you're not transmitting <% #name appl %>'s password to him by other means, run <tt>savepass <% #name appl %> <password></tt> to save it in <tt>~<% #name appl %>/.pass</tt>.</p>
+
+<form action="users" method="post">
<input type="hidden" name="app" value="<% #id appl %>">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name" value="<% Web.html (#name appl) %>"></td> </tr>
val user = Init.lookupUser (#usr req) %>
<h3><b>Handle request</b></h3>
-<form action="apt">
+<form action="apt" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Requestor</b>:</td> <td><a href="user?id=<% #usr req %>"><% #name user %></a></td> </tr>
List the package names you'd like, separated by any whitespace characters.
-<form action="apt">
+<form action="apt" method="post">
<table>
<tr> <td align="right" valign="top"><b>Packages</b>:</td> <td><textarea name="new" rows="10" cols="40" wrap="soft"></textarea></td> </tr>
<tr> <td align="right" valign="top"><b>Reason</b>:</td> <td><textarea name="msg" rows="5" cols="80" wrap="soft"></textarea></td> </tr>
val balance = Balance.lookupBalance (Web.stoi ($"mod")) %>
<h3><b>Modify balance record</b></h3>
-<form action="balances">
+<form action="balances" method="post">
<input type="hidden" name="id" value="<% $"mod" %>">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name" value="<% #name balance %>"></td> </tr>
ref total = 0.0 %>
<h3><b>New balance</b></h3>
-<form action="balances">
+<form action="balances" method="post">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name"></td> </tr>
<tr> <td><input type="submit" name="cmd" value="Create"></td> </tr>
<h3><b>Modify contact entry</b></h3>
-<form action="contact">
+<form action="contact" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Kind</b>:</td> <td><select name="knd">
<h3><b>Add new contact information</b></h3>
-<form action="contact">
+<form action="contact" method="post">
<input type="hidden" name="cmd" value="add">
<table>
<tr> <td align="right"><b>Kind</b>:</td> <td><select name="knd">
val user = Init.lookupUser (#usr req) %>
<h3><b>Handle request</b></h3>
-<form action="domain">
+<form action="domain" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Requestor</b>:</td> <td><a href="user?id=<% #usr req %>"><% #name user %></a></td> </tr>
Enter the full Internet domain name that you own and would like set up here. We don't do domain registration, so it is your responsibility to register this name with your registrar of choice before submitting it here. The "Reason" field is optional.
-<form action="domain">
+<form action="domain" method="post">
<table>
<tr> <td align="right" valign="top"><b>Domain</b>:</td> <td><input name="req"></td> </tr>
<tr> <td align="right" valign="top"><b>Reason</b>:</td> <td><textarea name="msg" rows="5" cols="80" wrap="soft"></textarea></td> </tr>
val group = Group.lookupGroup (Web.stoi ($"mod")) %>
<h3><b>Modify group record</b></h3>
-<form action="groups">
+<form action="groups" method="post">
<input type="hidden" name="id" value="<% $"mod" %>">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name" value="<% #name group %>"></td> </tr>
<h3><b>Create group</b></h3>
-<form action="groups">
+<form action="groups" method="post">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name"></td> </tr>
<tr> <td><input type="submit" name="cmd" value="Create"></td> </tr>
<h3><b>Grant membership</b></h3>
-<form action="groups">
+<form action="groups" method="post">
<table>
<tr> <td align="right"><b>Group</b>:</td> <td><select name="grp">
<% foreach group in Group.listGroups () do %>
<html><head>
<% val title =
case $"title" of
- "" => "Hcoop Portal"
- | t => ("Hcoop Portal: " ^ t) %>
+ "" => "HCoop Portal"
+ | t => ("HCoop Portal: " ^ t) %>
<title><% Web.html title %></title>
</head><body>
<h3><b>New issue</b></h3>
-<form action="issue">
+<form action="issue" method="post">
<input type="hidden" name="cat" value="<% catId %>">
<input type="hidden" name="cmd" value="add">
<table>
else %>
<h3><b>Modify issue</b></h3>
-<form action="issue">
+<form action="issue" method="post">
<input type="hidden" name="cat" value="<% catId %>">
<input type="hidden" name="save" value="<% id %>">
<table>
else %>
<h3><b>Modify post</b></h3>
-<form action="issue">
+<form action="issue" method="post">
<input type="hidden" name="cat" value="<% catId %>">
<input type="hidden" name="savePost" value="<% id %>">
<textarea name="body" rows="10" cols="80" wrap="soft"><% Web.htmlNl (#body post) %></textarea>
<h3><b>Post to this thread</b></h3>
-<form action="issue">
+<form action="issue" method="post">
<input type="hidden" name="cat" value="<% catId %>">
<input type="hidden" name="iss" value="<% id %>">
<input type="hidden" name="cmd" value="post">
val id = Web.stoi ($"mod");
val kind = Contact.lookupKind id %>
-<form action="kind">
+<form action="kind" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name" value="<% Web.html (#name kind) %>"></td> </tr>
<h3><b>Add a contact kind</b></h3>
-<form action="kind">
+<form action="kind" method="post">
<input type="hidden" name="cmd" value="add">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name"></td> </tr>
<h3><b>Modify link</b></h3>
-<form action="link">
+<form action="link" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Title</b>:</td> <td><input name="title" value="<% Web.html (#title link) %>"></td> </tr>
<h3><b>Add a link to a site you host with Hcoop</b></h3>
-<form action="link">
+<form action="link" method="post">
<input type="hidden" name="cmd" value="add">
<table>
<tr> <td align="right"><b>Title</b>:</td> <td><input name="title"></td> </tr>
val user = Init.lookupUser (#usr req) %>
<h3><b>Handle request</b></h3>
-<form action="list">
+<form action="list" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Requestor</b>:</td> <td><a href="user?id=<% #usr req %>"><% #name user %></a></td> </tr>
<p>If you want to use the Mailman web interface on your new list, and you want this to appear on a different web virtual host than hcoop.net, you should create a file <tt>.mailman</tt> in the domtool directory for this domain, before submitting a request. In that file, put the hostname of the vhost you want to use, and be sure to include a <tt>Mailman</tt> directive in that vhost's configuration.</p>
-<form action="list">
+<form action="list" method="post">
<table>
<tr> <td align="right" valign="top"><b>List name</b>:</td> <td><input name="req"></td> </tr>
<tr> <td align="right" valign="top"><b>Reason</b>:</td> <td><textarea name="msg" rows="5" cols="80" wrap="soft"></textarea></td> </tr>
<h3><b>Modify a location</b></h3>
-<form action="location">
+<form action="location" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Parent</b>:</td> <td><select name="parent">
<h3><b>Add a new location</b></h3>
-<form action="location">
+<form action="location" method="post">
<input type="hidden" name="cmd" value="add">
<table>
<tr> <td align="right"><b>Parent</b>:</td> <td><select name="parent">
Adding yourself to a location automatically adds you to all more general loations.
-<form action="location">
+<form action="location" method="post">
<select name="addLoc">
<% ref indent = 0;
foreach item in withUser do
<h3><b>Remove yourself from a location</b></h3>
-<form action="location">
+<form action="location" method="post">
<select name="remLoc">
<% ref indent = 0;
foreach item in withUser do
<h3><b>New hosting bill</b></h3>
-<form action="money">
+<form action="money" method="post">
<input type="hidden" name="cmd" value="hosting2">
<table>
<tr> <td align="right"><b>Description</b>:</td> <td><input name="descr"></td> </tr>
<h3><b>Modify hosting bill</b></h3>
-<form action="money">
+<form action="money" method="post">
<input type="hidden" name="saveHosting" value="<% id %>">
<table>
<tr> <td align="right"><b>Description</b>:</td> <td><input name="descr" value="<% Web.html (#descr trn) %>"></td> </tr>
Group.requireGroupName "money";
showNormal := false %>
<h3><b>New generic/even transaction</b></h3>
-<form action="money">
+<form action="money" method="post">
<input type="hidden" name="cmd" value="even">
<table>
<tr> <td align="right"><b>Description</b>:</td> <td><input name="descr"></td> </tr>
<h3><b>New member payment</b></h3>
-<form action="money">
+<form action="money" method="post">
<input type="hidden" name="cmd" value="pay2">
<table>
<tr> <td align="right"><b>Description</b>:</td> <td><input name="descr"></td> </tr>
<h3><b>Modify member payment</b></h3>
-<form action="money">
+<form action="money" method="post">
<input type="hidden" name="savePay" value="<% id %>">
<table>
<tr> <td align="right"><b>Description</b>:</td> <td><input name="descr" value="<% Web.html (#descr trn) %>"></td> </tr>
Group.requireGroupName "money";
showNormal := false %>
<h3><b>New generic/even transaction</b></h3>
-<form action="money">
+<form action="money" method="post">
<input type="hidden" name="cmd" value="even">
<table>
<tr> <td align="right"><b>Description</b>:</td> <td><input name="descr"></td> </tr>
val trn = Money.lookupTransaction (Web.stoi ($"modEven")) %>
<h3><b>Modify even transaction</b></h3>
-<form action="money">
+<form action="money" method="post">
<input type="hidden" name="saveEven" value="<% $"modEven" %>">
<table>
<tr> <td align="right"><b>Description</b>:</td> <td><input name="descr" value="<% Web.html (#descr trn) %>"></td> </tr>
<h3><b>Choices</b></h3>
-<form action="poll">
+<form action="poll" method="post">
<input type="hidden" name="vote2" value="<% id %>">
<% val choices = Poll.listChoicesWithMyVotes id;
if #votes poll = 1 then %>
Poll.requireCanModify poll %>
<h3><b>Modify poll</b></h3>
-<form action="poll">
+<form action="poll" method="post">
<input type="hidden" name="id" value="<% $"mod" %>">
<table>
<tr> <td align="right"><b>Title</b>:</td> <td><input name="title" value="<% Web.html (#title poll) %>"></td> </tr>
val poll = Poll.lookupPoll (#pol cho);
Poll.requireCanModify poll %>
-<form action="poll">
+<form action="poll" method="post">
<input type="hidden" name="saveChoice" value="<% id %>">
<table>
<tr> <td align="right"><b>Text</b>:</td> <td><input name="descr" value="<% Web.html (#descr cho) %>"></td> </tr>
<br><hr><br>
<h3><b>Add a new choice</b></h3>
-<form action="poll">
+<form action="poll" method="post">
<input type="hidden" name="addChoice" value="<% id %>">
<table>
<tr> <td align="right"><b>Text</b>:</td> <td><input name="descr"></td> </tr>
<h3><b>Create a poll</b></h3>
-<form action="poll">
+<form action="poll" method="post">
<input type="hidden" name="cmd" value="add">
<table>
<tr> <td align="right"><b>Title</b>:</td> <td><input name="title"></td> </tr>
<% if Group.inGroupNum 0 then %>
<b><h3>Admin</h3></b>
+<a href="apps?cmd=approved">Approved applicants waiting for accounts</a><br>
<a href="users">Members</a><br>
<a href="groups">Groups</a><br>
<a href="balances">Balances</a><br>
<a href="kind">Contact kinds</a><br>
+<a href="roll">Roll call!</a><br>
<% end %>
<b><h3>Your account</h3></b>
%><h3><b>Preferences updated</b></h3><%
end %>
-<form action="pref">
+<form action="pref" method="post">
<input type="hidden" name="cmd" value="mod">
<table>
<tr> <td align="right"><input type="checkbox" name="dir"<% if Pref.hasDirectory you then %> checked<% end %>></td> <td>Include me in the public member directory.</td> </tr>
--- /dev/null
+<% @header [("title", ["Roll call!"])];
+
+val you = Init.getUserId ();
+
+ref viewingCall = NONE;
+ref showNormal = true;
+
+if $"cmd" = "respond" then
+ showNormal := false;
+
+ val rol = Web.stoi ($"rol");
+ val code = $"code";
+ val rc = Roll.lookupEntry (rol, you);
+
+ if code = #code rc then
+ Roll.respond (rol, you);
+ %><h3><b>Your response has been saved. Thank you!</b></h3><%
+ else
+ %><h3><b>Incorrect code!</b></h3><%
+ end
+elseif $"cmd" = "add" then
+ Group.requireGroupNum 0;
+ val title = $"title";
+ val msg = $"msg";
+ if title = "" then
+ %><h3><b>Your roll call must have a title.</b></h3><%
+ else
+ val id = Roll.addRollCall (title, msg);
+ viewingCall := SOME id;
+ %><h3><b>Roll call added!</b></h3><%
+ end
+
+elseif $"mod" <> "" then
+ Group.requireGroupNum 0;
+ showNormal := false;
+ val rc = Roll.lookupRollCall (Web.stoi ($"mod")) %>
+<h3><b>Modify roll call</b></h3>
+
+<form action="roll" method="post">
+<input type="hidden" name="id" value="<% $"mod" %>">
+<table>
+<tr> <td align="right"><b>Title</b>:</td> <td><input name="title" value="<% Web.html (#title rc) %>"></td> </tr>
+<tr> <td align="right" valign="top"><b>Message</b>:</td> <td><textarea name="msg" wrap="soft" rows="5" cols="80"><% Web.html (#msg rc) %></textarea></td> </tr>
+<tr> <td><input type="submit" name="cmd" value="Save"></td> </tr>
+</table>
+</form>
+
+<% elseif $"cmd" = "Save" then
+ Group.requireGroupNum 0;
+ val rc = Roll.lookupRollCall (Web.stoi ($"id"));
+
+ val title = $"title";
+ val msg = $"msg";
+ if title = "" then
+ %><h3><b>Your rol call must have a title.</b></h3><%
+ else
+ Roll.modRollCall {rc with title = title, msg = msg};
+ viewingCall := SOME (#id rc);
+ %><h3><b>Roll call saved.</b></h3><%
+ end
+
+elseif $"del" <> "" then
+ Group.requireGroupNum 0;
+ showNormal := false;
+ val rc = Roll.lookupRollCall (Web.stoi ($"del")) %>
+ <h3><b>Are you sure you want to delete roll call "<a href="roll?view=<% #id rc %>"><% Web.html (#title rc) %></a>"?</b></h3>
+ <a href="roll?del2=<% $"del" %>">Yes, delete <% Web.html (#title rc) %>!</a>
+
+<% elseif $"del2" <> "" then
+ Group.requireGroupNum 0;
+ val rc = Roll.lookupRollCall (Web.stoi ($"del2"));
+ Roll.deleteRollCall (Web.stoi ($"del2")) %>
+ <h3><b><% Web.html (#title rc) %> deleted!</b></h3>
+
+<% elseif $"cmd" = "mailall" then
+ Group.requireGroupNum 0;
+ showNormal := false;
+ ref first = true %>
+
+<a href="mailto:<% foreach uname in Roll.activeUsernames () do
+ if first then
+ first := false
+ else
+ %>,<%
+ end
+ uname; Init.emailSuffix
+end %>">Mail everyone!</a>
+
+<% elseif $"view" <> "" then
+ Group.requireGroupNum 0;
+ val id = Web.stoi ($"view");
+ viewingCall := SOME id
+end;
+
+if showNormal then
+ Group.requireGroupNum 0;
+
+ switch viewingCall of
+ NONE => %>
+<h3><b>Existing roll calls</b></h3>
+
+<% foreach rc in Roll.listRollCalls () do %>
+<li> <a href="roll?view=<% #id rc %>"><% Web.html (#title rc) %></a> (<% #started rc %>)</li>
+<% end %>
+
+<h3><b>New roll call</b></h3>
+
+<form action="roll" method="post">
+<input type="hidden" name="cmd" value="add">
+<table>
+<tr> <td align="right"><b>Title</b>:</td> <td><input name="title"></td> </tr>
+<tr> <td align="right" valign="top"><b>Message</b>:</td> <td><textarea name="msg" wrap="soft" rows="5" cols="80"></textarea></td> </tr>
+<tr> <td><input type="submit" value="Create"></td> </tr>
+</table>
+</form>
+
+<a href="roll?cmd=mailall">Mail everyone! (provides mailto: link)</a>
+
+<% | SOME id =>
+ val rc = Roll.lookupRollCall id %>
+ <h3><b>Roll call "<% Web.html (#title rc) %>"</b></h3>
+ <table border="0">
+ <tr> <td align="right"><b>Started:</b></td> <td><% #started rc %></td> </tr>
+ <tr> <td align="right" valign="top"><b>Message:</b></td> <td><% Web.htmlNl (#msg rc) %></td> </tr>
+ </table>
+ [ <a href="roll?mod=<% id %>">Modify</a> | <a href="roll?del=<% id %>">Delete</a> ]<br>
+
+<% val (didnt, did) = Roll.listEntries id %>
+
+<h2><b>Didn't respond yet:</b></h2>
+<% foreach (usr, ent) in didnt do %>
+<li> <a href="user?id=<% #id usr %>"><% Web.html (#name usr) %></a></li>
+<% end %>
+
+<h2><b>Responded:</b></h2>
+<% foreach (usr, ent) in did do %>
+<li> <a href="user?id=<% #id usr %>"><% Web.html (#name usr) %></a> (<%
+ switch #responded ent of SOME st => st end %>)</li>
+<% end %>
+
+<% end
+end %>
+
+<% @footer[] %>
\ No newline at end of file
--- /dev/null
+signature ROLL =
+sig
+ val activeUsernames : unit -> string list
+
+ type roll_call = {
+ id : int,
+ title : string,
+ msg : string,
+ started : Init.C.timestamp
+ }
+
+ val addRollCall : string * string -> int
+ val modRollCall : roll_call -> unit
+ val deleteRollCall : int -> unit
+ val lookupRollCall : int -> roll_call
+ val listRollCalls : unit -> roll_call list
+
+ type roll_call_entry = {
+ rol : int,
+ usr : int,
+ code : string,
+ responded : Init.C.timestamp option
+ }
+
+ val listEntries : int -> (Init.user * roll_call_entry) list * (Init.user * roll_call_entry) list
+ val lookupEntry : int * int -> roll_call_entry
+ val respond : int * int -> unit
+end
--- /dev/null
+structure Roll :> ROLL = struct
+
+open Init Sql Util
+
+fun activeUsernames () =
+ let
+ fun mkRow [name] = C.stringFromSql name
+ | mkRow row = rowError ("activeUsernames", row)
+ in
+ C.map (getDb ()) mkRow "SELECT name FROM WebUserActive ORDER BY name"
+ end
+
+type roll_call = {
+ id : int,
+ title : string,
+ msg : string,
+ started : C.timestamp
+}
+
+fun mkRollRow [id, title, msg, started] =
+ {id = C.intFromSql id, title = C.stringFromSql title,
+ msg = C.stringFromSql msg, started = C.timestampFromSql started}
+ | mkRollRow row = rowError ("roll", row)
+
+fun addRollCall (title, msg) =
+ let
+ val db = getDb ()
+ val id = nextSeq (db, "RollCallSeq")
+
+ fun addUser [uid, name] =
+ let
+ val uid = C.intFromSql uid
+ val name = C.stringFromSql name
+ val code = randomPassword ()
+
+ val _ = C.dml db ($`INSERT INTO RollCallEntry (rol, usr, code, responded)
+ VALUES (^(C.intToSql id), ^(C.intToSql uid), ^(C.stringToSql code), NULL)`)
+
+ val mail = Mail.mopen ()
+ in
+ Mail.mwrite (mail, "From: Hcoop Portal <hcoop");
+ Mail.mwrite (mail, emailSuffix);
+ Mail.mwrite (mail, ">\nTo: ");
+ Mail.mwrite (mail, name);
+ Mail.mwrite (mail, emailSuffix);
+ Mail.mwrite (mail, "\nSubject: HCoop Roll Call: ");
+ Mail.mwrite (mail, title);
+ Mail.mwrite (mail, "\n\n");
+ Mail.mwrite (mail, "The admins want to make sure that they can reach everyone by e-mail. To let them know that you're here, please visit this URL:\n\t");
+ Mail.mwrite (mail, urlPrefix);
+ Mail.mwrite (mail, "roll?cmd=respond&rol=");
+ Mail.mwrite (mail, Int.toString id);
+ Mail.mwrite (mail, "&code=");
+ Mail.mwrite (mail, code);
+ Mail.mwrite (mail, "\nYou may have to hit \"reload\" in your web browser, if you aren't already logged into the portal.\n\n");
+ Mail.mwrite (mail, msg);
+ ignore (Mail.mclose mail)
+ end
+ | addUser row = rowError ("add roll entry", row)
+ in
+ C.dml db ($`INSERT INTO RollCall (id, title, msg, started)
+ VALUES (^(C.intToSql id), ^(C.stringToSql title), ^(C.stringToSql msg),
+ CURRENT_TIMESTAMP)`);
+ C.app db addUser "SELECT id, name FROM WebUserActive";
+ id
+ end
+
+fun modRollCall (rc : roll_call) =
+ let
+ val db = getDb ()
+ in
+ ignore (C.dml db ($`UPDATE RollCall SET
+ title = ^(C.stringToSql (#title rc)),
+ msg = ^(C.stringToSql (#msg rc))
+ WHERE id = ^(C.intToSql (#id rc))`))
+ end
+
+fun deleteRollCall id =
+ ignore (C.dml (getDb ()) ($`DELETE FROM RollCall WHERE id = ^(C.intToSql id)`))
+
+fun lookupRollCall id =
+ case C.oneOrNoRows (getDb ()) ($`SELECT id, title, msg, started
+ FROM RollCall
+ WHERE id = ^(C.intToSql id)`) of
+ NONE => raise Fail "Roll call not found"
+ | SOME row => mkRollRow row
+
+fun listRollCalls id =
+ C.map (getDb ()) mkRollRow "SELECT id, title, msg, started FROM RollCall ORDER BY started DESC"
+
+type roll_call_entry = {
+ rol : int,
+ usr : int,
+ code : string,
+ responded : C.timestamp option
+}
+
+fun mkEntryRow [rol, usr, code, responded] =
+ {rol = C.intFromSql rol, usr = C.intFromSql usr,
+ code = C.stringFromSql code,
+ responded = (if C.isNull responded then NONE else SOME (C.timestampFromSql responded))}
+ | mkEntryRow row = rowError ("roll entry", row)
+
+fun lookupEntry (rol, usr) =
+ case C.oneOrNoRows (getDb ()) ($`SELECT rol, usr, code, responded
+ FROM RollCallEntry
+ WHERE rol = ^(C.intToSql rol) AND usr = ^(C.intToSql usr)`) of
+ NONE => raise Fail "Roll call entry not found"
+ | SOME row => mkEntryRow row
+
+fun listEntries id =
+ let
+ fun folder (_ :: row, (didnt, did)) =
+ let
+ val ent = mkEntryRow row
+ val uent = (Init.lookupUser (#usr ent), ent)
+ in
+ case #responded ent of
+ NONE => (uent :: didnt, did)
+ | SOME _ => (didnt, uent :: did)
+ end
+ | folder (row, _) = rowError ("listEntries folder", row)
+ in
+ C.fold (getDb ()) folder ([], [])
+ ($`SELECT name, rol, usr, code, responded
+ FROM RollCallEntry JOIN WebUser ON id = usr
+ WHERE rol = ^(C.intToSql id)
+ ORDER BY responded, name DESC`)
+ end
+
+fun respond (rol, usr) =
+ ignore (C.dml (getDb ()) ($`UPDATE RollCallEntry
+ SET responded = CURRENT_TIMESTAMP
+ WHERE rol = ^(C.intToSql rol) AND usr = ^(C.intToSql usr)`))
+
+end
<h3><b>Modify category</b></h3>
-<form action="support">
+<form action="support" method="post">
<input type="hidden" name="save" value="<% id %>">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name" value="<% Web.html (#name cat) %>"></td> </tr>
<h3><b>Add new category</b></h3>
-<form action="support">
+<form action="support" method="post">
<input type="hidden" name="cmd" value="add">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name"></td> </tr>
AS SELECT id, name, rname, bal, joined, app
FROM WebUser
LEFT OUTER JOIN (SELECT usr FROM Membership JOIN WebGroup
- ON grp = WebGroup.id AND WebGroup.name = 'retired') AS mem
+ ON grp = WebGroup.id AND (WebGroup.name IN ('retired', 'phantom'))) AS mem
ON usr = WebUser.id
-
WHERE usr IS NULL;
+CREATE TABLE RollCall(
+ id INTEGER PRIMARY KEY,
+ title TEXT NOT NULL,
+ msg TEXT NOT NULL,
+ started TIMESTAMP NOT NULL);
+
+CREATE SEQUENCE RollCallSeq START 1;
+
+CREATE TABLE RollCallEntry(
+ rol INTEGER NOT NULL,
+ usr INTEGER NOT NULL,
+ code TEXT NOT NULL,
+ responded TIMESTAMP,
+ PRIMARY KEY (rol, usr),
+ FOREIGN KEY (rol) REFERENCES RollCall(id) ON DELETE CASCADE,
+ FOREIGN KEY (usr) REFERENCES WebUser(id) ON DELETE CASCADE);
val user = Init.lookupUser (Web.stoi ($"mod")) %>
<h3><b>Modify member record</b></h3>
-<form action="users">
+<form action="users" method="post">
<input type="hidden" name="id" value="<% $"mod" %>">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name" value="<% #name user %>"></td> </tr>
<% if showNormal then %>
<h3><b>New member</b></h3>
-<form action="users">
+<form action="users" method="post">
<table>
<tr> <td align="right"><b>Name</b>:</td> <td><input name="name"></td> </tr>
<tr> <td align="right"><b>Real name</b>:</td> <td><input name="rname"></td> </tr>
fun neg (r : real) = ~r
fun add (r1 : real, r2) = r1 + r2
-fun isIdent ch = Char.isLower ch orelse Char.isDigit ch
+fun isIdent ch = Char.isLower ch orelse Char.isDigit ch orelse ch = #"-"
fun validHost s =
size s > 0 andalso size s < 20 andalso List.all isIdent (String.explode s)