pyc-website
main website for pyc inc.
git clone https://9o.is/git/pyc-website.git
Atm.scala
(5501B)
1 package inc.pyc
2 package model
3
4 import lib._
5 import field._
6 import net.liftweb._
7 import common.{Box, Empty}
8 import util.Helpers
9 import json._
10 import JsonDSL._
11 import mongodb.record._
12 import mongodb.record.field._
13 import record.field.{StringField, PostalCodeField, CountryField, Countries, TimeZoneField}
14 import com.foursquare.rogue._
15 import org.joda.time._, format._
16 import net.liftmodules.mongoauth.field._
17 import org.bson.types.ObjectId
18
19 class Atm private () extends MongoRecord[Atm] with ObjectIdPk[Atm] {
20 def meta = Atm
21
22 object name extends StringField(this, 64)
23 object address extends StringField(this, 255)
24 object city extends StringField(this, 64)
25 object state extends StringField(this, 64)
26 object postal extends PostalCodeField(this, country)
27 object phone extends StringField(this, 64)
28 object owner extends StringField(this, 64)
29 object website extends StringField(this, 255)
30 object model extends StringField(this, 64)
31 object times extends BsonRecordListField(this, TimeOpen)
32 object ownerObj extends ObjectIdRefField(this, User)
33
34 object country extends CountryField(this) {
35 override def defaultValue = Countries.USA
36 }
37
38 object timezone extends TimeZoneField(this)
39
40 /**
41 * This is used for the ATM to authenticate and communicate with the web server.
42 */
43 object secret extends PasswordField(this, 32, 32)
44
45 /** The Geolocation of the atm. */
46 object loc extends MongoCaseClassField[Atm, LatLong](this) {
47 import Geocode._
48
49 def apply(geo: GeoPoint): Atm = {
50 val latLong = LatLong(geo.lat, geo.lng)
51 apply(latLong)
52 }
53 }
54
55 override def asJValue: JObject = {
56 val json = super.asJValue merge
57 ("status" -> status) ~
58 ("statusLevel" -> statusLevel)
59
60 (json transform {
61 case JField("lat", lat) => JField("latitude", lat)
62 case JField("long", lng) => JField("longitude", lng)
63 case JField("secret", _) => JField("secret", "")
64 case JField("ownerObj", _) => JField("ownerObj", "")
65 case JField("_id", _) => JField("_id", "")
66 })
67 .asInstanceOf[JObject]
68 }
69
70
71 private def timeForToday: TimeOpen = {
72 val now = DateTime.now
73
74 val today = {
75 val n = now.dayOfWeek.get
76 if(n==7) 0 else n // DateTime's Sunday is 7, but TimeOpen's Sunday is 0
77 }
78
79 times.get(today)
80 }
81
82 /**
83 * Whether the ATM is available for service or not.
84 */
85 private def isOpen: Boolean = {
86 val comparator = DateTimeComparator.getTimeOnlyInstance()
87 val formatter = DateTimeFormat.forPattern("HH:mm ZZZ")
88 val time = timeForToday
89 val now = DateTime.now.withZone(DateTimeZone.forID(timezone.get))
90 val open = formatter.parseDateTime(time.open.get + " " + timezone.get)
91 val close = formatter.parseDateTime(time.close.get + " " + timezone.get)
92
93 (comparator.compare(now, open) == 1) && (comparator.compare(now, close) == -1)
94 }
95
96 private def status = if(isOpen) "Now Open" else "Now Closed"
97 private def statusLevel = if(isOpen) "success" else "warning"
98 }
99
100 object Atm extends Atm with RogueMetaRecord[Atm] {
101 import mongodb.BsonDSL._
102 import Geocode._
103
104 override def collectionName = "atm.atms"
105
106 ensureIndex((name.name -> 1), unique = true)
107 ensureIndex(loc.name -> "2d", unique = true)
108
109 def findByName(in: String): Box[Atm] = find(name.name, in)
110
111 def findByStringId(id: String): Box[Atm] =
112 if (ObjectId.isValid(id)) find(new ObjectId(id))
113 else Empty
114
115 /**
116 * Searches for ATM's within a certain distance from a geolocation.
117 */
118 def nearby(geo: GeoPoint, kilometers: Double) = {
119 val radius = Degrees((kilometers / 6378.137).toDegrees)
120 this.where(_.loc near (geo.lat, geo.lng, radius)).fetch()
121 }
122 }
123
124
125 /**
126 * Range of time open for one day.
127 */
128 class TimeOpen private () extends BsonRecord[TimeOpen] {
129 def meta = TimeOpen
130
131 /* Open/Close format HH:mm */
132 object open extends StringField(this, 10)
133 object close extends StringField(this, 10)
134 }
135
136 object TimeOpen extends TimeOpen with BsonMetaRecord[TimeOpen] {
137 def create(open: String, close: String) =
138 TimeOpen.createRecord.open(open).close(close)
139 }
140
141 object FeaturedAtm {
142 import TimeOpen._
143
144 val name = "Crispins"
145
146 lazy val atm: Atm = Atm.findByName(name) openOr {
147
148 val ownerEmail = "robertetaylor@gmail.com"
149 val ownerUser = "Robert_Taylor"
150 val ownerFname = "Robert"
151 val ownerLname = "Taylor"
152
153 val owner: User = User.findByEmail(ownerEmail) openOr {
154 User.createRecord
155 .email(ownerEmail)
156 .username(ownerUser)
157 .fname(ownerFname)
158 .lname(ownerLname)
159 .roles("atm_owner" :: Nil)
160 .password(Helpers.randomString(20), true)
161 .save()
162 }
163
164 val times =
165 create("12:00", "2:00") ::
166 create("12:00", "2:00") ::
167 create("12:00", "2:00") ::
168 create("12:00", "2:00") ::
169 create("12:00", "2:00") ::
170 create("12:00", "2:00") ::
171 create("12:00", "2:00") :: Nil
172
173 Atm.createRecord
174 .name(name)
175 .secret("$2a$10$F/91Ve4n16NkgDT7GQgQUuTjDkQdxV.U1lDAPdQs5LIsbH44FB/ci")
176 .loc(LatLong(40.765708, -73.990707))
177 .address("764 10th Ave")
178 .city("New York")
179 .state("New York")
180 .postal("10019")
181 .phone("(212) 586-0888")
182 .owner(ownerFname + " " + ownerLname)
183 .ownerObj(owner.id.get)
184 .website("http://www.crispinsnyc.com")
185 .model("skyhook")
186 .timezone("America/New_York")
187 .times(times)
188 .save()
189 }
190 }