# HG changeset patch # User Tomas Zeman # Date 1322668750 -3600 # Node ID 6b1a7f3429cadc9369df22450602d9c1bd42c84e # Parent 0f6859991f554692815a2559225bcf808acd6079 ca1737768512bd36 Search by dynamic IP address, IP assignment history list diff -r 0f6859991f55 -r 6b1a7f3429ca src/main/scala/bootstrap/liftweb/Boot.scala --- a/src/main/scala/bootstrap/liftweb/Boot.scala Thu Apr 14 15:42:46 2011 +0200 +++ b/src/main/scala/bootstrap/liftweb/Boot.scala Wed Nov 30 16:59:10 2011 +0100 @@ -17,11 +17,14 @@ import net.liftweb.common._ import net.liftweb.http._ +import net.liftweb.http.js.JsObj +import net.liftweb.http.js.JE.JsObj import net.liftweb.mapper._ import net.liftweb.sitemap._ import net.liftweb.sitemap.Loc._ +import net.liftweb.widgets.menu.MenuStyle +import net.liftweb.widgets.menu.{MenuWidget => LiftMenuWidget} import net.liftweb.util._ -import net.liftweb.widgets.menu.MenuWidget import net.tz.lift.snippet.ActionLinks import net.tz.lift.util.YmdDateTimeConverter import radview.model._ @@ -57,7 +60,9 @@ LiftRules.snippetDispatch.append { case "Menubar" => new AnyRef with DispatchSnippet { def dispatch: DispatchIt = { - case _ => { xhtml => MenuWidget() } + case _ => { xhtml => + new MenuWidget(MenuStyle.HORIZONTAL, JsObj(), Nil) render + } } } case "action-links" => ActionLinks @@ -72,11 +77,12 @@ Menu.i("Cells") / "cell", Menu(SessionSnippet), Menu(AccountSnippet), - Menu.i("Accounts") / "account" + Menu.i("Accounts") / "account", + DynIpSnippet.menu )) /* Menu widget */ - MenuWidget.init() + LiftMenuWidget.init() /* Http conf */ LiftRules.logServiceRequestTiming = false @@ -94,4 +100,18 @@ } } +class MenuWidget(style: MenuStyle.Value, jsObj: JsObj, groups : List[String]) + extends LiftMenuWidget(style, jsObj, groups) { + + override def render: NodeSeq = { + head ++
{groups match { + case Nil => + + case xs => groups.flatMap(group => + ) + }}
+ } +} + + // vim: set ts=2 sw=2 et: diff -r 0f6859991f55 -r 6b1a7f3429ca src/main/scala/net/tz/lift/snippet/SnippetHelpers.scala --- a/src/main/scala/net/tz/lift/snippet/SnippetHelpers.scala Thu Apr 14 15:42:46 2011 +0200 +++ b/src/main/scala/net/tz/lift/snippet/SnippetHelpers.scala Wed Nov 30 16:59:10 2011 +0100 @@ -21,6 +21,8 @@ trait SnippetHelpers { def mkPath(prefix: String, l: String*) = (prefix :: l.toList) mkString ("/", "/", "") + + type CssTr = (NodeSeq => NodeSeq) } class A(href: => String) extends Function1[NodeSeq, NodeSeq] { diff -r 0f6859991f55 -r 6b1a7f3429ca src/main/scala/radview/model/DynIp.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/radview/model/DynIp.scala Wed Nov 30 16:59:10 2011 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 radview.model + +import java.sql.Types +import net.liftweb.common._ +import net.liftweb.mapper._ +import org.joda.time.DateMidnight +import radview.snippet.SessionSnippet +import scala.xml.Text + +object DynIp extends DynIp with MetaMapper[DynIp] { + override def dbTableName = "radacct" + override def dbDefaultConnectionIdentifier = RadAcctConnectionIdentifier + + def byImsi(i: String, from: DateMidnight, to: DateMidnight) = + findAllByPreparedStatement { c => + val sql = "SELECT MIN(%s) AS %s, %s, %s FROM %s" + + " WHERE %s = ? AND %s BETWEEN ? AND ? GROUP BY %s ORDER BY %s" + val pars = ((List(ts, ts, framedIp, callingNo) map (_.dbColumnName)) :+ + dbTableName) ::: (List(callingNo, ts, framedIp, ts) map (_.dbColumnName)) + val st = c.connection.prepareStatement(sql.format(pars :_*)) + st.setString(1, i) + st.setObject(2, from.toDate, Types.DATE) + st.setObject(3, to.toDate, Types.DATE) + st + } + + def byIp(i: String, from: DateMidnight, to: DateMidnight) = + findAllByPreparedStatement { c => + val sql = "SELECT MIN(%s) AS %s, %s, %s FROM %s" + + " WHERE %s = ? AND %s BETWEEN ? AND ? GROUP BY %s ORDER BY %s" + val pars = ((List(ts, ts, framedIp, callingNo) map (_.dbColumnName)) :+ + dbTableName) ::: (List(framedIp, ts, callingNo, ts) map (_.dbColumnName)) + val st = c.connection.prepareStatement(sql.format(pars :_*)) + st.setString(1, i) + st.setObject(2, from.toDate, Types.DATE) + st.setObject(3, to.toDate, Types.DATE) + st + } +} + +class DynIp extends Mapper[DynIp] { + def getSingleton = DynIp + + object framedIp extends MappedPoliteStringColName(this, 15, + "framedipaddress", "Framed IP") + + object ts extends MappedDateTime(this) { + override def dbColumnName = "Event_Timestamp" + override def displayName = "Timestamp" + } + + object callingNo extends MappedLongColName(this, "callingstationid", + "Calling No.") + +} + +// vim: set ts=2 sw=2 et: diff -r 0f6859991f55 -r 6b1a7f3429ca src/main/scala/radview/snippet/AccountSnippet.scala --- a/src/main/scala/radview/snippet/AccountSnippet.scala Thu Apr 14 15:42:46 2011 +0200 +++ b/src/main/scala/radview/snippet/AccountSnippet.scala Wed Nov 30 16:59:10 2011 +0100 @@ -30,7 +30,8 @@ import scala.xml.{NodeSeq, Text} object AsAccountImsi { - def unapply(in: String): Option[RadCheckSub] = RadCheckSub.byImsi(in) + def unapply(in: String) = apply(in) + def apply(in: String): Option[RadCheckSub] = RadCheckSub.byImsi(in) } abstract sealed class AccountLoc @@ -38,12 +39,14 @@ case class ViewAccount(acc: RadCheckSub) extends AccountLoc case class SyslogAccount(acc: RadCheckSub) extends AccountLoc case class CdrAccount(acc: RadCheckSub) extends AccountLoc +case class DynIpAccount(acc: RadCheckSub) extends AccountLoc object AsAccount { def unapply(loc: Box[AccountLoc]): Option[RadCheckSub] = loc flatMap { _ match { case SyslogAccount(a) => Some(a) case ViewAccount(a) => Some(a) case CdrAccount(a) => Some(a) + case DynIpAccount(a) => Some(a) case _ => None }} } @@ -61,6 +64,7 @@ case ViewAccount(a) => mkPath(prefix, "imsi", a.imsi.is) case SyslogAccount(a) => mkPath(prefix, "imsi", a.imsi.is, "syslog") case CdrAccount(a) => mkPath(prefix, "imsi", a.imsi.is, "cdr") + case DynIpAccount(a) => mkPath(prefix, "imsi", a.imsi.is, "dyn-ip") } } @@ -71,6 +75,7 @@ case ViewAccount(a) => "Account " + a.imsi case SyslogAccount(a) => "Syslog search for account " + a.imsi case CdrAccount(a) => "CDR search for account " + a.imsi + case DynIpAccount(a) => "Dynamic IP assignments for account " + a.imsi })) override def rewrite: LocRewrite = Full({ @@ -85,9 +90,13 @@ case "cdr" :: xs => ActionLinks.append(A(url(ViewAccount(a)), "Back to account")) CdrAccount(a) + case "dyn-ip" :: xs => + ActionLinks.append(A(url(ViewAccount(a)), "Back to account")) + DynIpAccount(a) case _ => ActionLinks.append(A(url(SyslogAccount(a)), "Syslog search")) ActionLinks.append(A(url(CdrAccount(a)), "CDR search")) + ActionLinks.append(A(url(DynIpAccount(a)), "Dynamic IP address assignments")) ViewAccount(a) } (RResp(List(tpl, "view")), l) @@ -104,6 +113,7 @@ case ("form", Full(SyslogAccount(a))) => syslogForm(a) case ("cdr-list", Full(CdrAccount(a))) => cdrList(a) case ("form", Full(CdrAccount(a))) => cdrForm(a) + case ("dyn-ip-list", Full(DynIpAccount(a))) => dynIpList(a) case ("form", _) => ClearNodes case ("syslog-list", _) => ClearNodes @@ -111,6 +121,7 @@ case ("sub", _) => ClearNodes case ("if-nai", _) => ClearNodes case ("nai", _) => ClearNodes + case ("dyn-ip-list", _) => ClearNodes } /* Shared in all searches. */ @@ -309,6 +320,20 @@ "attr-name-wide", "attr-value") } ) & ".list" #> CdrTable(Cdr.findAll( (qp:+MaxRows(mxCnt.is) ):_*), a.isAdsl) } openOr ClearNodes + + def dynIpList(a: RadCheckSub): CssTr = { + import DynIp._ + val from = (S param "from") flatMap (AsDateMidnight(_)) openOr ( + (new DateTime).minusDays(7).toDateMidnight) + val to = (S param "to") flatMap (AsDateMidnight(_)) openOr ( + (new DateTime).toDateMidnight) + + "#dyn-ip-from [value]" #> AsDateMidnight(from) & + "#dyn-ip-to [value]" #> AsDateMidnight(to) & + ".list" #> Table[DynIp](List(framedIp, ts) map { f => + Column[DynIp](f.displayName, { v: DynIp => f.actualField(v).asHtml }) + }, byImsi(a.imsi, from, to.plusDays(1))) + } } object AccountTable { diff -r 0f6859991f55 -r 6b1a7f3429ca src/main/scala/radview/snippet/DynIpSnippet.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/radview/snippet/DynIpSnippet.scala Wed Nov 30 16:59:10 2011 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright 2011 Tomas Zeman + * + * 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 radview.snippet + +import net.liftweb.common._ +import net.liftweb.http._ +import net.liftweb.sitemap._ +import net.liftweb.sitemap.Loc._ +import net.liftweb.util.ClearNodes +import net.liftweb.util.Helpers._ +import net.tz.lift.snippet._ +import net.tz.lift.util._ +import org.joda.time.DateTime +import radview.model._ +import scala.xml.{NodeSeq, Text} + +object DynIpSnippet extends SnippetHelpers { + + val menu = Menu("Dynamic IP Search") / "dyn-ip" >> + Snippet("form", form) >> Snippet("res", res) + + def from = (S param "from") flatMap (AsDateMidnight(_)) openOr ( + (new DateTime).minusDays(7).toDateMidnight) + def to = (S param "to") flatMap (AsDateMidnight(_)) openOr ( + (new DateTime).toDateMidnight) + + def form: CssTr = { + "#ip [value]" #> (S param "ip") & + "#from [value]" #> AsDateMidnight(from) & + "#to [value]" #> AsDateMidnight(to) + } + + def res: CssTr = { + import DynIp._ + "*" #> (for { + ip <- S param "ip" + } yield { + Table[DynIp](List( + Column[DynIp](callingNo.displayName, { v: DynIp => + val n = v.callingNo.is.toString + val h = v.callingNo.asHtml + AsAccountImsi(n) map { a => + {h} + } getOrElse h + }), + Column[DynIp](ts.displayName, { v: DynIp => v.ts.asHtml }) + ), byIp(ip, from, to.plusDays(1))) + }) + } +} + +// vim: set ts=2 sw=2 et: diff -r 0f6859991f55 -r 6b1a7f3429ca src/main/webapp/account/view.html --- a/src/main/webapp/account/view.html Thu Apr 14 15:42:46 2011 +0200 +++ b/src/main/webapp/account/view.html Wed Nov 30 16:59:10 2011 +0100 @@ -47,6 +47,32 @@

+
+
+ + + + + + + + + + + + +
+ + + +
+ + + +
+
+
+
diff -r 0f6859991f55 -r 6b1a7f3429ca src/main/webapp/dyn-ip.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/webapp/dyn-ip.html Wed Nov 30 16:59:10 2011 +0100 @@ -0,0 +1,62 @@ + + + + + Dyn IP Search + + +
+ + + + + +
+

+
+
+
+ + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+
+ +