adamc@1022: signature INPUT = sig
adamc@1023: con paper :: {Type}
adamc@1022: constraint [Id, Document] ~ paper
adamc@1022:
adamc@1022: type userId
adamc@1022: val userId_inj : sql_injectable_prim userId
adamc@1022: table user : {Id : userId, Nam : string, Password : string, Chair : bool, OnPc : bool}
adamc@1022: PRIMARY KEY Id,
adamc@1022: CONSTRAINT Nam UNIQUE Nam
adamc@1022:
adamc@1022: type paperId
adamc@1022: val paperId_inj : sql_injectable_prim paperId
adamc@1023: val paperId_show : show paperId
adamc@1023: val paperId_read : read paperId
adamc@1025: val paperId_eq : eq paperId
adamc@1023: table paper : ([Id = paperId, Document = blob] ++ paper)
adamc@1022: PRIMARY KEY Id
adamc@1022:
adamc@1022: val checkLogin : transaction (option {Id : userId, Nam : string, Chair : bool, OnPc : bool})
adamc@1022: val getLogin : transaction {Id : userId, Nam : string, Chair : bool, OnPc : bool}
adamc@1023: val getPcLogin : transaction {Id : userId, Nam : string, Chair : bool}
adamc@1025: val checkChair : transaction unit
adamc@1023: val summarizePaper : ctx ::: {Unit} -> [[Body] ~ ctx] => $paper -> xml ([Body] ++ ctx) [] []
adamc@1022: end
adamc@1022:
adamc@1022: signature OUTPUT = sig
adamc@1023: con paper :: {Type}
adamc@1022: type userId
adamc@1022: type paperId
adamc@1022:
adamc@1022: val linksForPc : xbody
adamc@1025: val linksForChair : xbody
adamc@1022:
adamc@1022: con yourPaperTables :: {{Type}}
adamc@1022: constraint [Paper] ~ yourPaperTables
adamc@1022: val joinYourPaper : tabs ::: {{Type}} -> paper ::: {Type}
adamc@1022: -> [[Paper] ~ tabs] => [[Paper] ~ yourPaperTables] => [tabs ~ yourPaperTables] => [[Id] ~ paper] =>
adamc@1022: sql_from_items ([Paper = [Id = paperId] ++ paper] ++ tabs)
adamc@1022: -> sql_from_items (yourPaperTables ++ [Paper = [Id = paperId] ++ paper] ++ tabs)
adamc@1022: end
adamc@1022:
adamc@1004: open Meta
adamc@1001:
adamc@1001: functor Make(M : sig
adamc@1003: con paper :: {(Type * Type)}
adamc@1010: constraint [Id, Document, Authors] ~ paper
adamc@1003: val paper : $(map meta paper)
adamc@1007: val paperFolder : folder paper
adamc@1003:
adamc@1001: con review :: {(Type * Type)}
adamc@1003: constraint [Paper, User] ~ review
adamc@1003: val review : $(map meta review)
adamc@1011: val reviewFolder : folder review
adamc@1006:
adamc@1006: val submissionDeadline : time
adamc@1023: val summarizePaper : ctx ::: {Unit} -> [[Body] ~ ctx] => $(map fst paper) -> xml ([Body] ++ ctx) [] []
adamc@1022:
adamc@1023: functor Make (M : INPUT where con paper = map fst paper)
adamc@1023: : OUTPUT where con paper = map fst paper
adamc@1023: where con userId = M.userId
adamc@1022: where con paperId = M.paperId
adamc@1001: end) = struct
adamc@1001:
adamc@1003: table user : {Id : int, Nam : string, Password : string, Chair : bool, OnPc : bool}
adamc@1003: PRIMARY KEY Id,
adamc@1003: CONSTRAINT Nam UNIQUE Nam
adamc@1003: sequence userId
adamc@1003:
adamc@1008: con paper = [Id = int, Document = blob] ++ map fst M.paper
adamc@1003: table paper : paper
adamc@1003: PRIMARY KEY Id
adamc@1003: sequence paperId
adamc@1003:
adamc@1010: table authorship : {Paper : int, User : int}
adamc@1010: PRIMARY KEY (Paper, User),
adamc@1011: CONSTRAINT Paper FOREIGN KEY Paper REFERENCES paper(Id) ON DELETE CASCADE,
adamc@1010: CONSTRAINT User FOREIGN KEY User REFERENCES user(Id)
adamc@1010:
adamc@1003: con review = [Paper = int, User = int] ++ map fst M.review
adamc@1003: table review : review
adamc@1003: PRIMARY KEY (Paper, User),
adamc@1003: CONSTRAINT Paper FOREIGN KEY Paper REFERENCES paper(Id),
adamc@1003: CONSTRAINT User FOREIGN KEY User REFERENCES user(Id)
adamc@1003: sequence reviewId
adamc@1003:
adamc@1003: cookie login : {Id : int, Password : string}
adamc@1003:
adamc@1004: val checkLogin =
adamc@1003: r <- getCookie login;
adamc@1003: case r of
adamc@1003: None => return None
adamc@1003: | Some r =>
adamc@1003: oneOrNoRows1 (SELECT user.Id, user.Nam, user.Chair, user.OnPc
adamc@1003: FROM user
adamc@1003: WHERE user.Id = {[r.Id]}
adamc@1003: AND user.Password = {[r.Password]})
adamc@1003:
adamc@1010: val getLogin =
adamc@1010: ro <- checkLogin;
adamc@1010: case ro of
adamc@1010: None => error You must be logged in to do that.
adamc@1010: | Some r => return r
adamc@1010:
adamc@1023: val getPcLogin =
adamc@1023: r <- getLogin;
adamc@1023: if r.OnPc then
adamc@1023: return (r -- #OnPc)
adamc@1023: else
adamc@1023: error You are not on the PC.
adamc@1023:
adamc@1025: val checkChair =
adamc@1025: r <- getLogin;
adamc@1025: if r.Chair then
adamc@1025: return ()
adamc@1025: else
adamc@1025: error You are not a chair.
adamc@1025:
adamc@1022: structure O = M.Make(struct
adamc@1022: val user = user
adamc@1022: val paper = paper
adamc@1022: val checkLogin = checkLogin
adamc@1022: val getLogin = getLogin
adamc@1023: val getPcLogin = getPcLogin
adamc@1025: val checkChair = checkChair
adamc@1023: val summarizePaper = @@M.summarizePaper
adamc@1022: end)
adamc@1022:
adamc@1022: val checkOnPc =
adamc@1022: r <- getLogin;
adamc@1022: if r.OnPc then
adamc@1022: return ()
adamc@1022: else
adamc@1022: error You aren't authorized to do that.
adamc@1022:
adamc@1009: fun checkPaper id =
adamc@1010: r <- getLogin;
adamc@1010: if r.OnPc then
adamc@1009: return ()
adamc@1009: else
adamc@1010: error You aren't authorized to see that paper.
adamc@1009:
adamc@1004: structure Users = BulkEdit.Make(struct
adamc@1004: con keyName = #Id
adamc@1004: val visible = {Nam = string "Name",
adamc@1004: Chair = bool "Chair?",
adamc@1004: OnPc = bool "On PC?"}
adamc@1004:
adamc@1004: val title = "Users"
adamc@1004: val isAllowed =
adamc@1004: me <- checkLogin;
adamc@1004: return (Option.isSome me)
adamc@1004:
adamc@1004: val t = user
adamc@1004: end)
adamc@1004:
adamc@1003: fun doRegister r =
adamc@1003: n <- oneRowE1 (SELECT COUNT( * ) AS N
adamc@1003: FROM user
adamc@1003: WHERE user.Nam = {[r.Nam]});
adamc@1003: if n > 0 then
adamc@1003: register (Some "Sorry; that username is taken.")
adamc@1003: else
adamc@1003: id <- nextval userId;
adamc@1003: dml (INSERT INTO user (Id, Nam, Password, Chair, OnPc)
adamc@1003: VALUES ({[id]}, {[r.Nam]}, {[r.Password]}, FALSE, FALSE));
adamc@1003: setCookie login {Id = id, Password = r.Password};
adamc@1003: main ()
adamc@1003:
adamc@1003: and register msg = return
adamc@1003:
Registering a New Account
adamc@1003:
adamc@1003: {case msg of
adamc@1003: None =>
adamc@1003: | Some msg =>
{[msg]}
}
adamc@1003:
adamc@1003:
adamc@1003:
adamc@1003:
adamc@1006: and signin r =
adamc@1006: ro <- oneOrNoRowsE1 (SELECT user.Id AS N
adamc@1006: FROM user
adamc@1006: WHERE user.Nam = {[r.Nam]}
adamc@1006: AND user.Password = {[r.Password]});
adamc@1006: (case ro of
adamc@1006: None => return ()
adamc@1006: | Some id => setCookie login {Id = id, Password = r.Password});
adamc@1006: m <- main' ();
adamc@1006: return
adamc@1006: {case ro of
adamc@1006: None =>
Invalid username or password.
adamc@1006: | _ => }
adamc@1006:
adamc@1006: {m}
adamc@1006:
adamc@1006:
adamc@1006: and main' () =
adamc@1004: me <- checkLogin;
adamc@1006: now <- now;
adamc@1006: return
adamc@1003: {case me of
adamc@1006: None =>
adamc@1006:
adamc@1009:
adamc@1009:
adamc@1022: and all () =
adamc@1022: checkOnPc;
adamc@1022: listPapers (SELECT paper.Id, paper.{{map fst M.paper}} FROM paper)
adamc@1022:
adamc@1022: and your () =
adamc@1022: me <- getLogin;
adamc@1022: listPapers (sql_query {Rows = sql_query1 {Distinct = False,
adamc@1022: From = O.joinYourPaper (sql_from_table [#Paper] paper),
adamc@1022: Where = (WHERE TRUE),
adamc@1022: GroupBy = sql_subset_all [_],
adamc@1022: Having = (WHERE TRUE),
adamc@1022: SelectFields = sql_subset [[Paper = ([Id = _] ++ map fst M.paper, _)]
adamc@1022: ++ map (fn ts => ([], ts))
adamc@1022: O.yourPaperTables],
adamc@1022: SelectExps = {}},
adamc@1022: OrderBy = sql_order_by_Nil [_],
adamc@1022: Limit = sql_no_limit,
adamc@1022: Offset = sql_no_offset})
adamc@1022:
adamc@1009: and one id =
adamc@1012: let
adamc@1012: fun newReview r =
adamc@1012: me <- getLogin;
adamc@1012: checkPaper id;
adamc@1012: dml (insert review ({Paper = sql_inject id, User = sql_inject me.Id}
adamc@1012: ++ ensql M.review r M.reviewFolder));
adamc@1012: one id
adamc@1009:
adamc@1012: fun saveReview r =
adamc@1012: me <- getLogin;
adamc@1012: checkPaper id;
adamc@1012: dml (update [map fst M.review] ! (ensql M.review r M.reviewFolder)
adamc@1012: review (WHERE T.Paper = {[id]} AND T.User = {[me.Id]}));
adamc@1012: one id
adamc@1012: in
adamc@1012: me <- getLogin;
adamc@1012: checkPaper id;
adamc@1012: ro <- oneOrNoRows (SELECT paper.{{map fst M.paper}}, octet_length(paper.Document) AS N
adamc@1012: FROM paper
adamc@1012: WHERE paper.Id = {[id]});
adamc@1012: authors <- queryX (SELECT user.Nam
adamc@1012: FROM authorship
adamc@1012: JOIN user ON authorship.User = user.Id
adamc@1012: WHERE authorship.Paper = {[id]})
adamc@1012: (fn r =>
{[r.User.Nam]}
);
adamc@1012: myReview <- oneOrNoRows1 (SELECT review.{{map fst M.review}}
adamc@1012: FROM review
adamc@1012: WHERE review.User = {[me.Id]}
adamc@1012: AND review.Paper = {[id]});
adamc@1012: case ro of
adamc@1012: None => error Paper not found!
adamc@1012: | Some r => return
adamc@1012:
adamc@1012: else
adamc@1012: Download paper ({[r.N]} bytes)}
adamc@1011:
adamc@1012:
adamc@1011:
adamc@1012: {case myReview of
adamc@1012: None =>
adamc@1012:
Add Your Review
adamc@1012:
adamc@1012:
adamc@1012:
adamc@1012: | Some myReview =>
adamc@1012:
Edit Your Review
adamc@1012:
adamc@1012:
adamc@1012: }
adamc@1012:
adamc@1012: end
adamc@1009:
adamc@1009: and download id =
adamc@1009: checkPaper id;
adamc@1009: ro <- oneOrNoRows (SELECT paper.Document
adamc@1009: FROM paper
adamc@1009: WHERE paper.Id = {[id]});
adamc@1009: case ro of
adamc@1009: None => error Paper not found!
adamc@1009: | Some r => returnBlob r.Paper.Document (blessMime "application/pdf")
adamc@1009:
adamc@1001: end