diff demo/more/conference.ur @ 1010:6b0f3853cc81

authorship table
author Adam Chlipala <adamc@hcoop.net>
date Thu, 22 Oct 2009 14:05:48 -0400
parents 59097824f19b
children 16f7cb0891b6
line wrap: on
line diff
--- a/demo/more/conference.ur	Thu Oct 22 12:16:31 2009 -0400
+++ b/demo/more/conference.ur	Thu Oct 22 14:05:48 2009 -0400
@@ -2,7 +2,7 @@
 
 functor Make(M : sig
                  con paper :: {(Type * Type)}
-                 constraint [Id, Document] ~ paper
+                 constraint [Id, Document, Authors] ~ paper
                  val paper : $(map meta paper)
                  val paperFolder : folder paper
 
@@ -24,6 +24,11 @@
           PRIMARY KEY Id
     sequence paperId
 
+    table authorship : {Paper : int, User : int}
+          PRIMARY KEY (Paper, User),
+          CONSTRAINT Paper FOREIGN KEY Paper REFERENCES paper(Id),
+          CONSTRAINT User FOREIGN KEY User REFERENCES user(Id)
+
     con review = [Paper = int, User = int] ++ map fst M.review
     table review : review
           PRIMARY KEY (Paper, User),
@@ -43,14 +48,18 @@
                           WHERE user.Id = {[r.Id]}
                             AND user.Password = {[r.Password]})
 
+    val getLogin =
+        ro <- checkLogin;
+        case ro of
+            None => error <xml>You must be logged in to do that.</xml>
+          | Some r => return r
+
     fun checkPaper id =
-        ro <- checkLogin;
-        if (case ro of
-                None => False
-              | Some r => r.OnPc) then
+        r <- getLogin;
+        if r.OnPc then
             return ()
         else
-            error <xml>You must be logged in to do that.</xml>
+            error <xml>You aren't authorized to see that paper.</xml>
 
     structure Users = BulkEdit.Make(struct
                                         con keyName = #Id
@@ -66,6 +75,29 @@
                                         val t = user
                                     end)
 
+    datatype dnat = O | S of source dnat
+    type dnatS = source dnat
+
+    fun inc n =
+        v <- get n;
+        case v of
+            O =>
+            n' <- source O;
+            set n (S n')
+          | S n => inc n
+
+    fun dec n =
+        let
+            fun dec' last n =
+                v <- get n;
+                case v of
+                    O => (case last of
+                              None => return ()
+                            | Some n' => set n' O)
+                  | S n' => dec' (Some n) n'
+        in
+            dec' None n
+        end
 
     fun doRegister r =
         n <- oneRowE1 (SELECT COUNT( * ) AS N
@@ -151,18 +183,54 @@
     and submit () =
         let
             fun doSubmit r =
-                id <- nextval paperId;
-                dml (insert paper ({Id = sql_inject id, Document = sql_inject (fileData r.Document)}
-                                       ++ ensql M.paper (r -- #Document) M.paperFolder));
-                return <xml><body>
-                  OK, done!
-                </body></xml>
+                me <- getLogin;
+                coauthors <- List.mapM (fn name => oneOrNoRowsE1 (SELECT user.Id AS N
+                                                                  FROM user
+                                                                  WHERE user.Nam = {[name.Nam]})) r.Authors;
+                if List.exists Option.isNone coauthors then
+                    error <xml>At least one of those coauthor usernames isn't registered.</xml>
+                else
+                    id <- nextval paperId;
+                    dml (insert paper ({Id = sql_inject id, Document = sql_inject (fileData r.Document)}
+                                           ++ ensql M.paper (r -- #Authors -- #Document) M.paperFolder));
+                    List.app (fn uid =>
+                                 case uid of
+                                     None => error <xml>Impossible empty uid!</xml>
+                                   | Some uid => dml (INSERT INTO authorship (Paper, User)
+                                                      VALUES ({[id]}, {[uid]})))
+                             (Some me.Id :: coauthors);
+                    return <xml><body>
+                      Thanks for submitting!
+                    </body></xml>
+
+            fun authorBlanks n =
+                case n of
+                    O => <xml/>
+                  | S n => <xml>
+                    <entry><b>Author:</b> <textbox{#Nam}/><br/></entry>
+                    <dyn signal={authorBlanksS n}/>
+                  </xml>
+
+            and authorBlanksS n =
+                n <- signal n;
+                return (authorBlanks n)
         in
+            me <- getLogin;
+            numAuthors <- source O;
+
             return <xml><body>
               <h1>Submit a Paper</h1>
               
               <form>
-                {allWidgets M.paper M.paperFolder}
+                <b>Author:</b> {[me.Nam]}<br/>
+                <subforms{#Authors}>
+                  <dyn signal={authorBlanksS numAuthors}/>
+                </subforms>
+                <button value="Add author" onclick={inc numAuthors}/><br/>
+                <button value="Remove author" onclick={dec numAuthors}/><br/>
+                <br/>
+
+                {useMore (allWidgets M.paper M.paperFolder)}
                 <b>Paper:</b> <upload{#Document}/><br/>
                 <submit value="Submit" action={doSubmit}/>
               </form>
@@ -185,11 +253,21 @@
         ro <- oneOrNoRows (SELECT paper.{{map fst M.paper}}, octet_length(paper.Document) AS N
                            FROM paper
                            WHERE paper.Id = {[id]});
+        authors <- queryX (SELECT user.Nam
+                           FROM authorship
+                             JOIN user ON authorship.User = user.Id
+                           WHERE authorship.Paper = {[id]})
+                   (fn r => <xml><li>{[r.User.Nam]}</li></xml>);
         case ro of
             None => error <xml>Paper not found!</xml>
           | Some r => return <xml><body>
             <h1>Paper #{[id]}</h1>
 
+            <h3>Authors:</h3>
+            <ul>
+              {authors}
+            </ul>
+
             {allContent M.paper r.Paper M.paperFolder}<br/>
 
             {if r.N = 0 then