Skip to content
Browse files

Start work on category related maps

  • Loading branch information...
1 parent dbce41a commit 30e191359552ff3293e0aa7dd81e57a4e63941d3 @nfolkert-foursquare nfolkert-foursquare committed
View
1 project/build.properties
@@ -6,3 +6,4 @@ project.version=0.0.2
def.scala.version=2.7.7
build.scala.versions=2.8.0 2.7.7
project.initialize=false
+lift.version=2.4-M3
View
2 src/main/scala/boostrap/liftweb/Boot.scala
@@ -11,6 +11,7 @@ import Loc._
import org.nfolkert.fssc.model.MongoSetup
import org.scalafoursquare.call.App
import org.scalafoursquare.call.App.CallLogger
+import org.nfolkert.fssc.UserData
/**
* A class that's instantiated early and run. It allows the application
@@ -56,6 +57,7 @@ class Boot {
// Force the request to be UTF-8
LiftRules.early.append(_.setCharacterEncoding("UTF-8"))
+ UserData.initCaches
}
}
View
22 src/main/scala/org/nfolkert/fssc/UserData.scala
@@ -1,13 +1,13 @@
package org.nfolkert.fssc
-import model.{UserVenueHistoryEntry, UserVenueHistory, User}
-import org.scalafoursquare.call.{HttpCaller, AuthApp}
+import model.{VenueCategories, UserVenueHistoryEntry, UserVenueHistory, User}
import net.liftweb.util.Props
import org.joda.time.DateTime
import org.scalafoursquare.auth.OAuthFlow
import org.scalafoursquare.response.{Response, VenueExploreResponse, VenueCompact, VenueLocation, CheckinForFriend}
import org.nfolkert.lib.{T, Util}
import net.liftweb.common.{Full, Loggable, Box}
+import org.scalafoursquare.call.{UserlessApp, HttpCaller, AuthApp}
object UserData extends Loggable {
val AUTH_TOKEN = Props.get("access.token.user").open_!
@@ -20,7 +20,7 @@ object UserData extends Loggable {
}
def getApp(token: String) = new AuthApp(HttpCaller(CLIENT_ID, CLIENT_SECRET, readTimeout=10000), token)
-
+ def getUserlessApp = new UserlessApp(HttpCaller(CLIENT_ID, CLIENT_SECRET, readTimeout=10000))
def getUser(token: String): Option[User] = {
val app = getApp(token)
@@ -99,13 +99,15 @@ object UserData extends Loggable {
}
}
+ val MAX_IDLE_DAYS_TO_REFRESH = 7
+ val MAX_DAYS_TO_REFRESH = 30
+
def updateUserVenueHistory(token: String, userid: String, history: UserVenueHistory): Box[UserVenueHistory] = T("Update UserVenueHistory") {
val lastUpdateSeconds = history.lastUpdate.value
val lastRefreshSeconds = history.lastRefresh.value
- // If no updates have been made in a month, or last full rebuild is older than 6 months, do complete rebuild
- if (Util.dateFromSeconds(lastUpdateSeconds).isBefore(new DateTime().minusDays(30)) ||
- Util.dateFromSeconds(lastRefreshSeconds).isBefore(new DateTime().minusDays(180)))
+ if (Util.dateFromSeconds(lastUpdateSeconds).isBefore(new DateTime().minusDays(MAX_IDLE_DAYS_TO_REFRESH)) ||
+ Util.dateFromSeconds(lastRefreshSeconds).isBefore(new DateTime().minusDays(MAX_DAYS_TO_REFRESH)))
fetchUserVenueHistory(userid, token)
else if (Util.dateFromSeconds(lastUpdateSeconds).isAfter(new DateTime().minusMinutes(1)))
Full(history) // We can give a little delay on reloading?
@@ -135,7 +137,6 @@ object UserData extends Loggable {
history.venues(out)
}
history.setLastUpdate(new DateTime()).save
-
})
}
}
@@ -200,4 +201,11 @@ object UserData extends Loggable {
})
}).toSet
}
+
+ lazy val venueCategories = {
+ VenueCategories.create(getUserlessApp.venueCategories.get.response)
+ }
+ def initCaches {
+ venueCategories
+ }
}
View
1 src/main/scala/org/nfolkert/fssc/model/User.scala
@@ -39,6 +39,7 @@ object RecommendationType {
val shops = RecommendationType("shops", "Shopping")
val arts = RecommendationType("arts", "Arts & Entertainment")
val outdoors = RecommendationType("outdoors", "Outdoors")
+ val travel = RecommendationType("travel", "Travel")
val all = RecommendationType("all", "All Categories")
val values = List(none, food, drinks, coffee, shops, arts, outdoors, all)
val defaultValue = all
View
61 src/main/scala/org/nfolkert/fssc/model/VenueCategory.scala
@@ -0,0 +1,61 @@
+package org.nfolkert.fssc.model
+
+import org.scalafoursquare.response.{VenueCategoryWithChildren, VenueCategoriesResponse}
+import net.liftweb.common.{Full, Box, Empty}
+import org.nfolkert.fssc.UserData
+
+case class VenueCategory(id: String, name: String, icon: String, children: List[VenueCategory]) {}
+
+case class VenueCategories (roots: List[VenueCategory], map: Map[String, VenueCategory], ancestors: Map[VenueCategory, List[VenueCategory]]) {
+ def parent(id: String): Option[VenueCategory] = category(id).flatMap(cat=>parent(cat))
+ def category(id: String): Option[VenueCategory] = map.get(id)
+ def root(id: String): Option[VenueCategory] = category(id).flatMap(cat=>root(cat))
+
+ def parent(cat: VenueCategory): Option[VenueCategory] = ancestors.get(cat).flatMap(_.headOption).filter(_ != cat)
+ def root(cat: VenueCategory): Option[VenueCategory] = ancestors.get(cat).flatMap(_.lastOption)
+
+ def exploreSection(cat: VenueCategory) = root(cat).map(_.id match {
+ // Meh. Can't use anything from category to infer the explore section
+
+ case "4d4b7104d754a06370d81259" => Some(RecommendationType.arts) // Arts & Entertainment
+ case "4d4b7105d754a06372d81259" => None // Colleges & Universities
+ case "4d4b7105d754a06374d81259" => Some(RecommendationType.food) // Food
+ case "4d4b7105d754a06377d81259" => Some(RecommendationType.outdoors) // Great Outdoors
+ case "4d4b7105d754a06376d81259" => Some(RecommendationType.drinks) // Nightlife
+ case "4d4b7105d754a06375d81259" => None // Professional & Other Places
+ case "4e67e38e036454776db1fb3a" => None // Residence
+ case "4d4b7105d754a06378d81259" => Some(RecommendationType.shops) // Shops & Services
+ case "4d4b7105d754a06379d81259" => Some(RecommendationType.travel) // Travel Spot
+ case _ => None
+ }).getOrElse({
+ cat.id match {
+ case "4bf58dd8d48988d1e0931735" | "4bf58dd8d48988d16d941735" | "4bf58dd8d48988d1dc931735" => Some(RecommendationType.coffee)
+ case _ => None
+ }
+ })
+}
+
+object VenueCategories {
+ def create(response: Option[VenueCategoriesResponse]): VenueCategories = {
+ response.map(r=>{
+ def recRebuild(cat: VenueCategoryWithChildren): VenueCategory = {
+ val children = cat.categories.map(children => {
+ children.map(ch => {recRebuild(ch)})
+ }).getOrElse(Nil)
+ VenueCategory(cat.id.getOrElse(cat.name), cat.name, cat.icon, children)
+ }
+
+ val roots = r.categories.map(cat => {recRebuild(cat)})
+
+ def pull(cat: VenueCategory): List[VenueCategory] = cat :: cat.children.flatMap(cat=>pull(cat))
+ val map = roots.flatMap(cat=>pull(cat)).map(cat=>(cat.id, cat)).toMap
+
+ def ancs(category: VenueCategory, ancestors: List[VenueCategory]): List[(VenueCategory, List[VenueCategory])] = {
+ (category -> ancestors) :: category.children.flatMap(ch=>ancs(ch, ch :: ancestors))
+ }
+ val ancestors = roots.flatMap(cat => ancs(cat, List(cat))).toMap
+
+ VenueCategories(roots, map, ancestors)
+ }).getOrElse(VenueCategories(Nil, Map.empty, Map.empty))
+ }
+}

0 comments on commit 30e1913

Please sign in to comment.
Something went wrong with that request. Please try again.