pyc-website
main website for pyc inc.
git clone https://9o.is/git/pyc-website.git
commit d3f56ba818333d2c86174dd612207a3041fe9bef parent 4cee6540db9b56a520d85b00c6405074bc348359 Author: Jul <jul@9o.is> Date: Sat, 7 Jun 2014 07:07:14 -0400 transfered ui-router to lift module (fixes issue #21) Diffstat:
| M | project/Build.scala | | | 3 | ++- |
| M | src/main/scala/bootstrap/liftweb/Boot.scala | | | 9 | ++++----- |
| M | src/main/scala/inc/pyc/config/Site.scala | | | 1 | - |
| D | src/main/scala/inc/pyc/lib/NgUIRouter.scala | | | 319 | ------------------------------------------------------------------------------- |
| D | src/main/scala/inc/pyc/snippet/AngularSnips.scala | | | 76 | ---------------------------------------------------------------------------- |
| A | src/main/scala/inc/pyc/snippet/NgAlert.scala | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
| M | src/main/scala/inc/pyc/snippet/Sitemap.scala | | | 13 | +++++++------ |
| M | src/main/scala/inc/pyc/snippet/UserSnip.scala | | | 74 | ++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
| M | src/main/scala/inc/pyc/snippet/UtilSnips.scala | | | 27 | ++++++++++++--------------- |
9 files changed, 109 insertions(+), 455 deletions(-)
diff --git a/project/Build.scala b/project/Build.scala @@ -18,7 +18,8 @@ object LiftProjectBuild extends Build { "ch.qos.logback" % "logback-classic" % "1.0.13" % "compile", "org.scalatest" %% "scalatest" % "1.9.2" % "test", "com.foursquare" %% "rogue-lift_3.0" % "2.3.0-SNAPSHOT", - "inc.pyc" %% "aws-s3" % "0.1" + "inc.pyc" %% "aws-s3" % "0.1", + "net.liftmodules" %% ("uirouter_"+Ver.lift_edition) % "0.1-SNAPSHOT" ) ) } diff --git a/src/main/scala/bootstrap/liftweb/Boot.scala b/src/main/scala/bootstrap/liftweb/Boot.scala @@ -12,10 +12,10 @@ import util.Helpers._ import inc.pyc.config._ import inc.pyc.lib._ import inc.pyc.model.{SystemUser, User} -import inc.pyc.lib.NgUIRouterFactory import net.liftmodules.extras.{Gravatar, LiftExtras} import net.liftmodules.mongoauth.MongoAuth +import net.liftmodules.uirouter._ /** * A class that's instantiated early and run. It allows the application @@ -71,10 +71,9 @@ class Boot extends Loggable { // don't include the liftAjax.js code. It's served statically. LiftRules.autoIncludeAjaxCalc.default.set(() => (session: LiftSession) => false) - // don't include cometajax.js. served by ui-router module - LiftRules.autoIncludeComet = ((session: LiftSession) => false) - - LiftRules.maxConcurrentRequests.default.set((request: Req) => 50) + // Initialize required settings for UiRouter + UiRouter.init + UiRouter.pageTitle.default.set(setTitle(pageName => "PYC: " + pageName)) // Mailer Mailer.devModeSend.default.set((m: MimeMessage) => logger.info("Dev mode message:\n" + prettyPrintMime(m))) diff --git a/src/main/scala/inc/pyc/config/Site.scala b/src/main/scala/inc/pyc/config/Site.scala @@ -1,7 +1,6 @@ package inc.pyc package config -import lib.NgUIRouterFactory._ import model.User import model.EmailResetToken._ diff --git a/src/main/scala/inc/pyc/lib/NgUIRouter.scala b/src/main/scala/inc/pyc/lib/NgUIRouter.scala @@ -1,318 +0,0 @@ -package inc.pyc -package lib - -import scala.xml._ -import net.liftweb._ -import sitemap._ -import common._ -import http._ -import js._ -import sitemap.Loc.{LocGroup, AnyLocParam} -import util._ -import Helpers._ -import net.liftmodules.extras.SnippetHelper - -/** - * Configure these settings during boot. - */ -object NgUIRouterFactory extends Factory { - - /** - * Ignore the UiRouter Loc Group and add all menus in sitemap. - */ - val html5mode = new FactoryMaker[Boolean](true) {} - - /** - * Ignore the UiRouter Loc Group and add all menus in sitemap. - */ - val ignoreUiRouterGroup = new FactoryMaker[Boolean](true) {} - - /** - * Default route when page lands on index. - */ - val defaultRoute = new FactoryMaker[Box[Menu]](Empty) {} - - /** - * List of all the routes. - */ - lazy val routes = new FactoryMaker[Seq[Menu]](findRoutes) {} - - /** - * Place this LocGroup on any Menu Items in Lift's SiteMap - * that will have a state in AngularJs UI-Router. - */ - val UiRouterGroup = LocGroup("uirouter") - - /* Finds menu items that are in UiRouterGroup group. */ - private def findRoutes = LiftRules.siteMap map { - siteMap => - if(ignoreUiRouterGroup.vend) - siteMap.menus - else - siteMap.menus.filter(_.loc.inGroup_?(UiRouterGroup.group.head)) - } openOr Nil -} - -trait NgUIRouterSnip extends SnippetHelper { - - /** - * Snippet to configures AngularJs module with all routes. - * - * Required attributes: - * - ngApp: Name of AngularJs module. - */ - def js: CssSel = - for{ - app <- S.attr("ngApp") ?~ "ngApp name is missing" - } yield "* *" #> { - import NgUIRouterFactory._ - - // the default route - val otherwise = - defaultRoute.vend map { - "$urlRouterProvider.otherwise('"+S.contextPath+_.loc.calcDefaultHref+"');" - } openOr "" - - // ng ui-router config - val config = - """ - .config(function($stateProvider, $urlRouterProvider,$locationProvider) { - $locationProvider.html5Mode("""+html5mode.vend.toString+"""); - """+otherwise+""" - $stateProvider"""+{ - routes.vend.map { menu => - val templateUrl = S.contextPath+menu.loc.calcDefaultHref - val state: String = menu.loc.name.replaceAll(" ","_") - - ".state('"+state+"', {"+ - "url:'"+templateUrl+"',"+ - "views: {'viewA': {"+ - "templateUrl:'"+templateUrl+".html?ajax'"+ - "}}"+ - "})" - }.mkString - }+""" - ;}) - """ - - def init = "var statesVisited = []; var lift_toWatch = {};" - - // updates lift_toWatch js variable - val updateLiftWatch = - """var el = angular.element(document.querySelectorAll(".lift-roundtrip"));"""+ - """for (var i=0;i<el.length;++i) { window.lift_toWatch[el[i].getAttribute("id")] = el[i].getAttribute("when") };""" - - // evaluates the javascript that was placed in the ajax-uploaded html page - val evalRenderedJS = - """var promises = angular.element(document.querySelectorAll(".lift-promise"));"""+ - """for (var i=0;i<promises.length;++i) { eval(promises[i].innerHTML) };""" - - val liftCometStart = """window.liftComet.lift_cometRestart();""" - - /** Changes document title on state change. */ - val changeTitle = "document.title = 'PYC: ' + toState.name.replace(/_/g, ' ');" - - /** - * Run commands when UI-Router's $viewContentLoaded event is fired. - */ - def onViewContentLoaded(cmds: String*): String = - """.run(['$rootScope', '$state', function($rootScope, $state) {$rootScope.$on('$viewContentLoaded', function() {"""+ - cmds.mkString+"""}); }])""" - - /** - * Run commands when UI-Router's $stateChangeSuccess event is fired. - */ - def onStateChangeSuccess(cmds: String*): String = - """.run(['$rootScope', function($rootScope) {$rootScope.$on('$stateChangeSuccess', function(e, toState) {"""+ - cmds.mkString+"""}); }])""" - - def ifStateNotVisited(cmds: String*): String = """ - var visited = false; - angular.forEach(statesVisited, function(state){ - if(state === $state.current.name) {visited = true;} - }); - if(!visited){ - statesVisited.push($state.current.name); - """+cmds.mkString+""" - } - """ - - def func(body: String): String = "(function() {"+body+"});" - - s"""// <![CDATA[ - ${init + app + config + - onViewContentLoaded(ifStateNotVisited(updateLiftWatch, evalRenderedJS, liftCometStart)) + - onStateChangeSuccess(changeTitle)}; - $cometScript - //]]>""" - } - - /** - * Renders the default JS comet script - */ - private def cometScript: String = """ - (function() { - var currentCometRequest = null; - window.liftComet = { - lift_handlerSuccessFunc: function() { - setTimeout("liftComet.lift_cometEntry();",100); - }, - - lift_unlistWatch : function(watchId) { - var ret = []; - for (item in lift_toWatch) { - if (item !== watchId) { - ret.push(item); - } - } - lift_toWatch = ret; - }, - - lift_handlerFailureFunc: function() { - setTimeout("liftComet.lift_cometEntry();",""" + LiftRules.cometFailureRetryTimeout + """); - }, - - - lift_cometError: function(e) { - if (console && typeof console.error == 'function') - console.error(e.stack || e); - throw e; - }, - - lift_sessionLost: function() { window.location = '/' }, - - lift_cometRestart: function() { - if (currentCometRequest) { - currentCometRequest.abort(); - } - - liftComet.lift_handlerSuccessFunc(); - }, - - lift_cometEntry: function() { - var isEmpty = function(){for (var i in lift_toWatch) {return false} return true}(); - if (!isEmpty) { - liftAjax.lift_uriSuffix = undefined; - currentCometRequest = """ + - LiftRules.jsArtifacts.comet(AjaxInfo(JE.JsRaw("lift_toWatch"), - "GET", - LiftRules.cometGetTimeout, - false, - "script", - Full("liftComet.lift_handlerSuccessFunc"), - Full("liftComet.lift_handlerFailureFunc"))) + - """ - } - } - - }})(); - """ - - - /** - * Conditional Template Surround Snippet. Allows pages to be surrounded by a - * different template if it's accessed with ajax. - * - * Needed attributes are: - * - with: template name to surround page. - * - at: id of element in template to place the page. - * - withAjax: template name to surround page when accessed with ajax. - * - * When accessing with ajax, assure URL query parameter 'ajax' exists. - * - * NOTE: default.html in templates-hidden cannot exist - * (else Lift will auto-surround everything with default) - */ - def surround(ns: NodeSeq): NodeSeq = - for { - surroundWith <- S.attr("with") ?~ "Surround with not specified" - surroundWithAjax <- S.attr("withAjax") ?~ "Surround with ajax not specified" - at <- S.attr("at") ?~ "Surround at not specified" - } yield { - if(S.param("ajax").isDefined) - Templates("templates-hidden" :: surroundWithAjax :: Nil) map { - s"#$at" #> ns - } openOr Text("Template '"+surroundWithAjax+"' not found") - else - Templates("templates-hidden" :: surroundWith :: Nil) map { - s"#$at" #> ns - } openOr Text("Template '"+surroundWith+"' not found") - } -} - -/** - * Menu Group snippet. List of links grouped with LocGroup will - * have ui-sref attribute. If link points to /some/foo/bar, - * then ui-router state or ui-sref value will be some.foo.bar. - * - * Example snippet: data-lift="NgUIRouterMenu.group?group=topbar" - */ -trait NgUIRouterMenu extends SnippetHelper { - - private def buildUIRouterLink(name: String): NodeSeq = { - val options = for { - loc <- SiteMap.findAndTestLoc(name).toList - link <- loc.createDefaultLink - } yield { - - def uiSref(el: Elem): Elem = { - import NgUIRouterFactory._ - if(loc.inGroup_?(UiRouterGroup.group.head)) - el % ("ui-sref" -> loc.name.replaceAll(" ","_")) - else - el - } - - val linkText = loc.linkText openOr Text(loc.name) - uiSref(<a href={link}>{linkText}</a>) - - } - options.headOption getOrElse NodeSeq.Empty - } - - def item: CssSel = { - val options = (for { - name: String <- S.attr("name") ?~ "Item name not specified" - } yield for { - loc <- SiteMap.findAndTestLoc(name) - link <- loc.createDefaultLink - } yield { - "* [ui-sref]" #> loc.name.replaceAll(" ","_") & - "* [href]" #> link - }) openOr Empty - options - } - - /** - * Produces a menu UL from a group, for use with Bootstrap. - */ - def group = { - val menus: NodeSeq = - for { - group <- S.attr("group") ?~ "Group not specified" - sitemap <- LiftRules.siteMap ?~ "Sitemap is empty" - request <- S.request ?~ "Request is empty" - curLoc <- request.location ?~ "Current location is empty" - } yield ({ - sitemap.locForGroup(group) flatMap { loc => - val nonHiddenKids = loc.menu.kids.filterNot(_.loc.hidden) - - if (nonHiddenKids.length == 0) { - <li>{buildUIRouterLink(loc.name)}</li> - } - else { - val dropdown: NodeSeq = nonHiddenKids.map { kid => - <li>{buildUIRouterLink(kid.loc.name)}</li> - } - - <li class="dropdown"> - <a href="#" class="dropdown-toggle" data-toggle="dropdown">{loc.linkText.openOr(Text("Empty Name"))} <b class="caret"></b></a> - <ul class="dropdown-menu">{ dropdown }</ul> - </li> - } - } - }): NodeSeq - - "* *" #> menus - } -} -\ No newline at end of file diff --git a/src/main/scala/inc/pyc/snippet/AngularSnips.scala b/src/main/scala/inc/pyc/snippet/AngularSnips.scala @@ -1,75 +0,0 @@ -package inc.pyc -package snippet - -import xml._ -import net.liftweb._ -import util._ -import Helpers._ -import common._ -import json.JsonAST._ -import http._ -import js._ -import JsCmds._ -import JE.JsVar -import net.liftmodules.extras.SnippetHelper - -/** - * Snippet classes with AngularJs server-side code need to extend this. - * Javascript promism - */ -trait AngularSnippet extends SnippetHelper with Logger { - - def roundTrips: List[RoundTripInfo] - - def render: CssSel = - for (sess <- S.session) yield { - val roundtrips = sess.buildRoundtrip(roundTrips) - - val lastcomet = S.cometAtEnd.last - val whenregex = "<div.*lift:when=\"([0-9]*)\".*/>".r - - val when: String = lastcomet.toString match { - case whenregex(when) => when - case _ => "" - } - - val className: String = this.getClass.getName.split("""\.""").last - - "* *+" #> <script class="lift-promise">{SetExp(JsVar("window", className), roundtrips).toJsCmd}</script> & - "* *+" #> <div class="lift-roundtrips">{(lastcomet % ("class" -> "lift-roundtrip") % ("when" -> when))}</div> - } -} - -/** - * Builds Alert JSON messages for server-side responses. - */ -object NgAlert extends Logger { - - private def msgBox(msgType: String, msg: NodeSeq): JValue = - JObject(List( - JField("msg_type", JString(msgType)), - JField("msg", JString(msg.toString)))) - - def success(msg: NodeSeq): JValue = msgBox("success", msg) - def success(msg: String): JValue = success(Text(msg)) - def success: JValue = success(Text("")) - - def danger(msg: NodeSeq, errors: List[FieldError]): JValue = { - debug(errors) - - msgBox("danger", msg ++ - errors.foldLeft(<ul></ul>)((el,err) => el.copy(child = el.child :+ <li>{err.msg}</li>))) - } - - def danger(msg: String, errors: List[FieldError] = Nil): JValue = danger(Text(msg), errors) - def danger: JValue = danger(Text(""), Nil) - - def info(msg: NodeSeq): JValue = msgBox("info", msg) - def info(msg: String): JValue = info(Text(msg)) - def info: JValue = info(Text("")) - - def warning(msg: NodeSeq): JValue = msgBox("warning", msg) - def warning(msg: String): JValue = warning(Text(msg)) - def warning: JValue = warning(Text("")) - -} -\ No newline at end of file diff --git a/src/main/scala/inc/pyc/snippet/NgAlert.scala b/src/main/scala/inc/pyc/snippet/NgAlert.scala @@ -0,0 +1,41 @@ +package inc.pyc +package snippet + +import xml._ +import net.liftweb._ +import util._ +import common._ +import json.JsonAST._ + +/** + * Builds Alert JSON messages for server-side responses. + */ +object NgAlert extends Logger { + + private def msgBox(msgType: String, msg: NodeSeq): JValue = + JObject(List( + JField("msg_type", JString(msgType)), + JField("msg", JString(msg.toString)))) + + def success(msg: NodeSeq): JValue = msgBox("success", msg) + def success(msg: String): JValue = success(Text(msg)) + def success: JValue = success(Text("")) + + def danger(msg: NodeSeq, errors: List[FieldError]): JValue = { + debug(errors) + + msgBox("danger", msg ++ + errors.foldLeft(<ul></ul>)((el,err) => el.copy(child = el.child :+ <li>{err.msg}</li>))) + } + + def danger(msg: String, errors: List[FieldError] = Nil): JValue = danger(Text(msg), errors) + def danger: JValue = danger(Text(""), Nil) + + def info(msg: NodeSeq): JValue = msgBox("info", msg) + def info(msg: String): JValue = info(Text(msg)) + def info: JValue = info(Text("")) + + def warning(msg: NodeSeq): JValue = msgBox("warning", msg) + def warning(msg: String): JValue = warning(Text(msg)) + def warning: JValue = warning(Text("")) +} +\ No newline at end of file diff --git a/src/main/scala/inc/pyc/snippet/Sitemap.scala b/src/main/scala/inc/pyc/snippet/Sitemap.scala @@ -2,9 +2,6 @@ package inc.pyc package snippet import config._ -import lib._ - -import org.joda.time.DateTime import net.liftweb._ import http._ import rest.RestHelper @@ -12,6 +9,9 @@ import util._ import Helpers._ import common._ +import net.liftmodules.uirouter.UiRouter._ +import org.joda.time.DateTime + object Sitemap extends RestHelper { serve { case Req("sitemap" :: Nil, _, GetRequest) => @@ -25,9 +25,10 @@ class SitemapContent { case class Post(url: String, date: DateTime) - lazy val baseEntry = NgUIRouterFactory.defaultRoute.vend map { - _.loc.calcDefaultHref - } openOr "" + lazy val baseEntry = + defaultRoute.vend map { + _.loc.calcDefaultHref + } openOr "" lazy val entries = LiftRules.siteMap map { diff --git a/src/main/scala/inc/pyc/snippet/UserSnip.scala b/src/main/scala/inc/pyc/snippet/UserSnip.scala @@ -23,18 +23,18 @@ sealed trait UserSnippet extends SnippetHelper with Logger { protected def user: Box[User] - protected def serveNodeseq(snip: User => NodeSeq): NodeSeq = + protected def serve(snip: User => NodeSeq): NodeSeq = (for { u <- user ?~ "User not found" } yield { snip(u) }): NodeSeq - def username(in: NodeSeq): NodeSeq = serveNodeseq { user => + def username(in: NodeSeq): NodeSeq = serve { user => Text(user.username.get) } - def name(in: NodeSeq): NodeSeq = serveNodeseq { user => + def name(in: NodeSeq): NodeSeq = serve { user => val name = user.fname.get + " " + user.lname.get if (name.length > 1) Text(name) else Text(user.username.get) @@ -51,9 +51,11 @@ trait CurrentUser extends UserSnippet { object CurrentUser extends CurrentUser /** - * Angular snippet when logged in. + * Angular snippet for accessing user information. */ -trait AngularUserSnippet extends AngularSnippet with CurrentUser { +trait AngularUserSnippet extends AngularSnippet { + + protected def user: Box[User] protected def serve(snip: User => JValue): JValue = (for { @@ -90,6 +92,13 @@ trait AngularUserSnippet extends AngularSnippet with CurrentUser { } } +/** + * Angular snippet for accessing logged in user information. + */ +trait AngularCurrentUser extends AngularUserSnippet { + protected def user = User.currentUser +} + class UserLogin extends AngularSnippet { def roundTrips: List[RoundTripInfo] = List("submit" -> submit _) @@ -125,7 +134,7 @@ class UserLogin extends AngularSnippet { } } -class PasswordChange extends AngularUserSnippet { +class PasswordChange extends AngularCurrentUser { /** * Passwords must match this pattern. @@ -228,7 +237,7 @@ class UserRegistration extends AngularSnippet { } } -class UserSettings extends AngularUserSnippet { +class UserSettings extends AngularCurrentUser { def roundTrips: List[RoundTripInfo] = List( "init" -> init _, @@ -248,7 +257,6 @@ class UserSettings extends AngularUserSnippet { for { JString(fname) <- model } yield { - info(fname) user.fname(fname) validateAndUpdate() } @@ -275,7 +283,7 @@ class UserSettings extends AngularUserSnippet { } } -class UserSettingsEmail extends AngularUserSnippet { +class UserSettingsEmail extends AngularCurrentUser { def roundTrips: List[RoundTripInfo] = List( "submit" -> submit _, @@ -302,7 +310,29 @@ class UserSettingsEmail extends AngularUserSnippet { } } -class IdVerification extends AngularUserSnippet { +object IdVerification extends CurrentUser { + def is3rdPartyVerified(ns: NodeSeq): NodeSeq = serve { + user => + if(user.is3rdPartyVerified) ns else NodeSeq.Empty + } + + def waiting3rdPartyVerification(ns: NodeSeq): NodeSeq = serve { + user => + if(user.waiting3rdPartyVerification && + !user.is3rdPartyVerified) ns + else NodeSeq.Empty + } + + def isPycVerified(ns: NodeSeq): NodeSeq = serve { + user => + if(user.isPycVerified && + !user.waiting3rdPartyVerification && + !user.is3rdPartyVerified) ns + else NodeSeq.Empty + } +} + +class IdVerification extends AngularCurrentUser { def roundTrips: List[RoundTripInfo] = List( "submit" -> submit _, @@ -344,7 +374,7 @@ class IdVerification extends AngularUserSnippet { IdVerificationFiles(Nil) if(statusCodes.forall(_ == 200)) { - user.idVerification(IdVerification.PYC_Pending) + user.idVerification(field.IdVerification.PYC_Pending) user.update notifyIdentityRequest(user) NgAlert.success( @@ -360,29 +390,9 @@ class IdVerification extends AngularUserSnippet { } } - def is3rdPartyVerified(ns: NodeSeq): NodeSeq = serveNodeseq { - user => - if(user.is3rdPartyVerified) ns else NodeSeq.Empty - } - - def waiting3rdPartyVerification(ns: NodeSeq): NodeSeq = serveNodeseq { - user => - if(user.waiting3rdPartyVerification && - !user.is3rdPartyVerified) ns - else NodeSeq.Empty - } - - def isPycVerified(ns: NodeSeq): NodeSeq = serveNodeseq { - user => - if(user.isPycVerified && - !user.waiting3rdPartyVerification && - !user.is3rdPartyVerified) ns - else NodeSeq.Empty - } - def thirdPartyVerify(model: JValue): JValue = serve { user => - user.idVerification(IdVerification.Third_Party_Request) + user.idVerification(field.IdVerification.Third_Party_Request) user.update IdVerificationHelper.notifyIdentityRequest(user, thirdParty = true) diff --git a/src/main/scala/inc/pyc/snippet/UtilSnips.scala b/src/main/scala/inc/pyc/snippet/UtilSnips.scala @@ -1,30 +1,27 @@ package inc.pyc package snippet -import lib._ import model.field._ -import scala.xml.NodeSeq +import xml._ import net.liftweb._ import common._ import util._ import Helpers._ -import http._ -import js._ -import net.liftmodules.extras._, snippet._ -import net.liftweb.json.JsonAST.{JNull, JValue} - -/* - * Base all LiftScreens off this. Currently configured to use bootstrap 3. - */ -abstract class BaseScreen extends Bootstrap3Screen { - override def defaultToAjax_? = true -} +import json.JsonAST._ +import net.liftmodules._ +import extras._, snippet._ +import uirouter.snippet._ object Assets extends AssetLoader -object NgUIRouter extends NgUIRouterSnip +trait AngularSnippet extends UiRoundTrip { + implicit def boxedJValueToJValue(in: Box[JValue]): JValue = in openOr JNull + implicit def listJValueToJValue(in: List[JValue]): JValue = in.headOption.getOrElse(JNull) +} + +object NgUIRouter extends UiRouter -object Menus extends NgUIRouterMenu +object Menus extends UiMenu object ProductionOnly { def render(in: NodeSeq): NodeSeq =