diff --git a/.app_version b/.app_version index 35aa2f3c..16c6b58f 100644 --- a/.app_version +++ b/.app_version @@ -1 +1 @@ -0.25.4 +0.25.5 diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 597df91b..d697d8f8 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -32,7 +32,6 @@ services: PROMETHEUS_EXPORTER_ENABLED: false PROMETHEUS_EXPORTER_HOST: 0.0.0.0 PROMETHEUS_EXPORTER_PORT: 9394 - ENABLE_TELEMETRY: false # More on telemetry: https://dawarich.app/docs/tutorials/telemetry dawarich_redis: image: redis:7.4-alpine container_name: dawarich_redis diff --git a/.gitignore b/.gitignore index b3a85915..3e2a87f6 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,8 @@ .dotnet/ .cursorrules .cursormemory.md + +/config/credentials/production.key +/config/credentials/production.yml.enc + +Makefile diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da4e84c..ff22b3b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +# 0.25.5 - 2025-04-13 + +## Removed + +- Optional telemetry was removed from the app. +- Sidekiq Web UI is now protected by basic auth in non-self-hosted mode. + +## Changed + +- `rake points:migrate_to_lonlat` task now also tries to extract latitude and longitude from `raw_data` column before using `longitude` and `latitude` columns to fill `lonlat` column. +- Docker entrypoints are now using `DATABASE_NAME` environment variable to check if Postgres is existing/available. + + # 0.25.4 - 2025-04-02 ⚠️ This release includes a breaking change. ⚠️ diff --git a/Gemfile b/Gemfile index ec872bfe..1b6b8ece 100644 --- a/Gemfile +++ b/Gemfile @@ -27,6 +27,7 @@ gem 'activerecord-postgis-adapter' gem 'puma' gem 'pundit' gem 'rails', '~> 8.0' +gem 'rexml' gem 'rgeo' gem 'rgeo-activerecord' gem 'rswag-api' diff --git a/Gemfile.lock b/Gemfile.lock index ff5a3ab7..bdd2bb76 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -506,6 +506,7 @@ DEPENDENCIES pundit rails (~> 8.0) redis + rexml rgeo rgeo-activerecord rspec-rails diff --git a/Makefile b/Makefile deleted file mode 100644 index b4c221d0..00000000 --- a/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -build_and_push: - git tag -a "$(version)" -f -m "$(version)" - docker build . -t dawarich:$(version) --platform=linux/amd64 - docker tag dawarich:$(version) registry.chibi.rodeo/dawarich:$(version) - docker tag registry.chibi.rodeo/dawarich:$(version) registry.chibi.rodeo/dawarich:latest - docker push registry.chibi.rodeo/dawarich:$(version) diff --git a/app/jobs/telemetry_sending_job.rb b/app/jobs/telemetry_sending_job.rb deleted file mode 100644 index 7bec3b00..00000000 --- a/app/jobs/telemetry_sending_job.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -class TelemetrySendingJob < ApplicationJob - queue_as :default - - def perform - return unless ENV['ENABLE_TELEMETRY'] == 'true' - - data = Telemetry::Gather.new.call - Rails.logger.info("Telemetry data: #{data}") - - Telemetry::Send.new(data).call - end -end diff --git a/app/models/user.rb b/app/models/user.rb index dc0bb532..8d7282b4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -101,7 +101,7 @@ class User < ApplicationRecord end def can_subscribe? - active_until&.past? && !DawarichSettings.self_hosted? + (active_until.nil? || active_until&.past?) && !DawarichSettings.self_hosted? end def generate_subscription_token diff --git a/app/services/gpx/track_importer.rb b/app/services/gpx/track_importer.rb index 9abd1a56..24dd2798 100644 --- a/app/services/gpx/track_importer.rb +++ b/app/services/gpx/track_importer.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'rexml/document' + class Gpx::TrackImporter include Imports::Broadcaster diff --git a/app/services/photos/import_parser.rb b/app/services/photos/import_parser.rb index b91a9ca3..fec7bba8 100644 --- a/app/services/photos/import_parser.rb +++ b/app/services/photos/import_parser.rb @@ -3,16 +3,19 @@ class Photos::ImportParser include Imports::Broadcaster include PointValidation - attr_reader :import, :json, :user_id + attr_reader :import, :user_id def initialize(import, user_id) @import = import - @json = import.raw_data @user_id = user_id end def call - json.each.with_index(1) { |point, index| create_point(point, index) } + import.file.download do |file| + json = Oj.load(file) + + json.each.with_index(1) { |point, index| create_point(point, index) } + end end def create_point(point, index) diff --git a/app/services/points/raw_data_lonlat_extractor.rb b/app/services/points/raw_data_lonlat_extractor.rb new file mode 100644 index 00000000..81071976 --- /dev/null +++ b/app/services/points/raw_data_lonlat_extractor.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +class Points::RawDataLonlatExtractor + def initialize(point) + @point = point + end + + def call + lonlat = extract_lonlat(@point) + + @point.update( + longitude: lonlat[0], + latitude: lonlat[1] + ) + end + + private + + # rubocop:disable Metrics/MethodLength + def extract_lonlat(point) + if point.raw_data['activitySegment']['waypointPath']['waypoints'][0] + # google_semantic_history_parser + [ + point.raw_data['activitySegment']['waypointPath']['waypoints'][0]['lngE7'].to_f / 10**7, + point.raw_data['activitySegment']['waypointPath']['waypoints'][0]['latE7'].to_f / 10**7 + ] + elsif point.raw_data['longitudeE7'] && point.raw_data['latitudeE7'] + # google records + [ + point.raw_data['longitudeE7'].to_f / 10**7, + point.raw_data['latitudeE7'].to_f / 10**7 + ] + elsif point.raw_data['position']['LatLng'] + # google phone export + raw_coordinates = point.raw_data['position']['LatLng'] + if raw_coordinates.include?('°') + raw_coordinates.split(', ').map { _1.chomp('°') } + else + raw_coordinates.delete('geo:').split(',') + end + elsif point.raw_data['lon'] && point.raw_data['lat'] + # gpx_track_importer, owntracks + [point.raw_data['lon'], point.raw_data['lat']] + elsif point.raw_data['geometry']['coordinates'][0] && point.raw_data['geometry']['coordinates'][1] + # geojson + [ + point.raw_data['geometry']['coordinates'][0], + point.raw_data['geometry']['coordinates'][1] + ] + elsif point.raw_data['longitude'] && point.raw_data['latitude'] + # immich_api, photoprism_api + [point.raw_data['longitude'], point.raw_data['latitude']] + end + end + # rubocop:enable Metrics/MethodLength +end diff --git a/app/services/telemetry/gather.rb b/app/services/telemetry/gather.rb deleted file mode 100644 index 90b7ee01..00000000 --- a/app/services/telemetry/gather.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -class Telemetry::Gather - def initialize(measurement: 'dawarich_usage_metrics') - @measurement = measurement - end - - def call - { - measurement:, - timestamp: Time.current.to_i, - tags: { instance_id: }, - fields: { dau:, app_version: } - } - end - - private - - attr_reader :measurement - - def instance_id - @instance_id ||= Digest::SHA2.hexdigest(User.first.api_key) - end - - def app_version - "\"#{APP_VERSION}\"" - end - - def dau - User.where(last_sign_in_at: Time.zone.today.beginning_of_day..Time.zone.today.end_of_day).count - end -end diff --git a/app/services/telemetry/send.rb b/app/services/telemetry/send.rb deleted file mode 100644 index 96f222af..00000000 --- a/app/services/telemetry/send.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -class Telemetry::Send - BUCKET = 'dawarich_metrics' - ORG = 'monitoring' - - def initialize(payload) - @payload = payload - end - - def call - return unless ENV['ENABLE_TELEMETRY'] == 'true' - - line_protocol = build_line_protocol - response = send_request(line_protocol) - handle_response(response) - end - - private - - attr_reader :payload - - def build_line_protocol - tag_string = payload[:tags].map { |k, v| "#{k}=#{v}" }.join(',') - field_string = payload[:fields].map { |k, v| "#{k}=#{v}" }.join(',') - - "#{payload[:measurement]},#{tag_string} #{field_string} #{payload[:timestamp].to_i}" - end - - def send_request(line_protocol) - HTTParty.post( - "#{TELEMETRY_URL}?org=#{ORG}&bucket=#{BUCKET}&precision=s", - body: line_protocol, - headers: { - 'Authorization' => "Token #{Base64.decode64(TELEMETRY_STRING)}", - 'Content-Type' => 'text/plain' - } - ) - end - - def handle_response(response) - Rails.logger.error("InfluxDB write failed: #{response.body}") unless response.success? - - response - end -end diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb index 417b5fa0..5d5296b6 100644 --- a/app/views/devise/shared/_links.html.erb +++ b/app/views/devise/shared/_links.html.erb @@ -5,6 +5,12 @@ <% end %> + <% if !SELF_HOSTED && devise_mapping&.registerable? && controller_name != 'registrations' %> +