diff --git a/Dockerfile b/Dockerfile index 961f490c..50b45877 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,6 +34,7 @@ RUN apk -U add --no-cache \ && rm -rf /var/cache/apk/* \ && mkdir -p $APP_PATH +RUN gem update --system RUN gem install bundler --version "$BUNDLE_VERSION" \ && rm -rf $GEM_HOME/cache/* diff --git a/Makefile b/Makefile index 42ab28c6..6a5a1f54 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,5 @@ build_and_push: docker build . -t dawarich:$(version) --platform=linux/amd64 docker tag dawarich:$(version) registry.chibi.rodeo/dawarich:$(version) docker push registry.chibi.rodeo/dawarich:$(version) + docker tag dawarich:$(version) freikin/dawarich:$(version) + docker push freikin/dawarich:$(version) diff --git a/README.md b/README.md index 09edc526..d70d5c7e 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,27 @@ # Dawarich -This is a Rails app that receives location updates from Owntracks and stores them in a database. It also provides a web interface to view the location history. +Dawarich is a self-hosted web application to replace Google Timeline (aka Google Location History). It allows you to import your location history from Google Maps Timeline and Owntracks, view it on a map and see some statistics, such as the number of countries and cities visited, and distance traveled. ## Usage -To track your location, install the Owntracks [app](https://owntracks.org/booklet/guide/apps/) on your phone and configure it to send location updates to your Dawarich instance. Currently, the app only supports HTTP mode. The url to send the location updates to is `http:///api/v1/points`. +To track your location, install the [Owntracks app](https://owntracks.org/booklet/guide/apps/) on your phone and configure it to send location updates to your Dawarich instance. Currently, the app only supports [HTTP mode](https://owntracks.org/booklet/tech/http/). The url to send the location updates to is `http:///api/v1/points`. To import your Google Maps Timeline data, download your location history from [Google Takeout](https://takeout.google.com/) and upload it to Dawarich. ## Features -### Import - -You can import your Google Maps Timeline data into Dawarich as well as Owntracks data. - ### Location history You can view your location history on a map. +### Statistics + +You can see the number of countries and cities visited, the distance traveled, and the time spent in each country, splitted by years and months. + +### Import + +You can import your Google Maps Timeline data into Dawarich as well as Owntracks data. + ## How to start the app locally `docker-compose up` to start the app. The app will be available at `http://localhost:3000`. diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index 9e0292d5..c3ceacad 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -7,7 +7,7 @@ class StatsController < ApplicationController def show @year = params[:year].to_i - @stats = current_user.stats.where(year: @year) + @stats = current_user.stats.where(year: @year).order(:month) end def update diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 30ed41cc..f7a13f81 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -26,4 +26,16 @@ module ApplicationHelper def header_colors %w[info success warning error accent secondary primary] end + + def countries_and_cities_stat(year) + data = Stat.year_cities_and_countries(year) + countries = data[:countries] + cities = data[:cities] + + "#{countries} countries, #{cities} cities" + end + + def year_distance_stat_in_km(year) + Stat.year_distance(year).sum { _1[1] } + end end diff --git a/app/javascript/controllers/maps_controller.js b/app/javascript/controllers/maps_controller.js index ee656ba0..143bf002 100644 --- a/app/javascript/controllers/maps_controller.js +++ b/app/javascript/controllers/maps_controller.js @@ -29,8 +29,7 @@ export default class extends Controller { Longitude: ${marker[1]}
Altitude: ${marker[3]}m
Velocity: ${marker[5]}km/h
- Battery: ${marker[2]}%
- id: ${marker[6]}
+ Battery: ${marker[2]}% `; } diff --git a/app/models/stat.rb b/app/models/stat.rb index e7b618f1..45ec29dd 100644 --- a/app/models/stat.rb +++ b/app/models/stat.rb @@ -34,6 +34,21 @@ class Stat < ApplicationRecord def self.year_distance(year) stats = where(year: year).order(:month) - stats.map { |stat| [Date::MONTHNAMES[stat.month], stat.distance] } + (1..12).to_a.map do |month| + month_stat = stats.select { |stat| stat.month == month }.first + + month_name = Date::MONTHNAMES[month] + distance = month_stat&.distance || 0 + + [month_name, distance] + end + end + + def self.year_cities_and_countries(year) + points = Point.where(timestamp: DateTime.new(year).beginning_of_year..DateTime.new(year).end_of_year) + + data = CountriesAndCities.new(points).call + + { countries: data.count, cities: data.sum { |country| country[:cities].count } } end end diff --git a/app/models/user.rb b/app/models/user.rb index 122407a3..a20d5430 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,7 +23,7 @@ class User < ApplicationRecord end def total_countries - Stat.where(user: self).pluck(:toponyms).flatten.uniq.size + Stat.where(user: self).pluck(:toponyms).flatten.map { _1['country'] }.uniq.size end def total_cities diff --git a/app/services/google_maps/timeline_parser.rb b/app/services/google_maps/timeline_parser.rb index 60196671..dd1f76c0 100644 --- a/app/services/google_maps/timeline_parser.rb +++ b/app/services/google_maps/timeline_parser.rb @@ -60,12 +60,28 @@ class GoogleMaps::TimelineParser } end elsif timeline_object['placeVisit'].present? - { - latitude: timeline_object['placeVisit']['location']['latitudeE7'].to_f / 10**7, - longitude: timeline_object['placeVisit']['location']['longitudeE7'].to_f / 10**7, - timestamp: DateTime.parse(timeline_object['placeVisit']['duration']['startTimestamp']), - raw_data: timeline_object - } + if timeline_object['placeVisit']['location']['latitudeE7'].present? && + timeline_object['placeVisit']['location']['longitudeE7'].present? + { + latitude: timeline_object['placeVisit']['location']['latitudeE7'].to_f / 10**7, + longitude: timeline_object['placeVisit']['location']['longitudeE7'].to_f / 10**7, + timestamp: DateTime.parse(timeline_object['placeVisit']['duration']['startTimestamp']), + raw_data: timeline_object + } + elsif timeline_object['placeVisit']['otherCandidateLocations'].any? + point = timeline_object['placeVisit']['otherCandidateLocations'][0] + + next unless point['latitudeE7'].present? && point['longitudeE7'].present? + + { + latitude: point['latitudeE7'].to_f / 10**7, + longitude: point['longitudeE7'].to_f / 10**7, + timestamp: DateTime.parse(timeline_object['placeVisit']['duration']['startTimestamp']), + raw_data: timeline_object + } + else + next + end end end.reject(&:blank?) end diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 97763314..4bd0a738 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -5,9 +5,9 @@ <%= link_to 'DaWarIch', root_path, class: 'btn btn-ghost normal-case text-xl mr-10'%> @@ -19,9 +19,9 @@