My First Web Application Mark 5

Full code for MyFirstWebApplication, mark5.

    application org.webdsl.myfirstwebapp.mark5

    description {
      A community site about research.
    }

    section data model

      entity Publication {
        title     :: String (name)
        authors   -> List<Person> (inverse=Person.publications)
        abstract  :: Text
        published :: Date
        url       :: URL
      }

      entity Person {
        fullname     :: String (name)
        homepage     :: URL   (optional)
        email        :: Email (optional)
        address      <> Address 
        publications -> Set<Publication> 
      }

      entity Address {
        street  :: String
        city    :: String
        country :: String
        phone   :: String
      }

    section home page

      define page home() {
        main()
        define body() {
          section{
            header{"Publications"}
            list{
              for(pub : Publication) {
                listitem{ 
                  navigate(publication(pub)){text(pub.name)}
                }
              }
              listitem{navigate(createPublication()){"New Publication"}}
            }
          }
          section{
            header{"Authors"}
            list{
              for(pers: Person) {
                listitem{ output(pers) }
              }
              listitem{navigate(createPerson()){"New Person"}}
            }
          }
        }
      }

      define page publication(p : Publication) {
        main()
        define body() {
          section{
            header{output(p)}
            par{
              "by " 
              for(a : Person in p.authors) {
                output(a) " "
              }
              "at " output(p.published)}
            section{
              header{"Abstract"}
              output(p.abstract)
            }
            "Published: " output(p.url)
          }
          reviews(p)
        }
        define manageMenu() {
          navigate(editPublication(p)){"Edit"}
        }
      }

    section templates 

      define main() {
        block("top") {
          top() }
        block("body") {
          block("left_innerbody") {
            sidebar() }
          block("main_innerbody") {
            body() } }
        block("footer") {
          footer() 
        } 
      }

      define top() {
        block("header") {}
        block("menubar") { 
          applicationMenubar() } }

      define body() {}
      define manageMenu() {}
      define footer() {}
      define sidebar() { 
        navigate(home()){"Home"}
      }

      define applicationMenubar()
      {
        menubar {
          menu { 
            menuheader{ "People" }
            for(p : Person) {
              menuitem{ output(p) }
            }
          }
          menu {
            menuheader{ manageMenu() }
          }
          currentUser()
        }
      }

    section reviews

      entity Review {
        publication -> Publication (inverse=Publication.reviews)
        author      -> User
        content     :: WikiText
        created     :: Date
      }

      extend entity Publication {
        reviews -> Set<Review> 
      }

      define reviews(p : Publication) {
        showReviews(p)
         addReview(p)
      }

      define showReviews(p : Publication) {
        for(r : Review in p.reviewsList) {
          section {
            header{"Review by " output(r.author)} 
            par{" at " output(r.created)}
            output(r.content)
          }
        }
      }

      define addReview(p : Publication) {
        var text : WikiText;
        section{ 
          header{"Write a Review"}
          form {
            input(text)
            action("Submit", submitReview())
            action submitReview() {
              var review : Review := 
                Review {
                  content := text
                  author  := securityContext.principal
                  publication := p
                };
              // p.reviews.add(review);
              p.persist();
              return publication(p);
            }
          }
        }
      }

    section init

      globals {
        var eelcovisser : User := 
          User {
            username := "EelcoVisser"
            fullname := "Eelco Vissr"
            email := "E.Visser@tudelft.nl"
            homepage := "http://www.eelcovisser.net"
            password := "foo"
          };
      }

    section users

      entity User {
        username :: String (id,name)
        fullname :: String
        email    :: Email (unique)
        homepage :: URL
        password :: Secret
      }

      access control rules {
        principal is User with credentials username, password
      }

      define currentUser() {
        signinMenu()
        signoffMenu()
      }

      define page login() {
        main()
        define body() {
          signin()
          signoff()
        }
      }

      define signinMenu() {
        menu{ 
          menuheader{ navigate(login()){"Sign in"} }
        }
      }

      define signin() 
      {
        var username : String;
        var password : Secret;
        form { 
          table {
            row{ "Username: " input(username) }
            row{ "Password: " input(password) }
            row{ action("Sign in", signin()) "" }
          }
          action signin() {
            var users : List<User> :=
              select u from User as u 
              where (u._username = ~username);

            for (us : User in users ) {
              if (us.password.check(password)) {
                securityContext.principal := us;
                securityContext.loggedIn := true;
                return user(securityContext.principal);
              }
            }
            securityContext.loggedIn := false;
            return home();
          }
        }
      }

      define signoff()
      {
        "Signed in as " output(securityContext.principal)
        signoffAction()
      }

      define signoffAction() {
        form {
          actionLink("Sign Off", signoff())
          action signoff() {
            securityContext.loggedIn := false;
            securityContext.principal := null;
            // ensure that principal is null when signing off
            return home();
          }
        }
      }

      define signoffMenu() 
      {
        menu{
          menuheader{ "You" }
          menuitem{ output(securityContext.principal) }
          menuitem{ signoffAction() }
        }
      }


    section acr

      access control rules {

        rules page home() {
          true
        }

        rules page publication(p : Publication) {
          true
        }

        rules page editPublication(p : Publication) {
          securityContext.loggedIn
        }

        rules page createPublication() {
          securityContext.loggedIn
        }

        rules page person(p : Person) { true }

        rules page editPerson(p : Person) {
          securityContext.loggedIn
        }

        rules page createPerson() {
          securityContext.loggedIn
        }

        rules template addReview(p : Publication) {
          securityContext.loggedIn
        }

      }

      access control rules {

        rules page user(u : User) {
          true
        }

        rules page editUser(u : User) {
          securityContext.principal = u
        }

        rules page login() {
          true
        }

        rules template signin() {
          !securityContext.loggedIn
        }

        rules template signinMenu() {
          !securityContext.loggedIn
        }

        rules template signoff() {
          securityContext.loggedIn
        }

        rules template signoffMenu() {
          securityContext.loggedIn
        }

        rules template signoffAction() {
          securityContext.loggedIn
        }

      }
My First Web Application Mark 5