diff --git a/app/controllers/api/v1/owntracks/points_controller.rb b/app/controllers/api/v1/owntracks/points_controller.rb index 6f97cfe9..9dc8cbe9 100644 --- a/app/controllers/api/v1/owntracks/points_controller.rb +++ b/app/controllers/api/v1/owntracks/points_controller.rb @@ -7,7 +7,9 @@ class Api::V1::Owntracks::PointsController < ApiController def create Owntracks::PointCreatingJob.perform_later(point_params, current_api_user.id) - render json: {}, status: :ok + family_locations = OwnTracks::FamilyLocationsFormatter.new(current_api_user).call + + render json: family_locations, status: :ok end private diff --git a/app/services/own_tracks/family_locations_formatter.rb b/app/services/own_tracks/family_locations_formatter.rb new file mode 100644 index 00000000..f25aa955 --- /dev/null +++ b/app/services/own_tracks/family_locations_formatter.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +class OwnTracks::FamilyLocationsFormatter + attr_reader :user + + def initialize(user) + @user = user + end + + def call + return [] unless family_feature_enabled? + return [] unless user.in_family? + + sharing_members = family_members_with_sharing_enabled + return [] unless sharing_members.any? + + latest_points = sharing_members.map { |member| member.points.order(timestamp: :desc).first }.compact + latest_points.map { |point| build_owntracks_location(point) }.compact + end + + private + + def family_feature_enabled? + DawarichSettings.family_feature_enabled? + end + + def family_members_with_sharing_enabled + user.family.members + .where.not(id: user.id) + .select(&:family_sharing_enabled?) + end + + def build_owntracks_location(point) + location = { + _type: 'location', + lat: point.lat.to_f, + lon: point.lon.to_f, + tst: point.timestamp.to_i, + tid: point.user.email, + acc: point.accuracy, + alt: point.altitude, + batt: point.battery, + bs: OwnTracks::Params.battery_status_to_numeric(point.battery_status), + vel: OwnTracks::Params.velocity_to_kmh(point.velocity), + conn: OwnTracks::Params.connection_to_string(point.connection), + } + + location + end +end + diff --git a/app/services/own_tracks/params.rb b/app/services/own_tracks/params.rb index 838af33a..7f5c2d1f 100644 --- a/app/services/own_tracks/params.rb +++ b/app/services/own_tracks/params.rb @@ -90,4 +90,37 @@ class OwnTracks::Params def valid_point? params[:lon].present? && params[:lat].present? && params[:tst].present? end + + # Reverse conversion methods: from internal format to Owntracks format + class << self + def battery_status_to_numeric(battery_status) + case battery_status + when 'unknown' then 0 + when 'unplugged' then 1 + when 'charging' then 2 + when 'full' then 3 + else 0 + end + end + + def connection_to_string(connection) + case connection + when 'mobile' then 'm' + when 'wifi' then 'w' + when 'offline' then 'o' + else nil + end + end + + def velocity_to_kmh(velocity) + return nil if velocity.blank? + + # Try to parse as float + velocity_float = velocity.to_f + return nil if velocity_float.zero? + + # Reference: https://owntracks.org/booklet/tech/json/ + (velocity_float * 3.6).round.to_i + end + end end