signature INPUT = sig con paper :: {Type} constraint [Id, Document] ~ paper type userId val userId_inj : sql_injectable_prim userId table user : {Id : userId, Nam : string, Password : string, Chair : bool, OnPc : bool} PRIMARY KEY Id, CONSTRAINT Nam UNIQUE Nam type paperId val paperId_inj : sql_injectable_prim paperId val paperId_show : show paperId val paperId_read : read paperId val paperId_eq : eq paperId table paper : ([Id = paperId, Document = blob] ++ paper) PRIMARY KEY Id val checkLogin : transaction (option {Id : userId, Nam : string, Chair : bool, OnPc : bool}) val getLogin : transaction {Id : userId, Nam : string, Chair : bool, OnPc : bool} val getPcLogin : transaction {Id : userId, Nam : string, Chair : bool} val checkChair : transaction unit val summarizePaper : ctx ::: {Unit} -> [[Body] ~ ctx] => $paper -> xml ([Body] ++ ctx) [] [] end signature OUTPUT = sig con paper :: {Type} type userId type paperId val linksForPc : xbody val linksForChair : xbody con yourPaperTables :: {{Type}} constraint [Paper] ~ yourPaperTables val joinYourPaper : tabs ::: {{Type}} -> paper ::: {Type} -> [[Paper] ~ tabs] => [[Paper] ~ yourPaperTables] => [tabs ~ yourPaperTables] => [[Id] ~ paper] => userId -> sql_from_items ([Paper = [Id = paperId] ++ paper] ++ tabs) -> sql_from_items (yourPaperTables ++ [Paper = [Id = paperId] ++ paper] ++ tabs) end open Meta functor Make(M : sig con paper :: {(Type * Type)} constraint [Id, Document, Authors] ~ paper val paper : $(map Meta.meta paper) val paperFolder : folder paper con paperPrivate :: {Type} constraint [Id, Document, Authors] ~ paperPrivate constraint paper ~ paperPrivate val paperPrivate : $(map Meta.private paperPrivate) val paperPrivateFolder : folder paperPrivate con review :: {(Type * Type)} constraint [Paper, User] ~ review val review : $(map Meta.meta review) val reviewFolder : folder review val submissionDeadline : time val summarizePaper : ctx ::: {Unit} -> [[Body] ~ ctx] => $(map fst paper ++ paperPrivate) -> xml ([Body] ++ ctx) [] [] functor Make (M : INPUT where con paper = map fst paper ++ paperPrivate) : OUTPUT where con paper = map fst paper ++ paperPrivate where con userId = M.userId where con paperId = M.paperId end) = struct table user : {Id : int, Nam : string, Password : string, Chair : bool, OnPc : bool} PRIMARY KEY Id, CONSTRAINT Nam UNIQUE Nam sequence userId con paper = [Id = int, Document = blob] ++ map fst M.paper ++ M.paperPrivate table paper : paper PRIMARY KEY Id sequence paperId table authorship : {Paper : int, User : int} PRIMARY KEY (Paper, User), CONSTRAINT Paper FOREIGN KEY Paper REFERENCES paper(Id) ON DELETE CASCADE, 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), CONSTRAINT Paper FOREIGN KEY Paper REFERENCES paper(Id), CONSTRAINT User FOREIGN KEY User REFERENCES user(Id) sequence reviewId cookie login : {Id : int, Password : string} val checkLogin = r <- getCookie login; case r of None => return None | Some r => oneOrNoRows1 (SELECT user.Id, user.Nam, user.Chair, user.OnPc FROM user WHERE user.Id = {[r.Id]} AND user.Password = {[r.Password]}) val getLogin = ro <- checkLogin; case ro of None => error You must be logged in to do that. | Some r => return r val getPcLogin = r <- getLogin; if r.OnPc then return (r -- #OnPc) else error You are not on the PC. val checkChair = r <- getLogin; if r.Chair then return () else error You are not a chair. structure O = M.Make(struct val user = user val paper = paper val checkLogin = checkLogin val getLogin = getLogin val getPcLogin = getPcLogin val checkChair = checkChair val summarizePaper = @@M.summarizePaper end) val checkOnPc = r <- getLogin; if r.OnPc then return () else error You aren't authorized to do that. fun checkPaper id = r <- getLogin; if r.OnPc then return () else error You aren't authorized to see that paper. structure Users = BulkEdit.Make(struct con keyName = #Id val visible = {Nam = string "Name", Chair = bool "Chair?", OnPc = bool "On PC?"} val title = "Users" val isAllowed = me <- checkLogin; return (Option.isSome me) val t = user end) fun doRegister r = n <- oneRowE1 (SELECT COUNT( * ) AS N FROM user WHERE user.Nam = {[r.Nam]}); if n > 0 then register (Some "Sorry; that username is taken.") else id <- nextval userId; dml (INSERT INTO user (Id, Nam, Password, Chair, OnPc) VALUES ({[id]}, {[r.Nam]}, {[r.Password]}, FALSE, FALSE)); setCookie login {Id = id, Password = r.Password}; main () and register msg = return

Registering a New Account

{case msg of None => | Some msg =>
{[msg]}
}
Username:
Password:
and signin r = ro <- oneOrNoRowsE1 (SELECT user.Id AS N FROM user WHERE user.Nam = {[r.Nam]} AND user.Password = {[r.Password]}); (case ro of None => return () | Some id => setCookie login {Id = id, Password = r.Password}); m <- main' (); return {case ro of None =>
Invalid username or password.
| _ => } {m} and main' () = me <- checkLogin; now <- now; return and main () = m <- main' (); return {m} and submit () = let fun doSubmit r = 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 At least one of those coauthor usernames isn't registered. 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 ++ initialize M.paperPrivate M.paperPrivateFolder)); List.app (fn uid => case uid of None => error Impossible empty uid! | Some uid => dml (INSERT INTO authorship (Paper, User) VALUES ({[id]}, {[uid]}))) (Some me.Id :: coauthors); return Thanks for submitting! in me <- getLogin; numAuthors <- Dnat.zero; return

Submit a Paper

Author: {[me.Nam]}
{Dnat.render Author:
numAuthors}