src/main/scala/fis/pm/ui/ProjectSnippet.scala
author Tomas Zeman <tzeman@volny.cz>
Tue, 01 May 2012 23:27:55 +0200
changeset 89 fd364bae9c49
parent 87 80b87b8de739
child 98 eac38214183d
permissions -rw-r--r--
Basic authorization: only logged in user can change entities

/*
 * Copyright 2012 Tomas Zeman <tzeman@volny.cz>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package fis.pm.ui

import fis.aaa.ui.IfLoggedIn
import fis.base.ui._
import fis.crm.model._
import fis.pm.model._
import net.liftweb.common._
import net.liftweb.http._
import net.liftweb.record.field._
import net.liftweb.sitemap._
import net.liftweb.sitemap.Loc._
import net.liftweb.util._
import net.liftweb.util.Helpers._
import net.tz.lift.model._
import net.tz.lift.snippet._
import scala.xml.{Elem, NodeSeq, Text}

object ProjectSnippet extends ProjectCrud with EntitySnippet[Project] {
  val prefix = "project"

  private val listPre = Menu("project.list", l10n("Projects")) / prefix >>
    Title(_ => i18n("Projects")) >>
    locTpl("entity/list") >> Snippet("list", list)

  private val createPre = Menu("project.create", l10n("Create")) / prefix / ADD >>
    Title(_ => i18n("Create project")) >> IfLoggedIn.test >>
    locTpl("entity/form") >> Snippet("form", form) >> Hidden

  private val viewPre = Menu.param[Project]("project.view", l10n("Project"), parse,
    encode) / prefix / * >> Title(p => i18n("Project %s", p.linkName)) >>
    locTpl("project/view") >> Snippet("panel", panel) >>
    Snippet("tasks", tasks) >> Hidden

  private val editPre = Menu.param[Project]("project.edit", l10n("Edit"), parse,
    encode) / prefix / * / EDIT >>
    Title(p => i18n("Edit project %s", p.linkName)) >> IfLoggedIn.testVal >>
    locTpl("entity/form") >> Snippet("form", form) >> Hidden

  private val deletePre = Menu.param[Project]("project.delete", l10n("Delete"),
    parse, encode) / prefix / * / DELETE >>
    Title(p => i18n("Delete project %s", p.linkName)) >> IfLoggedIn.testVal >>
    locTpl("entity/delete") >> Snippet("form", deleteF) >> Hidden

  private val createTaskPre = Menu.param[Project]("project.create-task",
    l10n("Create task"), parse, encode) / prefix / * / "create-task" >>
    Title(p => i18n("Create task for project %s", p.linkName)) >>
    IfLoggedIn.testVal >>
    locTpl("entity/form") >> Snippet("form", taskF) >> Hidden

  private val listM = listPre >> SecNav(createPre).build
  private val createM = createPre >> SecNav(listPre).build
  private val viewM = viewPre >> (SecNav(editPre) + deletePre +
    createTaskPre).build
  private val editM = editPre >> SecNav(viewPre).build
  private val deleteM = deletePre >> SecNav(viewPre).build
  private val createTaskM = createTaskPre >> SecNav(viewPre).build

  private lazy val viewLoc = viewM.toLoc
  private lazy val editLoc = editM.toLoc
  private lazy val deleteLoc = deleteM.toLoc

  val menu = listM submenus(viewM, editM, createM, deleteM, createTaskM)

  private def cur = viewLoc.currentValue or editLoc.currentValue or
    deleteLoc.currentValue

  private def list: CssTr = { _ => ProjectTable(PmSchema.projects) }

  private def panel: CssTr = "*" #> cur.map { p => ViewPanel(fields(p)) }

  private def tasks: CssTr = "*" #> cur.map { p => TaskTable(ProjectTasks(p)) }

  object url {
    def view: Project => Box[String] = (viewLoc.calcHref _) andThen (Box !! _)
    def list: String = listM.loc.calcDefaultHref
  }

  private def fields(p: Project) = List(p.name, p.identS, p.stateFld,
    p.createdBy, p.createdAt, p.deadline, p.responsible, p.productLine,
    ProjectCompanyField(p), p.description, p.note)

  private case class ProjectLink(c: Project) extends EntityLink[Project](c, url.view)

  EntityLink.register[Project](ProjectLink(_))

  private case class ProjectCompanyField(p: Project) extends OptionalLongField(p)
    with CompanyField with FieldLabel {
    override def name = "company"
    override def defaultValueBox =
      PmSchema.projectCompany.left(p).headOption.map(_.id)
  }

  private object form extends HorizontalScreen with CancelButton with
    SaveButton {

    private object project extends ScreenVar[Project](Project.createRecord)
    private object company extends ScreenVar[CompanyField](
      ProjectCompanyField(project))

    private def formFields(p: Project) = {
      List(p.name, p.identS, p.stateFld, p.deadline, p.responsible,
        p.productLine, company.get, p.description, p.note)
    }

    override def screenFields: List[BaseField] = formFields(project)

    override def localSetup() {
      cur.foreach { p => project(p); company(ProjectCompanyField(p)) }
    }

    def finish() {
      save(project) foreach { p =>
        val fk = PmSchema.projectCompany.left(p)
        company.vend match {
          case Full(c) if fk.exists(_.id == c.id) => // empty, no update
          case Full(c) =>
            fk.dissociateAll
            fk.associate(c)
          case _ => fk.dissociateAll
        }
        S notice l10n("Project %s saved.", p.linkName)
        S.redirectTo(viewLoc.calcHref(p))
      }
    }
  }

  private object deleteF extends HorizontalScreen with CancelButton with
    DeleteButton {

    val confirm = field(l10n("Really delete this project?"), false)

    def finish() {
      for {
        c <- deleteLoc.currentValue if confirm
        r <- delete(c)
        n <- r.box(c.linkName)
      } {
        S notice l10n("Project %s deleted.", n)
        S redirectTo listM.loc.calcDefaultHref
      }
    }
  }

  private object taskF extends TaskForm {

    override def localSetup() {
      createTaskM.currentValue.foreach { p => task.project(p.id) }
    }

    protected def onSuccess(t: Task) {
      TaskSnippet.url.view(t).foreach { u => S redirectTo u }
    }
  }

}

// vim: set ts=2 sw=2 et: