Allow sharing digest for 1 week or 1 month

This commit is contained in:
Eugene Burmakin 2025-12-27 23:03:31 +01:00
parent 230e641808
commit df26984777
13 changed files with 56 additions and 51 deletions

View file

@ -68,12 +68,14 @@ class Stat < ApplicationRecord
def enable_sharing!(expiration: '1h') def enable_sharing!(expiration: '1h')
# Default to 24h if an invalid expiration is provided # Default to 24h if an invalid expiration is provided
expiration = '24h' unless %w[1h 12h 24h].include?(expiration) expiration = '24h' unless %w[1h 12h 24h 1w 1m].include?(expiration)
expires_at = case expiration expires_at = case expiration
when '1h' then 1.hour.from_now when '1h' then 1.hour.from_now
when '12h' then 12.hours.from_now when '12h' then 12.hours.from_now
when '24h' then 24.hours.from_now when '24h' then 24.hours.from_now
when '1w' then 1.week.from_now
when '1m' then 1.month.from_now
end end
update!( update!(

View file

@ -46,12 +46,14 @@ class Users::Digest < ApplicationRecord
end end
def enable_sharing!(expiration: '24h') def enable_sharing!(expiration: '24h')
expiration = '24h' unless %w[1h 12h 24h].include?(expiration) expiration = '24h' unless %w[1h 12h 24h 1w 1m].include?(expiration)
expires_at = case expiration expires_at = case expiration
when '1h' then 1.hour.from_now when '1h' then 1.hour.from_now
when '12h' then 12.hours.from_now when '12h' then 12.hours.from_now
when '24h' then 24.hours.from_now when '24h' then 24.hours.from_now
when '1w' then 1.week.from_now
when '1m' then 1.month.from_now
end end
update!( update!(
@ -127,7 +129,7 @@ class Users::Digest < ApplicationRecord
end end
def total_distance_all_time def total_distance_all_time
all_time_stats['total_distance'] || 0 (all_time_stats['total_distance'] || 0).to_i
end end
def distance_km def distance_km

View file

@ -76,12 +76,12 @@ module Users
result = {} result = {}
monthly_stats.each do |stat| monthly_stats.each do |stat|
result[stat.month.to_s] = stat.distance result[stat.month.to_s] = stat.distance.to_s
end end
# Fill in missing months with 0 # Fill in missing months with 0
(1..12).each do |month| (1..12).each do |month|
result[month.to_s] ||= 0 result[month.to_s] ||= '0'
end end
result result
@ -131,7 +131,7 @@ module Users
{ {
'total_countries' => user.countries_visited.count, 'total_countries' => user.countries_visited.count,
'total_cities' => user.cities_visited.count, 'total_cities' => user.cities_visited.count,
'total_distance' => user.stats.sum(:distance) 'total_distance' => user.stats.sum(:distance).to_s
} }
end end
end end

View file

@ -43,7 +43,9 @@
<%= options_for_select([ <%= options_for_select([
['1 hour', '1h'], ['1 hour', '1h'],
['12 hours', '12h'], ['12 hours', '12h'],
['24 hours', '24h'] ['24 hours', '24h'],
['1 week', '1w'],
['1 month', '1m']
], @stat&.sharing_settings&.dig('expiration') || '1h') %> ], @stat&.sharing_settings&.dig('expiration') || '1h') %>
</select> </select>
</div> </div>

View file

@ -27,8 +27,9 @@
<% if @digests.empty? %> <% if @digests.empty? %>
<div class="card bg-base-200 shadow-xl"> <div class="card bg-base-200 shadow-xl">
<div class="card-body text-center py-12"> <div class="card-body text-center py-12">
<div class="text-6xl mb-4"><%= icon 'earth' %></div> <h2 class="text-xl font-semibold mb-2 flex items-center justify-center gap-2">
<h2 class="text-xl font-semibold mb-2">No Year-End Digests Yet</h2> <%= icon 'earth' %>No Year-End Digests Yet
</h2>
<p class="text-gray-500 mb-4"> <p class="text-gray-500 mb-4">
Year-end digests are automatically generated on January 1st each year. Year-end digests are automatically generated on January 1st each year.
<% if @available_years.any? && current_user.active? %> <% if @available_years.any? && current_user.active? %>

View file

@ -80,7 +80,7 @@
<div class="w-full h-48 bg-base-200 rounded-lg p-4 relative"> <div class="w-full h-48 bg-base-200 rounded-lg p-4 relative">
<%= column_chart( <%= column_chart(
@digest.monthly_distances.sort.map { |month, distance_meters| @digest.monthly_distances.sort.map { |month, distance_meters|
[Date::ABBR_MONTHNAMES[month.to_i], Users::Digest.convert_distance(distance_meters, @distance_unit).round] [Date::ABBR_MONTHNAMES[month.to_i], Users::Digest.convert_distance(distance_meters.to_i, @distance_unit).round]
}, },
height: '200px', height: '200px',
suffix: " #{@distance_unit}", suffix: " #{@distance_unit}",

View file

@ -102,7 +102,7 @@
<div class="w-full h-64 bg-base-100 rounded-lg p-4"> <div class="w-full h-64 bg-base-100 rounded-lg p-4">
<%= column_chart( <%= column_chart(
@digest.monthly_distances.sort.map { |month, distance_meters| @digest.monthly_distances.sort.map { |month, distance_meters|
[Date::ABBR_MONTHNAMES[month.to_i], Users::Digest.convert_distance(distance_meters, @distance_unit).round] [Date::ABBR_MONTHNAMES[month.to_i], Users::Digest.convert_distance(distance_meters.to_i, @distance_unit).round]
}, },
height: '250px', height: '250px',
suffix: " #{@distance_unit}", suffix: " #{@distance_unit}",
@ -262,8 +262,10 @@
<%= options_for_select([ <%= options_for_select([
['1 hour', '1h'], ['1 hour', '1h'],
['12 hours', '12h'], ['12 hours', '12h'],
['24 hours', '24h'] ['24 hours', '24h'],
], @digest&.sharing_settings&.dig('expiration') || '1h') %> ['1 week', '1w'],
['1 month', '1m']
], @digest&.sharing_settings&.dig('expiration') || '24h') %>
</select> </select>
</div> </div>

View file

@ -166,6 +166,12 @@
<p>Your journey, by the numbers</p> <p>Your journey, by the numbers</p>
</div> </div>
<div class="content">
<p>
Hi, this is Evgenii from Dawarich! Pretty wild journey last yeah, huh? Let's take a look back at all the places you explored in <strong><%= @digest.year %></strong>.
</p>
</div>
<div class="content"> <div class="content">
<!-- Distance Traveled --> <!-- Distance Traveled -->
<div class="stat-card"> <div class="stat-card">
@ -276,6 +282,12 @@
</div> </div>
</div> </div>
<div class="content">
<p>
You can open your digest for sharing on its page on Dawarich: <a href="<%= users_digest_url(year: @digest.year) %>"><%= users_digest_url(year: @digest.year) %></a>
</p>
</div>
<div class="footer"> <div class="footer">
<p>Powered by <a href="https://dawarich.app">Dawarich</a>, your personal location history.</p> <p>Powered by <a href="https://dawarich.app">Dawarich</a>, your personal location history.</p>
<p class="unsubscribe"> <p class="unsubscribe">

View file

@ -1,9 +1,7 @@
<%= @digest.year %> Year in Review <%= @digest.year %> Year in Review
==================================== ====================================
Hi <%= @user.email %>, Hi, this is Evgenii from Dawarich! Pretty wild journey last year, huh? Let's take a look back at all the places you explored in <%= @digest.year %>.
Here's your year in review!
DISTANCE TRAVELED DISTANCE TRAVELED
<%= distance_with_unit(@digest.distance, @distance_unit) %> <%= distance_with_unit(@digest.distance, @distance_unit) %>
@ -34,6 +32,8 @@ ALL-TIME STATS
- <%= @digest.total_cities_all_time %> cities explored - <%= @digest.total_cities_all_time %> cities explored
- <%= distance_with_unit(@digest.total_distance_all_time, @distance_unit) %> traveled - <%= distance_with_unit(@digest.total_distance_all_time, @distance_unit) %> traveled
Keep exploring, keep discovering. Here's to even more adventures in <%= @digest.year + 1 %>!
-- --
Powered by Dawarich Powered by Dawarich
https://dawarich.app https://dawarich.app

View file

@ -1,16 +0,0 @@
# frozen_string_literal: true
class ChangeDigestsDistanceToBigint < ActiveRecord::Migration[8.0]
# Safe: digests table is new with minimal data
disable_ddl_transaction!
def change
if respond_to?(:safety_assured)
safety_assured do
change_column :digests, :distance, :bigint, null: false, default: 0
end
else
change_column :digests, :distance, :bigint, null: false, default: 0
end
end
end

4
db/schema.rb generated
View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_12_27_193242) do ActiveRecord::Schema[8.0].define(version: 2025_12_27_000001) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql" enable_extension "pg_catalog.plpgsql"
enable_extension "postgis" enable_extension "postgis"
@ -84,7 +84,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_12_27_193242) do
t.bigint "user_id", null: false t.bigint "user_id", null: false
t.integer "year", null: false t.integer "year", null: false
t.integer "period_type", default: 0, null: false t.integer "period_type", default: 0, null: false
t.bigint "distance", default: 0, null: false t.integer "distance", default: 0, null: false
t.jsonb "toponyms", default: {} t.jsonb "toponyms", default: {}
t.jsonb "monthly_distances", default: {} t.jsonb "monthly_distances", default: {}
t.jsonb "time_spent_by_location", default: {} t.jsonb "time_spent_by_location", default: {}

View file

@ -28,18 +28,18 @@ FactoryBot.define do
monthly_distances do monthly_distances do
{ {
'1' => 50_000, '1' => '50000',
'2' => 45_000, '2' => '45000',
'3' => 60_000, '3' => '60000',
'4' => 55_000, '4' => '55000',
'5' => 40_000, '5' => '40000',
'6' => 35_000, '6' => '35000',
'7' => 30_000, '7' => '30000',
'8' => 45_000, '8' => '45000',
'9' => 50_000, '9' => '50000',
'10' => 40_000, '10' => '40000',
'11' => 25_000, '11' => '25000',
'12' => 25_000 '12' => '25000'
} }
end end
@ -78,7 +78,7 @@ FactoryBot.define do
{ {
'total_countries' => 10, 'total_countries' => 10,
'total_cities' => 45, 'total_cities' => 45,
'total_distance' => 2_500_000 'total_distance' => '2500000'
} }
end end

View file

@ -71,9 +71,9 @@ RSpec.describe Users::Digests::CalculateYear do
end end
it 'builds monthly distances' do it 'builds monthly distances' do
expect(calculate_digest.monthly_distances['1']).to eq(50_000) expect(calculate_digest.monthly_distances['1']).to eq('50000')
expect(calculate_digest.monthly_distances['2']).to eq(75_000) expect(calculate_digest.monthly_distances['2']).to eq('75000')
expect(calculate_digest.monthly_distances['3']).to eq(0) # Missing month expect(calculate_digest.monthly_distances['3']).to eq('0') # Missing month
end end
it 'calculates time spent by location' do it 'calculates time spent by location' do
@ -86,7 +86,7 @@ RSpec.describe Users::Digests::CalculateYear do
end end
it 'calculates all time stats' do it 'calculates all time stats' do
expect(calculate_digest.all_time_stats['total_distance']).to eq(125_000) expect(calculate_digest.all_time_stats['total_distance']).to eq('125000')
end end
context 'when digest already exists' do context 'when digest already exists' do