Skip to content

Commit 758b31d

Browse files
authored
Merge pull request #1666 from Freika/dev
0.30.10
2 parents 4e75943 + 001d294 commit 758b31d

34 files changed

+2595
-152
lines changed

.app_version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.30.9
1+
0.30.10

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

7+
# [0.30.10] - 2025-08-22
8+
9+
## Added
10+
11+
- `POST /api/v1/visits` endpoint.
12+
- User now can create visits manually on the map.
13+
- User can now delete a visit by clicking on the delete button in the visit popup.
14+
- Import failure now throws an internal server error.
15+
16+
## Changed
17+
18+
- Source of imports is now being detected automatically.
19+
720

821
# [0.30.9] - 2025-08-19
922

app/assets/builds/tailwind.css

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/assets/stylesheets/application.tailwind.css

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,40 @@
3333
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
3434
}
3535

36+
/* Add Visit Marker Styles */
37+
.add-visit-marker {
38+
display: flex !important;
39+
align-items: center;
40+
justify-content: center;
41+
font-size: 20px;
42+
background: white;
43+
border: 2px solid #007bff;
44+
border-radius: 50%;
45+
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.3);
46+
animation: pulse-visit 2s infinite;
47+
}
48+
49+
@keyframes pulse-visit {
50+
0% {
51+
transform: scale(1);
52+
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.3);
53+
}
54+
50% {
55+
transform: scale(1.1);
56+
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.5);
57+
}
58+
100% {
59+
transform: scale(1);
60+
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.3);
61+
}
62+
}
63+
64+
/* Visit Form Popup Styles */
65+
.visit-form-popup .leaflet-popup-content-wrapper {
66+
border-radius: 8px;
67+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
68+
}
69+
3670
.leaflet-right-panel.controls-shifted {
3771
right: 310px;
3872
}

app/controllers/api/v1/visits_controller.rb

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ def index
1010
render json: serialized_visits
1111
end
1212

13+
def create
14+
service = Visits::Create.new(current_api_user, visit_params)
15+
16+
result = service.call
17+
18+
if result
19+
render json: Api::VisitSerializer.new(service.visit).call
20+
else
21+
error_message = service.errors || 'Failed to create visit'
22+
render json: { error: error_message }, status: :unprocessable_entity
23+
end
24+
end
25+
1326
def update
1427
visit = current_api_user.visits.find(params[:id])
1528
visit = update_visit(visit)
@@ -62,10 +75,25 @@ def bulk_update
6275
end
6376
end
6477

78+
def destroy
79+
visit = current_api_user.visits.find(params[:id])
80+
81+
if visit.destroy
82+
head :no_content
83+
else
84+
render json: {
85+
error: 'Failed to delete visit',
86+
errors: visit.errors.full_messages
87+
}, status: :unprocessable_entity
88+
end
89+
rescue ActiveRecord::RecordNotFound
90+
render json: { error: 'Visit not found' }, status: :not_found
91+
end
92+
6593
private
6694

6795
def visit_params
68-
params.require(:visit).permit(:name, :place_id, :status)
96+
params.require(:visit).permit(:name, :place_id, :status, :latitude, :longitude, :started_at, :ended_at)
6997
end
7098

7199
def merge_params
@@ -78,6 +106,8 @@ def bulk_update_params
78106

79107
def update_visit(visit)
80108
visit_params.each do |key, value|
109+
next if %w[latitude longitude].include?(key.to_s)
110+
81111
visit[key] = value
82112
visit.name = visit.place.name if visit_params[:place_id].present?
83113
end

app/controllers/imports_controller.rb

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ def create
4343
raw_files = Array(files_params).reject(&:blank?)
4444

4545
if raw_files.empty?
46-
redirect_to new_import_path, alert: 'No files were selected for upload', status: :unprocessable_entity
47-
return
46+
redirect_to new_import_path, alert: 'No files were selected for upload', status: :unprocessable_entity and return
4847
end
4948

5049
created_imports = []
@@ -59,11 +58,11 @@ def create
5958
if created_imports.any?
6059
redirect_to imports_url,
6160
notice: "#{created_imports.size} files are queued to be imported in background",
62-
status: :see_other
61+
status: :see_other and return
6362
else
6463
redirect_to new_import_path,
6564
alert: 'No valid file references were found. Please upload files using the file selector.',
66-
status: :unprocessable_entity
65+
status: :unprocessable_entity and return
6766
end
6867
rescue StandardError => e
6968
if created_imports.present?
@@ -95,26 +94,37 @@ def authorize_import
9594
end
9695

9796
def import_params
98-
params.require(:import).permit(:name, :source, files: [])
97+
params.require(:import).permit(:name, files: [])
9998
end
10099

101100
def create_import_from_signed_id(signed_id)
102101
Rails.logger.debug "Creating import from signed ID: #{signed_id[0..20]}..."
103102

104103
blob = ActiveStorage::Blob.find_signed(signed_id)
105104

106-
import = current_user.imports.build(
107-
name: blob.filename.to_s,
108-
source: params[:import][:source]
109-
)
110-
105+
import = current_user.imports.build(name: blob.filename.to_s)
111106
import.file.attach(blob)
107+
import.source = detect_import_source(import.file) if import.source.blank?
112108

113109
import.save!
114110

115111
import
116112
end
117113

114+
def detect_import_source(file_attachment)
115+
temp_file_path = Imports::SecureFileDownloader.new(file_attachment).download_to_temp_file
116+
117+
Imports::SourceDetector.new_from_file_header(temp_file_path).detect_source
118+
rescue StandardError => e
119+
Rails.logger.warn "Failed to auto-detect import source for #{file_attachment.filename}: #{e.message}"
120+
nil
121+
ensure
122+
# Cleanup temp file
123+
if temp_file_path && File.exist?(temp_file_path)
124+
File.unlink(temp_file_path)
125+
end
126+
end
127+
118128
def validate_points_limit
119129
limit_exceeded = PointsLimitExceeded.new(current_user).call
120130

app/javascript/application.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
22

3-
import "@rails/ujs"
43
import "@rails/actioncable"
54
import "controllers"
65
import "@hotwired/turbo-rails"

0 commit comments

Comments
 (0)