Tweaks to Who's Nearby

This commit is contained in:
Noah Petherbridge 2023-08-19 21:09:23 -07:00
parent cc628afd44
commit a785b093e7
7 changed files with 104 additions and 10 deletions

View File

@ -78,7 +78,8 @@ func Dashboard() http.HandlerFunc {
// Geolocation/Who's Nearby: if the current user uses GeoIP, update // Geolocation/Who's Nearby: if the current user uses GeoIP, update
// their coordinates now. // their coordinates now.
if err := models.RefreshGeoIP(currentUser.ID, r); err != nil { myLocation, err := models.RefreshGeoIP(currentUser.ID, r)
if err != nil {
log.Error("RefreshGeoIP: %s", err) log.Error("RefreshGeoIP: %s", err)
} }
@ -92,6 +93,9 @@ func Dashboard() http.HandlerFunc {
"HasPublicPhoto": hasPublic, "HasPublicPhoto": hasPublic,
"PhotoLikeMap": models.MapLikes(currentUser, "photos", photoIDs), "PhotoLikeMap": models.MapLikes(currentUser, "photos", photoIDs),
// Who's Nearby stats.
"MyLocation": myLocation,
} }
if err := tmpl.Execute(w, r, vars); err != nil { if err := tmpl.Execute(w, r, vars); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)

View File

@ -5,6 +5,8 @@ import (
"strconv" "strconv"
"code.nonshy.com/nonshy/website/pkg/config" "code.nonshy.com/nonshy/website/pkg/config"
"code.nonshy.com/nonshy/website/pkg/geoip"
"code.nonshy.com/nonshy/website/pkg/log"
"code.nonshy.com/nonshy/website/pkg/models" "code.nonshy.com/nonshy/website/pkg/models"
"code.nonshy.com/nonshy/website/pkg/session" "code.nonshy.com/nonshy/website/pkg/session"
"code.nonshy.com/nonshy/website/pkg/templates" "code.nonshy.com/nonshy/website/pkg/templates"
@ -51,6 +53,13 @@ func Search() http.HandlerFunc {
return return
} }
// Geolocation/Who's Nearby: if the current user uses GeoIP, update
// their coordinates now.
myLocation, err := models.RefreshGeoIP(currentUser.ID, r)
if err != nil {
log.Error("RefreshGeoIP: %s", err)
}
// Sort options. // Sort options.
for _, v := range sortWhitelist { for _, v := range sortWhitelist {
if sort == v { if sort == v {
@ -87,6 +96,9 @@ func Search() http.HandlerFunc {
session.FlashError(w, r, "Couldn't search users: %s", err) session.FlashError(w, r, "Couldn't search users: %s", err)
} }
// Who's Nearby feature, get some data.
insights, _ := geoip.GetRequestInsights(r)
var vars = map[string]interface{}{ var vars = map[string]interface{}{
"Users": users, "Users": users,
"Pager": pager, "Pager": pager,
@ -106,8 +118,9 @@ func Search() http.HandlerFunc {
"PhotoCountMap": models.MapPhotoCounts(users), "PhotoCountMap": models.MapPhotoCounts(users),
// Current user's location setting. // Current user's location setting.
"MyLocation": models.GetUserLocation(currentUser.ID), "MyLocation": myLocation,
"DistanceMap": models.MapDistances(currentUser, users), "GeoIPInsights": insights,
"DistanceMap": models.MapDistances(currentUser, users),
} }
if err := tmpl.Execute(w, r, vars); err != nil { if err := tmpl.Execute(w, r, vars); err != nil {

View File

@ -43,6 +43,16 @@ func (i Insights) String() string {
return strings.Join(parts, "; ") return strings.Join(parts, "; ")
} }
// Short prints a short summary string of the insights.
func (i Insights) Short() string {
var parts = []string{
i.CountryName,
strings.Join(i.Subdivisions, ", "),
i.City,
}
return strings.Join(parts, "; ")
}
// GetRequestInsights returns structured insights based on the current HTTP request. // GetRequestInsights returns structured insights based on the current HTTP request.
func GetRequestInsights(r *http.Request) (Insights, error) { func GetRequestInsights(r *http.Request) (Insights, error) {
var ( var (

View File

@ -47,18 +47,18 @@ func (ul *UserLocation) Save() error {
} }
// RefreshGeoIP will auto-update a user's location by GeoIP if that's their setting. // RefreshGeoIP will auto-update a user's location by GeoIP if that's their setting.
func RefreshGeoIP(userID uint64, r *http.Request) error { func RefreshGeoIP(userID uint64, r *http.Request) (*UserLocation, error) {
loc := GetUserLocation(userID) loc := GetUserLocation(userID)
if loc.Source == LocationSourceGeoIP { if loc.Source == LocationSourceGeoIP {
if insights, err := geoip.GetRequestInsights(r); err == nil { if insights, err := geoip.GetRequestInsights(r); err == nil {
loc.Latitude = insights.Latitude loc.Latitude = insights.Latitude
loc.Longitude = insights.Longitude loc.Longitude = insights.Longitude
return loc.Save() return loc, loc.Save()
} else { } else {
return fmt.Errorf("didn't get insights: %s", err) return loc, fmt.Errorf("didn't get insights: %s", err)
} }
} }
return nil return loc, nil
} }
// MapDistances computes human readable distances between you and the set of users. // MapDistances computes human readable distances between you and the set of users.

View File

@ -133,6 +133,45 @@
</div> </div>
{{end}} {{end}}
<!-- New Feature: Who's Nearby -->
{{if not .MyLocation.Source}}
<div class="card block">
<header class="card-header has-background-success-dark">
<p class="card-header-title has-text-light">
<i class="fa fa-gift mr-2"></i>
New Feature: Who's Nearby?
</p>
</header>
<div class="card-content">
<p class="block">
We've recently added a new feature! <strong>Who's Nearby</strong> can allow you to sort the
<a href="/members">Member Directory</a> by their distance away from you.
</p>
<p class="block">
First, you'll need to opt-in where <em>your</em> location is so that the site can know who's
nearby. Please visit your <a href="/settings#location">Location Settings</a> page to choose
how you share your location -- you can even just drop a pin on a map anywhere you're comfortable
with!
</p>
<p class="block">
Then, you'll be able to <a href="/members?sort=distance">sort the Member Directory by distance</a>.
Only people whose location is known will show in the results.
</p>
<p class="block">
This feature is very privacy-conscious and you can turn it off again later, and we'll forget
any location data we had! For more information, see <a href="https://www.nonshy.com/forum/thread/161">this forum thread</a>.
This message will go away after you have set a <a href="/settings#location">location source</a>
for your profile -- or after a few weeks when enough people have had a chance to hear about
the new feature!
</p>
</div>
</div>
{{end}}
<div class="card block"> <div class="card block">
<header class="card-header has-background-link"> <header class="card-header has-background-link">
<p class="card-header-title has-text-light">My Account</p> <p class="card-header-title has-text-light">My Account</p>

View File

@ -6,7 +6,7 @@
<div class="hero-body"> <div class="hero-body">
<div class="container"> <div class="container">
<h1 class="title"> <h1 class="title">
{{if eq .Pager.Sort "distance"}} {{if eq .Sort "distance"}}
<i class="fa fa-location-dot mr-2"></i> <i class="fa fa-location-dot mr-2"></i>
Who's Nearby Who's Nearby
{{else}} {{else}}
@ -41,7 +41,18 @@
{{else}} {{else}}
<div class="notification is-success is-light"> <div class="notification is-success is-light">
Showing you <strong>Who's Nearby.</strong> Showing you <strong>Who's Nearby.</strong>
<a href="/settings#location">Update your location?</a>
<!-- Show options to refresh their location -->
{{if eq .MyLocation.Source "geoip"}}
You set your location automatically by your IP address <small>(currently {{.GeoIPInsights.Short}}).</small>
<a href="/settings#location">Update settings?</a>
{{else if eq .MyLocation.Source "gps"}}
Your location was set by your GPS location.
<a href="/settings#location" id="gpsRefresh">Refresh your location now?</a>
{{else if eq .MyLocation.Source "pin"}}
You set your location by pin on a map.
<a href="/settings#location">Update your location?</a>
{{end}}
</div> </div>
{{end}} {{end}}

View File

@ -426,6 +426,12 @@
feature and you have your choice of options how you want your location to be found. feature and you have your choice of options how you want your location to be found.
</p> </p>
<div class="notification is-info is-light py-2 px-3">
<i class="fa fa-exclamation-triangle"></i>
<strong>Notice:</strong>
Remember to click "Save" after setting your location preference!
</div>
<div class="field"> <div class="field">
<label class="label">How do you want your location to be determined?</label> <label class="label">How do you want your location to be determined?</label>
<label class="checkbox"> <label class="checkbox">
@ -525,7 +531,7 @@
</div> </div>
<div class="field"> <div class="field">
<button type="submit" class="button is-success" <button type="submit" class="button is-success mr-2"
name="intent" value="location"> name="intent" value="location">
Save My Location Settings Save My Location Settings
</button> </button>
@ -799,6 +805,11 @@ window.addEventListener("DOMContentLoaded", (event) => {
getLocation(); getLocation();
}); });
// If the page loaded w/ the GPS option on, ask right away.
if ($optionGPS.checked) {
$optionGPS.click();
}
// Wire the refresh button. // Wire the refresh button.
$gpsRefreshButton.addEventListener("click", (e) => { $gpsRefreshButton.addEventListener("click", (e) => {
e.preventDefault(); e.preventDefault();
@ -809,6 +820,12 @@ window.addEventListener("DOMContentLoaded", (event) => {
$optionGeoIP.addEventListener("click", (e) => { $optionGeoIP.addEventListener("click", (e) => {
// Set the form fields. // Set the form fields.
// NOTE: defaultCoords are [lon, lat] we want [lat, lon] // NOTE: defaultCoords are [lon, lat] we want [lat, lon]
if (geoIPInsights.Latitude != 0 || geoIPInsights.Longitude != 0) {
defaultCoords = [
geoIPInsights.Longitude,
geoIPInsights.Latitude,
];
}
saveCoords(defaultCoords[1], defaultCoords[0]); saveCoords(defaultCoords[1], defaultCoords[0]);
if (setMapPin !== null) { if (setMapPin !== null) {