User UI
authorTomas Zeman <tzeman@volny.cz>
Fri, 20 Apr 2012 08:26:22 +0200
changeset 60 e2a2e2045c0e
parent 59 9e35765f4669
child 61 b65843860274
User UI
src/main/scala/bootstrap/liftweb/Boot.scala
src/main/scala/fis/aaa/model/User.scala
src/main/scala/fis/aaa/ui/UserPanel.scala
src/main/scala/fis/aaa/ui/UserSnippet.scala
src/main/scala/fis/aaa/ui/UserTable.scala
--- a/src/main/scala/bootstrap/liftweb/Boot.scala	Fri Apr 20 08:26:06 2012 +0200
+++ b/src/main/scala/bootstrap/liftweb/Boot.scala	Fri Apr 20 08:26:22 2012 +0200
@@ -17,6 +17,7 @@
 
 import fis.base.model._
 import fis.base.ui._
+import fis.aaa.ui.UserSnippet
 import fis.crm.ui.ContactSnippet
 import fis.db.SquerylTxMgr
 import net.liftweb.common._
@@ -40,7 +41,8 @@
     SecNav.init()
 
     val menus = List(Menu("/", "FIS Main page") / "index" >> Hidden,
-      Menu.i("Home") / "" , ContactSnippet.menu)
+      Menu.i("Home") / "" , ContactSnippet.menu,
+      UserSnippet.menu)
 
     LiftRules.setSiteMap(SiteMap(menus:_*))
 
--- a/src/main/scala/fis/aaa/model/User.scala	Fri Apr 20 08:26:06 2012 +0200
+++ b/src/main/scala/fis/aaa/model/User.scala	Fri Apr 20 08:26:22 2012 +0200
@@ -30,7 +30,7 @@
   def meta = User
 
   val login = new StringField(this, 40) with FL
-  val password = new PasswordField(this) with FL
+  val password = new StringField(this, 128) with FL
   val active = new BooleanField(this) with FL {
     override def defaultValue = true
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/fis/aaa/ui/UserPanel.scala	Fri Apr 20 08:26:22 2012 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011-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.aaa.ui
+
+import fis.aaa.model._
+import fis.base.ui.ViewPanel
+import net.liftweb.util.BaseField
+
+object UserPanel {
+
+  def fields(u: User): List[BaseField] = List(u.name, u.login, u.active, u.note)
+
+  def apply(u: User) = ViewPanel(fields(u))
+}
+
+// vim: set ts=2 sw=2 et:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/fis/aaa/ui/UserSnippet.scala	Fri Apr 20 08:26:22 2012 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2011-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.aaa.ui
+
+import fis.base.ui._
+import fis.aaa.model._
+import net.liftweb.common._
+import net.liftweb.http._
+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 UserSnippet extends UserCrud with EntitySnippet[User] {
+  val prefix = "user"
+
+  private val listPre = Menu("user.list", l10n("Users")) / prefix >>
+    Title(_ => i18n("Users")) >>
+    locTpl("entity/list") >> Snippet("list", list)
+
+  private val createPre = Menu("user.create", l10n("Create")) / prefix / ADD >>
+    Title(_ => i18n("Create user")) >>
+    locTpl("entity/form") >> Snippet("form", form) >> Hidden
+
+  private val viewPre = Menu.param[User]("user.view", l10n("User"), parse,
+    encode) / prefix / * >> Title(c => i18n("User %s", c.linkName)) >>
+    locTpl("entity/view") >> Snippet("panel", panel) >> Hidden
+
+  private val editPre = Menu.param[User]("user.edit", l10n("Edit"), parse,
+    encode) / prefix / * / EDIT >>
+    Title(c => i18n("Edit user %s", c.linkName)) >>
+    locTpl("entity/form") >> Snippet("form", form) >> Hidden
+
+  private val deletePre = Menu.param[User]("user.delete", l10n("Delete"),
+    parse, encode) / prefix / * / DELETE >>
+    Title(c => i18n("Delete user %s", c.linkName)) >>
+    locTpl("entity/delete") >> Snippet("form", deleteF) >> Hidden
+
+  private val listM = listPre >> SecNav(createPre).build
+  private val createM = createPre >> SecNav(listPre).build
+  private val viewM = viewPre >> (SecNav(editPre) + deletePre).build
+  private val editM = editPre >> SecNav(viewPre).build
+  private val deleteM = deletePre >> 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)
+
+  private def cur = viewLoc.currentValue or editLoc.currentValue or
+    deleteLoc.currentValue
+
+  private def list: CssTr = { _ => UserTable(AaaSchema.usersF()) }
+
+  private def panel: CssTr = "*" #> cur.map(UserPanel(_))
+
+  object url {
+    def view: User => Box[String] = (viewLoc.calcHref _) andThen (Box !! _)
+  }
+
+  private case class UserLink(u: User) extends EntityLink[User](u, url.view) {
+    override def displayName = l10n("user.name")
+  }
+
+  EntityLink.register[User](UserLink(_))
+
+  private object form extends HorizontalScreen with CancelButton with SaveButton {
+
+    private object user extends ScreenVar[User](User.createRecord)
+
+    val pass1 = password(User.password.displayName, User.password.defaultValue)
+    val pass2 = password(l10n("user.password.repeat"),
+      User.password.defaultValue)
+
+    private def validatePass: List[FieldError] = (pass1.get != pass2.get).box {
+      FieldError(pass2, i18n("Passwords do not match.")) } toList
+
+    private def roText(f: BaseField) = new Field {
+      type ValueType = String 
+      def default = ""
+      override def name = f.name
+      override def displayName = f.displayName
+      override def toForm = Full(<span class="uneditable-input">{f.asHtml}</span>)
+      override implicit def manifest = buildIt[String] 
+    }
+
+    private def fields(u: User): List[FieldContainer] = {
+      val n_l = List(u.name, u.login)
+      val n_l_f = (u.id != u.idField.defaultValue).box(n_l map { roText _ }).
+        openOr(n_l)
+
+      n_l_f ++ List[FieldContainer](pass1, pass2, u.active, u.note)
+    }
+
+    override def screenFields: List[BaseField] =
+      fields(user) flatMap(_.allFields)
+
+    override def validations = validatePass _ :: super.validations
+
+    override def localSetup() {
+      cur.foreach(user(_))
+    }
+
+    def finish() {
+      (pass1.get.length > 0).box(user.password(md5(pass1.get)))
+      save(user) foreach { v =>
+        S notice l10n("User %s saved", v.linkName)
+        S.redirectTo(viewLoc.calcHref(v))
+      }
+    }
+  }
+
+  private object deleteF extends HorizontalScreen with CancelButton with
+    DeleteButton {
+
+    val confirm = field(l10n("Really delete this user?"), false)
+
+    def finish() {
+      for {
+        u <- cur if confirm
+        r <- save(u.deleted(true))
+      } {
+        S notice l10n("User %s deleted", r.linkName)
+        S redirectTo listM.loc.calcDefaultHref
+      }
+    }
+  }
+
+}
+
+// vim: set ts=2 sw=2 et:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/fis/aaa/ui/UserTable.scala	Fri Apr 20 08:26:22 2012 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2011-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.aaa.ui
+
+import fis.aaa.model._
+import fis.base.ui._
+import net.liftweb.common._
+import net.tz.lift.model._
+
+object UserTable extends FieldTable[User] {
+  def fields(u: User) = EntityLink(u) ++ Seq(u.login, u.active, u.note)
+
+  def apply(l: Iterable[User]) = build(User, l) 
+}
+
+
+// vim: set ts=2 sw=2 et: