koalagator 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/app/assets/stylesheets/calagator/layout.scss +4 -0
- data/app/controllers/calagator/admin/bulk_imports_controller.rb +37 -0
- data/app/controllers/calagator/events_controller.rb +10 -0
- data/app/controllers/calagator/venues_controller.rb +1 -0
- data/app/controllers/paper_trail_manager/changes_controller.rb +5 -5
- data/app/helpers/calagator/application_helper.rb +2 -2
- data/app/helpers/calagator/events_helper.rb +2 -1
- data/app/models/calagator/bulk_import.rb +59 -0
- data/app/models/calagator/curation.rb +1 -0
- data/app/models/calagator/event.rb +7 -2
- data/app/models/calagator/venue.rb +1 -0
- data/app/views/calagator/admin/bulk_imports/new.html.erb +34 -0
- data/app/views/calagator/admin/index.html.erb +2 -0
- data/app/views/calagator/events/_table.html.erb +14 -9
- data/app/views/calagator/events/_tabular.html.erb +59 -0
- data/app/views/calagator/events/_tabular_table.html.erb +82 -0
- data/app/views/calagator/events/tabular.html.erb +22 -0
- data/app/views/paper_trail_manager/changes/index.atom.builder +1 -1
- data/config/routes.rb +2 -0
- data/db/seeds.rb +1 -1
- data/lib/calagator/decode_html_entities_hack.rb +2 -0
- data/lib/calagator/import_events_csv.rb +123 -0
- data/lib/calagator/version.rb +2 -2
- data/lib/koalagator.rb +1 -1
- metadata +129 -54
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff66a4e6b8b4b8d8d8ec7380366f00970a540e62a3151989b5a38436b2405a32
|
|
4
|
+
data.tar.gz: b1fff8d25d098776ead6e5485c18c064a9466bfb59ef43b17b0b4387391bd112
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19a313f77215a0546e97cee14916c5b5d5f14c11eaa081abff80fa721eebc8be19f3d8a2f6f0eb71e8b1b4c29d8bcac43133e376ee2708ac5cee59a8a7dadfa6
|
|
7
|
+
data.tar.gz: 1416ae2d0f5f30eb0d44c829cffd29fc081e22160c5cba1934c6cc0852657e7bb39bdd5b998c5e5a8f3c63e03e99f8e9646203ae797b0a3f1bf883112249eb84
|
data/README.md
CHANGED
|
@@ -17,6 +17,8 @@ Thank you to everyone who contributed to the original calagator project (you're
|
|
|
17
17
|
We appreciate the encouragment from the ruby community for us to undertaking a revivial of this project.
|
|
18
18
|
Koalagator is a hard community fork of calagator. We've upgraded the project from Rails 4.2 to Rails 7.1 as part of this revival.
|
|
19
19
|
|
|
20
|
+
See also our [Koalagator Browser Extension for Firefox/Chrome](https://github.com/koalagator/koalagator-browser-extension) it supports most major event sites and enables quick and easy one-click adding of events to your instance.
|
|
21
|
+
|
|
20
22
|
About the revival
|
|
21
23
|
-----------------
|
|
22
24
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "csv"
|
|
4
|
+
require "calagator/import_events_csv"
|
|
5
|
+
|
|
6
|
+
module Calagator
|
|
7
|
+
module Admin
|
|
8
|
+
class BulkImportsController < Calagator::ApplicationController
|
|
9
|
+
require_admin
|
|
10
|
+
|
|
11
|
+
def new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
# example code via: https://guides.rubyonrails.org/form_helpers.html#uploading-files
|
|
16
|
+
|
|
17
|
+
@uploaded_file = params[:csv_file]
|
|
18
|
+
|
|
19
|
+
if @uploaded_file.present?
|
|
20
|
+
csv_data = CSV.parse(@uploaded_file.read, headers: true)
|
|
21
|
+
@bulk_import = Calagator::BulkImport.new(csv_data)
|
|
22
|
+
@bulk_import.process_csv_file(csv_data)
|
|
23
|
+
else
|
|
24
|
+
Rails.logger.info "upload_file not present"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
respond_to do |format|
|
|
28
|
+
if @bulk_import&.errors&.empty?
|
|
29
|
+
format.html { redirect_to events_path(order: "created_at"), notice: "Successfully imported all records." }
|
|
30
|
+
else
|
|
31
|
+
format.html { render :new, status: :unprocessable_entity }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -8,6 +8,7 @@ module Calagator
|
|
|
8
8
|
class EventsController < Calagator::ApplicationController
|
|
9
9
|
# Provides #duplicates and #squash_many_duplicates
|
|
10
10
|
include Calagator::DuplicateChecking::ControllerActions
|
|
11
|
+
|
|
11
12
|
require_admin only: %i[duplicates squash_many_duplicates]
|
|
12
13
|
|
|
13
14
|
authorize_resource :events, only: %i[new edit create update destroy clone]
|
|
@@ -24,6 +25,15 @@ module Calagator
|
|
|
24
25
|
render_events @events
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
# GET /events/tabular
|
|
29
|
+
# GET /events/tabular.xml
|
|
30
|
+
def tabular
|
|
31
|
+
@browse = Event::Browse.new(params)
|
|
32
|
+
@events = @browse.events
|
|
33
|
+
@browse.errors.each { |error| append_flash :failure, error }
|
|
34
|
+
render_events @events
|
|
35
|
+
end
|
|
36
|
+
|
|
27
37
|
# GET /events/1
|
|
28
38
|
# GET /events/1.xml
|
|
29
39
|
def show
|
|
@@ -6,6 +6,7 @@ module Calagator
|
|
|
6
6
|
class VenuesController < Calagator::ApplicationController
|
|
7
7
|
# Provides #duplicates and #squash_many_duplicates
|
|
8
8
|
include DuplicateChecking::ControllerActions
|
|
9
|
+
|
|
9
10
|
require_admin only: %i[duplicates squash_many_duplicates]
|
|
10
11
|
|
|
11
12
|
authorize_resource :venues, only: %i[new edit create update destroy]
|
|
@@ -16,7 +16,7 @@ class PaperTrailManager
|
|
|
16
16
|
def index
|
|
17
17
|
unless change_index_allowed?
|
|
18
18
|
flash[:error] = "You do not have permission to list changes."
|
|
19
|
-
return
|
|
19
|
+
return redirect_to root_url
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
@versions = PaperTrail::Version.order("created_at DESC, id DESC")
|
|
@@ -49,12 +49,12 @@ class PaperTrailManager
|
|
|
49
49
|
@version = PaperTrail::Version.find(params[:id])
|
|
50
50
|
rescue ActiveRecord::RecordNotFound
|
|
51
51
|
flash[:error] = "No such version."
|
|
52
|
-
return
|
|
52
|
+
return redirect_to action: :index
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
unless change_show_allowed?(@version)
|
|
56
56
|
flash[:error] = "You do not have permission to show that change."
|
|
57
|
-
return
|
|
57
|
+
return redirect_to action: :index
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
respond_to do |format|
|
|
@@ -69,12 +69,12 @@ class PaperTrailManager
|
|
|
69
69
|
@version = PaperTrail::Version.find(params[:id])
|
|
70
70
|
rescue ActiveRecord::RecordNotFound
|
|
71
71
|
flash[:error] = "No such version."
|
|
72
|
-
return
|
|
72
|
+
return redirect_to(changes_path)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
unless change_revert_allowed?(@version)
|
|
76
76
|
flash[:error] = "You do not have permission to revert this change."
|
|
77
|
-
return
|
|
77
|
+
return redirect_to changes_path
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
if @version.event == "create"
|
|
@@ -15,7 +15,7 @@ module Calagator
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def markdown(text)
|
|
18
|
-
|
|
18
|
+
Kramdown::Document.new(text).to_html.rstrip
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# Return a HTML string with the BR tags converted to XHTML compliant markup.
|
|
@@ -45,7 +45,7 @@ module Calagator
|
|
|
45
45
|
next if flash[type].blank?
|
|
46
46
|
|
|
47
47
|
content_tag(:div, class: "flash #{type} flash_#{type}") do
|
|
48
|
-
"#{
|
|
48
|
+
"#{"ERROR: " if type == :failure}#{flash[type]}".html_safe
|
|
49
49
|
end
|
|
50
50
|
end.compact.join.html_safe
|
|
51
51
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Calagator
|
|
2
|
+
class BulkImport
|
|
3
|
+
def initialize(csv_data)
|
|
4
|
+
@csv_data = csv_data
|
|
5
|
+
@errors = []
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
attr_reader :errors
|
|
9
|
+
|
|
10
|
+
def process_csv_file(csv_data)
|
|
11
|
+
@errors = []
|
|
12
|
+
processed_events = csv_data.each.with_index(2).map { |row, index| process_row(row, index) }
|
|
13
|
+
return false if @errors.any?
|
|
14
|
+
processed_events.map { |event| event.save }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def process_row(row, index)
|
|
18
|
+
venue = set_venue(row["venue"])
|
|
19
|
+
event = Calagator::Event.new(
|
|
20
|
+
title: row["title"],
|
|
21
|
+
venue_id: venue&.id,
|
|
22
|
+
url: row["url"],
|
|
23
|
+
start_time: set_event_at(row["event_start_at"]),
|
|
24
|
+
end_time: set_event_at(row["event_end_at"]),
|
|
25
|
+
description: row["description"],
|
|
26
|
+
venue_details: row["venue_details"],
|
|
27
|
+
tag_list: row["event_tag_list"]
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if Calagator::Event.find_duplicate(event.title, event.start_time, event.end_time, venue).any?
|
|
31
|
+
return @errors << "Row #{index}: 'Duplicate of an existing event.'"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if event.valid?
|
|
35
|
+
event
|
|
36
|
+
else
|
|
37
|
+
@errors << "Row #{index}: #{event.errors.full_messages}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def set_event_at(value)
|
|
42
|
+
return "" unless value.present?
|
|
43
|
+
Time.strptime value, "%d/%m/%Y %H:%M:%S"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def set_venue(value)
|
|
47
|
+
return "" unless value.present?
|
|
48
|
+
value_s = value.to_s
|
|
49
|
+
value_i = value_s.to_i
|
|
50
|
+
target_venue = if value_s.match?(/^\s*\d+\s*$/) && value_i > 0
|
|
51
|
+
Calagator::Venue.find_by(id: value_i)
|
|
52
|
+
else
|
|
53
|
+
Calagator::Venue.search(value_s, limit: 1).first
|
|
54
|
+
end
|
|
55
|
+
Rails.logger.info "set_venue.target_venue #{target_venue}"
|
|
56
|
+
target_venue
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -53,7 +53,7 @@ module Calagator
|
|
|
53
53
|
has_paper_trail
|
|
54
54
|
acts_as_taggable_on :tags
|
|
55
55
|
|
|
56
|
-
xss_foliate strip: %i[title description venue_details]
|
|
56
|
+
# xss_foliate strip: %i[title description venue_details]
|
|
57
57
|
|
|
58
58
|
include DecodeHtmlEntitiesHack
|
|
59
59
|
include ActiveModel::Serializers::Xml
|
|
@@ -76,6 +76,7 @@ module Calagator
|
|
|
76
76
|
|
|
77
77
|
# Duplicates
|
|
78
78
|
include DuplicateChecking
|
|
79
|
+
|
|
79
80
|
duplicate_checking_ignores_attributes :source_id, :version, :venue_id, :tag_list
|
|
80
81
|
duplicate_squashing_ignores_associations :tags, :base_tags, :taggings
|
|
81
82
|
duplicate_finding_scope -> { future.order(:id) }
|
|
@@ -100,7 +101,9 @@ module Calagator
|
|
|
100
101
|
end_date += 1.day if start_date == end_date
|
|
101
102
|
on_or_after_date(start_date).before_date(end_date)
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
+
scope :find_duplicate, ->(title, start_time, end_time, venue) {
|
|
105
|
+
includes(:venue).where(title: title, start_time: start_time, end_time: end_time, venue: venue)
|
|
106
|
+
}
|
|
104
107
|
# Expand the simple sort order names from the URL into more intelligent SQL order strings
|
|
105
108
|
scope :ordered_by_ui_field, lambda { |ui_field|
|
|
106
109
|
scope = case ui_field
|
|
@@ -108,6 +111,8 @@ module Calagator
|
|
|
108
111
|
order(Arel.sql("lower(events.title)"))
|
|
109
112
|
when "venue"
|
|
110
113
|
includes(:venue).order(Arel.sql("lower(venues.title)")).references(:venues)
|
|
114
|
+
when "created_at"
|
|
115
|
+
return order(created_at: :desc)
|
|
111
116
|
else
|
|
112
117
|
all
|
|
113
118
|
end
|
|
@@ -79,6 +79,7 @@ module Calagator
|
|
|
79
79
|
|
|
80
80
|
# Duplicates
|
|
81
81
|
include DuplicateChecking
|
|
82
|
+
|
|
82
83
|
duplicate_checking_ignores_attributes :source_id, :version, :closed, :wifi, :access_notes, :tag_list
|
|
83
84
|
duplicate_squashing_ignores_associations :tags, :base_tags, :taggings
|
|
84
85
|
duplicate_finding_scope -> { non_duplicates.order(:title, :id) }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<% if @bulk_import && @bulk_import&.errors.any? %>
|
|
2
|
+
<div style="color: red">
|
|
3
|
+
<h2><%= pluralize(@bulk_import&.errors.count, "error") %> in '<code><%= @uploaded_file.original_filename %></code>' prohibited this import from being saved:</h2>
|
|
4
|
+
|
|
5
|
+
<ul>
|
|
6
|
+
<% @bulk_import&.errors.each do |error| %>
|
|
7
|
+
<li><%= error %></li>
|
|
8
|
+
<% end %>
|
|
9
|
+
</ul>
|
|
10
|
+
</div>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<h1>Bulk Imports</h1>
|
|
14
|
+
|
|
15
|
+
<p>This feature supports bulk importing of events from a spreadsheet file</p>
|
|
16
|
+
<p>To work as expected the uploaded file needs to be in `.csv` format.</p>
|
|
17
|
+
<p>The header row in the csv file also needs to match our system defined field headings<p>
|
|
18
|
+
<p>We recommend you copy your spreadsheet data into this template, and upload the resultant file</p>
|
|
19
|
+
<p><%= link_to 'Koalagator Bulk Import Template v1.0', 'https://docs.google.com/spreadsheets/d/1QBGzaMjVCjUHQxQ3YIfX5Kivck2Rmow0IlyRAjDrbf4/edit?gid=0#gid=0' %></p>
|
|
20
|
+
<p>1. Open the Template. 2. File > 'Make a copy' 3. Copy paste your records in 4. Review and tidy up records for a clean import.</p>
|
|
21
|
+
<p>Once the sheet is ready. Download in .csv format by going: File > Download > Comma Separated Value (.csv)</p>
|
|
22
|
+
|
|
23
|
+
<p>The first version of this importer, will associate all events with a venue named 'TBA', for now its better than nothing.</p>
|
|
24
|
+
<p>Once imported you can go through each event and allocate to a real venue.</p>
|
|
25
|
+
|
|
26
|
+
<p>Drag and drop / attach your .csv file into the file area below: </p>
|
|
27
|
+
|
|
28
|
+
<div class="form-label"><h3>Upload Your Spreadsheet (.csv)</h3></div>
|
|
29
|
+
|
|
30
|
+
<%= form_with url: admin_bulk_imports_path, multipart: true do |form| %>
|
|
31
|
+
<%= file_field_tag :csv_file, accept:'.csv' %>
|
|
32
|
+
<br><br>
|
|
33
|
+
<%= form.submit "Upload attached File" %>
|
|
34
|
+
<% end %>
|
|
@@ -9,4 +9,6 @@
|
|
|
9
9
|
<li><%= link_to "Manage users", admin_users_path %></li>
|
|
10
10
|
<% end %>
|
|
11
11
|
<li><%= link_to "Manage curations", admin_curations_path %></li>
|
|
12
|
+
<li><%= link_to "Tablular Events View - Designed for copy/paste into an external newsletter", '/events/tabular' %></li>
|
|
13
|
+
<li><%= link_to "Bulk Import from CSV File", new_admin_bulk_import_path %></li>
|
|
12
14
|
</ul>
|
|
@@ -20,7 +20,8 @@ rowspans = calculate_rowspans(events)
|
|
|
20
20
|
<th class='date'>Sort By: <%= link_to "Date", url_for(params.to_unsafe_h.merge(:order => 'date')) %></th>
|
|
21
21
|
<th class='event_summary'>
|
|
22
22
|
<%= events_sort_link('name') -%>,
|
|
23
|
-
<%= events_sort_link('venue')
|
|
23
|
+
<%= events_sort_link('venue') -%>,
|
|
24
|
+
<%= events_sort_link('created_at') -%>
|
|
24
25
|
<%- if scores -%>,
|
|
25
26
|
<%= events_sort_link('score') -%>
|
|
26
27
|
<%- end -%>,
|
|
@@ -33,16 +34,20 @@ rowspans = calculate_rowspans(events)
|
|
|
33
34
|
<% events.each_with_index do |event, index| %>
|
|
34
35
|
<tr class='vevent h-event'>
|
|
35
36
|
<% if rowspans[index] > 0 %>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
<td class='date' rowspan="<%=rowspans[index]%>">
|
|
38
|
+
<div class='day_of_week <%= today_tomorrow_or_weekday(event).downcase -%>'>
|
|
39
|
+
<%= today_tomorrow_or_weekday(event) %>
|
|
40
|
+
</div>
|
|
41
|
+
<% show_year = event.start_time.year != Time.now.year %>
|
|
42
|
+
<%= datetime_format(event.start_time,'%b %d') -%><%= ", "+datetime_format(event.start_time,'%Y') if show_year %>
|
|
43
|
+
</td>
|
|
43
44
|
<% end %>
|
|
44
45
|
<td class='event_summary'>
|
|
45
|
-
|
|
46
|
+
<%= link_to event.title, event, class: "summary p-name u-url #{'orange' if event.created_at.to_date == Date.today}",
|
|
47
|
+
id: "event-#{event.id}",
|
|
48
|
+
name: "event-#{event.id}",
|
|
49
|
+
title: "Added #{event.created_at}"
|
|
50
|
+
%>
|
|
46
51
|
<%= normalize_time(event, :context => event.start_time.to_date) -%>
|
|
47
52
|
<% if event.venue && !event.venue.title.blank? %>
|
|
48
53
|
<a class='location p-location h-card' href='<%= url_for venue_url(event.venue) %>'><%= event.venue.title -%></a>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<% links ||= {} %>
|
|
2
|
+
<div class='list_description'>
|
|
3
|
+
<h2>Viewing <strong><%= browse.events.size %></strong>
|
|
4
|
+
<%= browse.date ? 'filtered' : 'future' %> events
|
|
5
|
+
<%= events_sort_label(browse.order) %></h2>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div id='list_filters' class='sidebar'>
|
|
9
|
+
|
|
10
|
+
<h3 class='first'>Filter:</h3>
|
|
11
|
+
|
|
12
|
+
<%= form_tag events_url, :method => 'get' do -%>
|
|
13
|
+
|
|
14
|
+
<div id="date_filter">
|
|
15
|
+
<h4>by date</h4>
|
|
16
|
+
<div id='start_calendar'>
|
|
17
|
+
<label for='date_start'>From</label>
|
|
18
|
+
<%= text_field_tag 'date[start]', browse.start_date, :id => 'date_start', :class => 'date_picker' %>
|
|
19
|
+
</div>
|
|
20
|
+
<div id='end_calendar'>
|
|
21
|
+
<label for='date_end'>To</label>
|
|
22
|
+
<%= text_field_tag 'date[end]', browse.end_date, :id => 'date_end', :class => 'date_picker' %>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<div id='time_filter'>
|
|
26
|
+
<h4>by time</h4>
|
|
27
|
+
<div id='start_time_picker'>
|
|
28
|
+
<label for="time_start">Begins after:</label>
|
|
29
|
+
<%= text_field_tag 'time[start]', browse.start_time, :id => 'filter_time_start', :class => 'time_picker_filter' %>
|
|
30
|
+
</div>
|
|
31
|
+
<div id='end_time_picker'>
|
|
32
|
+
<label for="time_end">Ends before:</label>
|
|
33
|
+
<%= text_field_tag 'time[end]', browse.end_time, :id => 'filter_time_end', :class => 'time_picker_filter' %>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div>
|
|
37
|
+
<label for="commit"> </label>
|
|
38
|
+
<%= submit_tag 'Filter' %>
|
|
39
|
+
<span class="clear_filter"><%= link_to 'Reset', events_url %></span>
|
|
40
|
+
</div>
|
|
41
|
+
<% end %>
|
|
42
|
+
|
|
43
|
+
<h3>Subscribe to</h3>
|
|
44
|
+
<ul>
|
|
45
|
+
<li><%= link_to "iCalendar feed", links[:ical] %></li>
|
|
46
|
+
<li><%= link_to "Atom feed", links[:atom] %></li>
|
|
47
|
+
<li><%= link_to "Google Calendar", links[:google] %></li>
|
|
48
|
+
</ul>
|
|
49
|
+
|
|
50
|
+
<h3>Export to</h3>
|
|
51
|
+
<ul>
|
|
52
|
+
<li><%= link_to "iCalendar file", links[:ical_export] %></li>
|
|
53
|
+
</ul>
|
|
54
|
+
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class='list_items'>
|
|
58
|
+
<%= render :partial => 'calagator/events/tabular_table', :locals => { :events => browse.events } %>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<%-
|
|
2
|
+
# Arguments:
|
|
3
|
+
# * events => Array of Event records.
|
|
4
|
+
# * scores => Offer a sort by score, like for search? Default to false.
|
|
5
|
+
|
|
6
|
+
scores = defined?(scores) ? scores : false
|
|
7
|
+
|
|
8
|
+
previous_start_time = nil
|
|
9
|
+
#show_year ||= false
|
|
10
|
+
skipped = 0
|
|
11
|
+
|
|
12
|
+
# calculate rowspans array for events
|
|
13
|
+
# each entry is number of rows spanned by today_tomorrow_weekday entry, if any, to left of event
|
|
14
|
+
# entry will be > 0 for first event of day, 0 for other events
|
|
15
|
+
rowspans = calculate_rowspans(events)
|
|
16
|
+
-%>
|
|
17
|
+
<table class='event_table'>
|
|
18
|
+
<thead>
|
|
19
|
+
<tr>
|
|
20
|
+
<th class='date'>Sort By: <%= link_to "Date", url_for(params.to_unsafe_h.merge(:order => 'date')) %></th>
|
|
21
|
+
<th class='event_summary'>
|
|
22
|
+
<%= events_sort_link('name') -%>,
|
|
23
|
+
<%= events_sort_link('venue') -%>,
|
|
24
|
+
<%= events_sort_link('created_at') -%>
|
|
25
|
+
<%- if scores -%>,
|
|
26
|
+
<%= events_sort_link('score') -%>
|
|
27
|
+
<%- end -%>,
|
|
28
|
+
<%= events_sort_link(nil) -%>
|
|
29
|
+
</th>
|
|
30
|
+
</tr>
|
|
31
|
+
</thead>
|
|
32
|
+
<tbody>
|
|
33
|
+
<% unless events.size==0 %>
|
|
34
|
+
<% events.each_with_index do |event, index| %>
|
|
35
|
+
<tr class='vevent h-event'>
|
|
36
|
+
<% if rowspans[index] > 0 %>
|
|
37
|
+
<td class='event_title rowspan="<%=rowspans[index]%>"'>
|
|
38
|
+
<%= link_to event.title, (event.url || event_url(event)),
|
|
39
|
+
class: "summary p-name u-url #{'orange' if event.created_at.to_date == Date.today}",
|
|
40
|
+
id: "event-#{event.id}",
|
|
41
|
+
name: "event-#{event.id}",
|
|
42
|
+
title: "Added #{event.created_at}"
|
|
43
|
+
%>
|
|
44
|
+
<%= " ".html_safe if event&.title&.blank? %>
|
|
45
|
+
<br/>
|
|
46
|
+
</td>
|
|
47
|
+
<td class='event_date'>
|
|
48
|
+
<div class='day_of_week <%= today_tomorrow_or_weekday(event).downcase -%>'>
|
|
49
|
+
<%= today_tomorrow_or_weekday(event) %>
|
|
50
|
+
<% show_year = event.start_time.year != Time.now.year %>
|
|
51
|
+
<%= datetime_format(event.start_time,'%b %d') -%><%= ", "+datetime_format(event.start_time,'%Y') if show_year %>
|
|
52
|
+
</div>
|
|
53
|
+
<%= normalize_time(event, :context => event.start_time.to_date) -%>
|
|
54
|
+
<%= " ".html_safe if event&.start_time&.blank? %>
|
|
55
|
+
</td>
|
|
56
|
+
<% end %>
|
|
57
|
+
<td class='event_location'>
|
|
58
|
+
<% if event.venue && !event.venue.title.blank? %>
|
|
59
|
+
<a class='location p-location h-card' href='<%= url_for venue_url(event.venue) %>'><%= event.venue.title %></a>
|
|
60
|
+
<% end -%>
|
|
61
|
+
<%= " ".html_safe if event&.venue&.blank? %>
|
|
62
|
+
</td>
|
|
63
|
+
<td class='event_summary'>
|
|
64
|
+
<%= format_description(event.description) %>
|
|
65
|
+
<%= " ".html_safe if event&.description&.blank? %>
|
|
66
|
+
</td>
|
|
67
|
+
</tr>
|
|
68
|
+
<% end %>
|
|
69
|
+
<% else %>
|
|
70
|
+
<tr>
|
|
71
|
+
<td colspan=2>No events were found.</td>
|
|
72
|
+
</tr>
|
|
73
|
+
<% end %>
|
|
74
|
+
<% if skipped > 0 %>
|
|
75
|
+
<tr>
|
|
76
|
+
<td colspan=2>
|
|
77
|
+
<%= link_to "(And #{skipped} more)", events_url %>
|
|
78
|
+
</td>
|
|
79
|
+
</tr>
|
|
80
|
+
<% end %>
|
|
81
|
+
</tbody>
|
|
82
|
+
</table>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<h1>Tabular Events</h1>
|
|
2
|
+
<p>This special events view has been added to support groups that want to copy/paste events into a newsletter or external publication.</p>
|
|
3
|
+
<p>Specifically it was first added to support a group that is proactivley adding multiple events from the community to then be able to pull this info back out in a useful format.</p>
|
|
4
|
+
<p>The events listing is split into four colummns: Title, Date Time, Venue and Description.</p>
|
|
5
|
+
<p>Note: Unlike elsewhere in the app, the venue title here links to the event website in the first instance.</p>
|
|
6
|
+
<p>If no website is included in the event record, the event title will link to the event record.</p>
|
|
7
|
+
<p>In this way end users of the listing of upcoming events will be linked directly to the event website where available.</p>
|
|
8
|
+
<p>The venue listed will always link to the instances venue record, such that accessibility details and directions are easily discoverable.</p>
|
|
9
|
+
<p>To copy/paste, select from the left hand side of Title the first record and drag until you are at the right hand side of the description of the last record.<p>
|
|
10
|
+
<p>Tip: Use the filter tool (right hand side) to narrow down the event dates before doing a copy/paste</p>
|
|
11
|
+
|
|
12
|
+
<%= content_for :title, "Events" %>
|
|
13
|
+
|
|
14
|
+
<% cache_if(@browse.default? && Calagator.cache_enabled, Calagator::CacheObserver.daily_key_for("events_index", request)) do %>
|
|
15
|
+
<%= render partial: "tabular", locals: {browse: @browse, links: {
|
|
16
|
+
ical: icalendar_feed_link,
|
|
17
|
+
atom: atom_feed_link,
|
|
18
|
+
google: google_events_subscription_link,
|
|
19
|
+
ical_export: icalendar_export_link
|
|
20
|
+
}}
|
|
21
|
+
%>
|
|
22
|
+
<% end %>
|
|
@@ -19,7 +19,7 @@ atom_feed do |feed|
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
entry.title "#{version.event.upcase} #{version.item_type} «#{change_title_for(version)}» #{
|
|
22
|
+
entry.title "#{version.event.upcase} #{version.item_type} «#{change_title_for(version)}» #{"by " + user.send(PaperTrailManager.whodunnit_name_method) if user}"
|
|
23
23
|
entry.updated version.created_at.utc.xmlschema
|
|
24
24
|
|
|
25
25
|
xm = ::Builder::XmlMarkup.new
|
data/config/routes.rb
CHANGED
|
@@ -33,6 +33,7 @@ Calagator::Engine.routes.draw do
|
|
|
33
33
|
|
|
34
34
|
namespace :admin do
|
|
35
35
|
resources :curations, except: :show
|
|
36
|
+
resources :bulk_imports
|
|
36
37
|
if Calagator.devise_enabled
|
|
37
38
|
resources :users do
|
|
38
39
|
get :invite, as: :invite
|
|
@@ -50,6 +51,7 @@ Calagator::Engine.routes.draw do
|
|
|
50
51
|
get :search
|
|
51
52
|
get :duplicates
|
|
52
53
|
get "tag/:tag", action: :search, as: :tag
|
|
54
|
+
get "tabular" => "events#tabular"
|
|
53
55
|
end
|
|
54
56
|
|
|
55
57
|
member do
|
data/db/seeds.rb
CHANGED
|
@@ -59,7 +59,7 @@ FactoryBot.define do
|
|
|
59
59
|
description { Faker::Lorem.paragraph }
|
|
60
60
|
start_time do
|
|
61
61
|
[
|
|
62
|
-
Faker::Time.between(from: 2.years.ago, to: 2.years.from_now),
|
|
62
|
+
Faker::Time.between(from: 2.years.ago, to: 2.years.from_now.to_datetime),
|
|
63
63
|
Faker::Time.backward(days: 1),
|
|
64
64
|
Faker::Time.forward(days: 1),
|
|
65
65
|
Faker::Time.forward(days: 7)
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
# Warning: this effectively renders loofah's "escape" scrubbing mode useless by
|
|
16
16
|
# undoing everything it does. Don't use that mode.
|
|
17
17
|
#
|
|
18
|
+
# TODO (2025): Review and remove if no longer needed
|
|
19
|
+
#
|
|
18
20
|
module Calagator
|
|
19
21
|
module DecodeHtmlEntitiesHack
|
|
20
22
|
def self.included(base)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require "smarter_csv"
|
|
2
|
+
|
|
3
|
+
module Calagator
|
|
4
|
+
class ImportEventsCsv
|
|
5
|
+
attr_reader :csv, :events
|
|
6
|
+
|
|
7
|
+
def initialize(input)
|
|
8
|
+
@csv = SmarterCSV::Reader.new(input,
|
|
9
|
+
col_sep: ",",
|
|
10
|
+
row_sep: "\n",
|
|
11
|
+
user_provided_headers: %i[title description venue start_date end_date tag_list])
|
|
12
|
+
@events = process_events
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def valid?
|
|
16
|
+
@valid
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def import!(allow_invalid: false)
|
|
20
|
+
events.each do |event|
|
|
21
|
+
if allow_invalid
|
|
22
|
+
event.import
|
|
23
|
+
else
|
|
24
|
+
event.import!
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private def process_events
|
|
30
|
+
event_list = []
|
|
31
|
+
|
|
32
|
+
@valid = true
|
|
33
|
+
csv.process do |row|
|
|
34
|
+
event = ImportedEvent.new(row.first)
|
|
35
|
+
@valid = false unless event.valid?
|
|
36
|
+
event_list << event
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
event_list
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class InvalidEventError < StandardError
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class ImportedEvent
|
|
46
|
+
attr_reader :data, :errors
|
|
47
|
+
attr_accessor :title, :description, :venue, :start_date, :end_date, :tag_list
|
|
48
|
+
|
|
49
|
+
def initialize(data)
|
|
50
|
+
@data = data
|
|
51
|
+
@errors = {}
|
|
52
|
+
|
|
53
|
+
set_title(data[:title])
|
|
54
|
+
set_description(data[:description])
|
|
55
|
+
set_venue(data[:venue])
|
|
56
|
+
set_start_date(data[:start_date])
|
|
57
|
+
set_end_date(data[:end_date])
|
|
58
|
+
set_tag_list(data[:tag_list])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def valid?
|
|
62
|
+
@errors.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def import
|
|
66
|
+
return false if !valid?
|
|
67
|
+
|
|
68
|
+
Calagator::Event.create(title: title, description: description, venue: venue, start_date: start_date, end_date: end_date, tag_list: tag_list)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def import!
|
|
72
|
+
result = import
|
|
73
|
+
raise InvalidEventError unless result
|
|
74
|
+
|
|
75
|
+
result
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def set_title(value)
|
|
81
|
+
return errors[:title] = "is empty" unless value.present?
|
|
82
|
+
|
|
83
|
+
@title = value.to_s
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def set_description(value)
|
|
87
|
+
@description = value.to_s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def set_venue(value)
|
|
91
|
+
return errors[:venue] = "is empty" unless value.present?
|
|
92
|
+
|
|
93
|
+
value_s = value.to_s
|
|
94
|
+
value_i = value_s.to_i
|
|
95
|
+
target_venue = if value_s.match?(/^\s*\d+\s*$/) && value_i > 0
|
|
96
|
+
Calagator::Venue.find_by(id: value_i)
|
|
97
|
+
else
|
|
98
|
+
Calagator::Venue.search(value_s, limit: 1).first
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
return errors[:venue] = "cannot be found" unless target_venue.present?
|
|
102
|
+
|
|
103
|
+
@venue = target_venue
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def set_start_date(value)
|
|
107
|
+
@start_date = Time.iso8601(value)
|
|
108
|
+
rescue
|
|
109
|
+
errors[:start_date] = "is not in ISO 8601 time format"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def set_end_date(value)
|
|
113
|
+
@end_date = Time.iso8601(value)
|
|
114
|
+
rescue
|
|
115
|
+
errors[:end_date] = "is not in ISO 8601 time format"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def set_tag_list(value)
|
|
119
|
+
@tag_list = value
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
data/lib/calagator/version.rb
CHANGED
data/lib/koalagator.rb
CHANGED
|
@@ -16,7 +16,6 @@ require "will_paginate/array"
|
|
|
16
16
|
require "rest-client"
|
|
17
17
|
require "loofah"
|
|
18
18
|
require "loofah-activerecord"
|
|
19
|
-
require "bluecloth"
|
|
20
19
|
require "acts-as-taggable-on"
|
|
21
20
|
require "jquery-rails"
|
|
22
21
|
require "jquery-ui-rails"
|
|
@@ -26,6 +25,7 @@ require "utf8-cleaner"
|
|
|
26
25
|
require "lucene_query"
|
|
27
26
|
require "rack/contrib/jsonp"
|
|
28
27
|
require "devise"
|
|
28
|
+
require "kramdown"
|
|
29
29
|
|
|
30
30
|
module Calagator
|
|
31
31
|
mattr_accessor :title,
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: koalagator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- the Koalagator team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-04-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 7.2.2
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 7.2.2
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: sprockets-rails
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,14 +58,14 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
61
|
+
version: '11.0'
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
68
|
+
version: '11.0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: annotate
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -86,34 +86,20 @@ dependencies:
|
|
|
86
86
|
- - "<"
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
88
|
version: 3.3.0
|
|
89
|
-
- !ruby/object:Gem::Dependency
|
|
90
|
-
name: bluecloth
|
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
|
92
|
-
requirements:
|
|
93
|
-
- - "~>"
|
|
94
|
-
- !ruby/object:Gem::Version
|
|
95
|
-
version: '2.2'
|
|
96
|
-
type: :runtime
|
|
97
|
-
prerelease: false
|
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
-
requirements:
|
|
100
|
-
- - "~>"
|
|
101
|
-
- !ruby/object:Gem::Version
|
|
102
|
-
version: '2.2'
|
|
103
89
|
- !ruby/object:Gem::Dependency
|
|
104
90
|
name: bootsnap
|
|
105
91
|
requirement: !ruby/object:Gem::Requirement
|
|
106
92
|
requirements:
|
|
107
93
|
- - "~>"
|
|
108
94
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '1.
|
|
95
|
+
version: '1.23'
|
|
110
96
|
type: :runtime
|
|
111
97
|
prerelease: false
|
|
112
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
99
|
requirements:
|
|
114
100
|
- - "~>"
|
|
115
101
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: '1.
|
|
102
|
+
version: '1.23'
|
|
117
103
|
- !ruby/object:Gem::Dependency
|
|
118
104
|
name: font-awesome-rails
|
|
119
105
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -146,36 +132,30 @@ dependencies:
|
|
|
146
132
|
name: geokit
|
|
147
133
|
requirement: !ruby/object:Gem::Requirement
|
|
148
134
|
requirements:
|
|
149
|
-
- - "
|
|
150
|
-
- !ruby/object:Gem::Version
|
|
151
|
-
version: '1.9'
|
|
152
|
-
- - "<"
|
|
135
|
+
- - "~>"
|
|
153
136
|
- !ruby/object:Gem::Version
|
|
154
|
-
version:
|
|
137
|
+
version: 1.14.0
|
|
155
138
|
type: :runtime
|
|
156
139
|
prerelease: false
|
|
157
140
|
version_requirements: !ruby/object:Gem::Requirement
|
|
158
141
|
requirements:
|
|
159
|
-
- - "
|
|
160
|
-
- !ruby/object:Gem::Version
|
|
161
|
-
version: '1.9'
|
|
162
|
-
- - "<"
|
|
142
|
+
- - "~>"
|
|
163
143
|
- !ruby/object:Gem::Version
|
|
164
|
-
version:
|
|
144
|
+
version: 1.14.0
|
|
165
145
|
- !ruby/object:Gem::Dependency
|
|
166
146
|
name: htmlentities
|
|
167
147
|
requirement: !ruby/object:Gem::Requirement
|
|
168
148
|
requirements:
|
|
169
149
|
- - "~>"
|
|
170
150
|
- !ruby/object:Gem::Version
|
|
171
|
-
version:
|
|
151
|
+
version: 4.4.2
|
|
172
152
|
type: :runtime
|
|
173
153
|
prerelease: false
|
|
174
154
|
version_requirements: !ruby/object:Gem::Requirement
|
|
175
155
|
requirements:
|
|
176
156
|
- - "~>"
|
|
177
157
|
- !ruby/object:Gem::Version
|
|
178
|
-
version:
|
|
158
|
+
version: 4.4.2
|
|
179
159
|
- !ruby/object:Gem::Dependency
|
|
180
160
|
name: jquery-rails
|
|
181
161
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -204,20 +184,40 @@ dependencies:
|
|
|
204
184
|
- - "~>"
|
|
205
185
|
- !ruby/object:Gem::Version
|
|
206
186
|
version: '7.0'
|
|
187
|
+
- !ruby/object:Gem::Dependency
|
|
188
|
+
name: kramdown
|
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
|
190
|
+
requirements:
|
|
191
|
+
- - "~>"
|
|
192
|
+
- !ruby/object:Gem::Version
|
|
193
|
+
version: '2.5'
|
|
194
|
+
- - ">="
|
|
195
|
+
- !ruby/object:Gem::Version
|
|
196
|
+
version: 2.5.1
|
|
197
|
+
type: :runtime
|
|
198
|
+
prerelease: false
|
|
199
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
200
|
+
requirements:
|
|
201
|
+
- - "~>"
|
|
202
|
+
- !ruby/object:Gem::Version
|
|
203
|
+
version: '2.5'
|
|
204
|
+
- - ">="
|
|
205
|
+
- !ruby/object:Gem::Version
|
|
206
|
+
version: 2.5.1
|
|
207
207
|
- !ruby/object:Gem::Dependency
|
|
208
208
|
name: loofah
|
|
209
209
|
requirement: !ruby/object:Gem::Requirement
|
|
210
210
|
requirements:
|
|
211
211
|
- - "~>"
|
|
212
212
|
- !ruby/object:Gem::Version
|
|
213
|
-
version:
|
|
213
|
+
version: 2.25.1
|
|
214
214
|
type: :runtime
|
|
215
215
|
prerelease: false
|
|
216
216
|
version_requirements: !ruby/object:Gem::Requirement
|
|
217
217
|
requirements:
|
|
218
218
|
- - "~>"
|
|
219
219
|
- !ruby/object:Gem::Version
|
|
220
|
-
version:
|
|
220
|
+
version: 2.25.1
|
|
221
221
|
- !ruby/object:Gem::Dependency
|
|
222
222
|
name: loofah-activerecord
|
|
223
223
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -272,14 +272,14 @@ dependencies:
|
|
|
272
272
|
requirements:
|
|
273
273
|
- - "~>"
|
|
274
274
|
- !ruby/object:Gem::Version
|
|
275
|
-
version: 1.
|
|
275
|
+
version: 1.19.2
|
|
276
276
|
type: :runtime
|
|
277
277
|
prerelease: false
|
|
278
278
|
version_requirements: !ruby/object:Gem::Requirement
|
|
279
279
|
requirements:
|
|
280
280
|
- - "~>"
|
|
281
281
|
- !ruby/object:Gem::Version
|
|
282
|
-
version: 1.
|
|
282
|
+
version: 1.19.2
|
|
283
283
|
- !ruby/object:Gem::Dependency
|
|
284
284
|
name: paper_trail
|
|
285
285
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -300,14 +300,14 @@ dependencies:
|
|
|
300
300
|
requirements:
|
|
301
301
|
- - "~>"
|
|
302
302
|
- !ruby/object:Gem::Version
|
|
303
|
-
version:
|
|
303
|
+
version: 2.5.0
|
|
304
304
|
type: :runtime
|
|
305
305
|
prerelease: false
|
|
306
306
|
version_requirements: !ruby/object:Gem::Requirement
|
|
307
307
|
requirements:
|
|
308
308
|
- - "~>"
|
|
309
309
|
- !ruby/object:Gem::Version
|
|
310
|
-
version:
|
|
310
|
+
version: 2.5.0
|
|
311
311
|
- !ruby/object:Gem::Dependency
|
|
312
312
|
name: rails-observers
|
|
313
313
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -398,14 +398,14 @@ dependencies:
|
|
|
398
398
|
requirements:
|
|
399
399
|
- - "~>"
|
|
400
400
|
- !ruby/object:Gem::Version
|
|
401
|
-
version: 1.
|
|
401
|
+
version: 1.54.0
|
|
402
402
|
type: :runtime
|
|
403
403
|
prerelease: false
|
|
404
404
|
version_requirements: !ruby/object:Gem::Requirement
|
|
405
405
|
requirements:
|
|
406
406
|
- - "~>"
|
|
407
407
|
- !ruby/object:Gem::Version
|
|
408
|
-
version: 1.
|
|
408
|
+
version: 1.54.0
|
|
409
409
|
- !ruby/object:Gem::Dependency
|
|
410
410
|
name: utf8-cleaner
|
|
411
411
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -460,14 +460,14 @@ dependencies:
|
|
|
460
460
|
requirements:
|
|
461
461
|
- - "~>"
|
|
462
462
|
- !ruby/object:Gem::Version
|
|
463
|
-
version: 2.
|
|
463
|
+
version: 2.9.2
|
|
464
464
|
type: :runtime
|
|
465
465
|
prerelease: false
|
|
466
466
|
version_requirements: !ruby/object:Gem::Requirement
|
|
467
467
|
requirements:
|
|
468
468
|
- - "~>"
|
|
469
469
|
- !ruby/object:Gem::Version
|
|
470
|
-
version: 2.
|
|
470
|
+
version: 2.9.2
|
|
471
471
|
- !ruby/object:Gem::Dependency
|
|
472
472
|
name: observer
|
|
473
473
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -510,6 +510,34 @@ dependencies:
|
|
|
510
510
|
- - "~>"
|
|
511
511
|
- !ruby/object:Gem::Version
|
|
512
512
|
version: '2.0'
|
|
513
|
+
- !ruby/object:Gem::Dependency
|
|
514
|
+
name: smarter_csv
|
|
515
|
+
requirement: !ruby/object:Gem::Requirement
|
|
516
|
+
requirements:
|
|
517
|
+
- - "~>"
|
|
518
|
+
- !ruby/object:Gem::Version
|
|
519
|
+
version: '1.13'
|
|
520
|
+
type: :runtime
|
|
521
|
+
prerelease: false
|
|
522
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
523
|
+
requirements:
|
|
524
|
+
- - "~>"
|
|
525
|
+
- !ruby/object:Gem::Version
|
|
526
|
+
version: '1.13'
|
|
527
|
+
- !ruby/object:Gem::Dependency
|
|
528
|
+
name: csv
|
|
529
|
+
requirement: !ruby/object:Gem::Requirement
|
|
530
|
+
requirements:
|
|
531
|
+
- - "~>"
|
|
532
|
+
- !ruby/object:Gem::Version
|
|
533
|
+
version: 3.3.3
|
|
534
|
+
type: :runtime
|
|
535
|
+
prerelease: false
|
|
536
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
537
|
+
requirements:
|
|
538
|
+
- - "~>"
|
|
539
|
+
- !ruby/object:Gem::Version
|
|
540
|
+
version: 3.3.3
|
|
513
541
|
- !ruby/object:Gem::Dependency
|
|
514
542
|
name: rexml
|
|
515
543
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -586,42 +614,42 @@ dependencies:
|
|
|
586
614
|
requirements:
|
|
587
615
|
- - "~>"
|
|
588
616
|
- !ruby/object:Gem::Version
|
|
589
|
-
version: 6.
|
|
617
|
+
version: 6.5.1
|
|
590
618
|
type: :development
|
|
591
619
|
prerelease: false
|
|
592
620
|
version_requirements: !ruby/object:Gem::Requirement
|
|
593
621
|
requirements:
|
|
594
622
|
- - "~>"
|
|
595
623
|
- !ruby/object:Gem::Version
|
|
596
|
-
version: 6.
|
|
624
|
+
version: 6.5.1
|
|
597
625
|
- !ruby/object:Gem::Dependency
|
|
598
626
|
name: faker
|
|
599
627
|
requirement: !ruby/object:Gem::Requirement
|
|
600
628
|
requirements:
|
|
601
629
|
- - "~>"
|
|
602
630
|
- !ruby/object:Gem::Version
|
|
603
|
-
version: 3.
|
|
631
|
+
version: 3.6.1
|
|
604
632
|
type: :development
|
|
605
633
|
prerelease: false
|
|
606
634
|
version_requirements: !ruby/object:Gem::Requirement
|
|
607
635
|
requirements:
|
|
608
636
|
- - "~>"
|
|
609
637
|
- !ruby/object:Gem::Version
|
|
610
|
-
version: 3.
|
|
638
|
+
version: 3.6.1
|
|
611
639
|
- !ruby/object:Gem::Dependency
|
|
612
640
|
name: gem-release
|
|
613
641
|
requirement: !ruby/object:Gem::Requirement
|
|
614
642
|
requirements:
|
|
615
643
|
- - "~>"
|
|
616
644
|
- !ruby/object:Gem::Version
|
|
617
|
-
version:
|
|
645
|
+
version: 2.2.4
|
|
618
646
|
type: :development
|
|
619
647
|
prerelease: false
|
|
620
648
|
version_requirements: !ruby/object:Gem::Requirement
|
|
621
649
|
requirements:
|
|
622
650
|
- - "~>"
|
|
623
651
|
- !ruby/object:Gem::Version
|
|
624
|
-
version:
|
|
652
|
+
version: 2.2.4
|
|
625
653
|
- !ruby/object:Gem::Dependency
|
|
626
654
|
name: puma
|
|
627
655
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -642,14 +670,14 @@ dependencies:
|
|
|
642
670
|
requirements:
|
|
643
671
|
- - "~>"
|
|
644
672
|
- !ruby/object:Gem::Version
|
|
645
|
-
version: 1.
|
|
673
|
+
version: 1.3.0
|
|
646
674
|
type: :development
|
|
647
675
|
prerelease: false
|
|
648
676
|
version_requirements: !ruby/object:Gem::Requirement
|
|
649
677
|
requirements:
|
|
650
678
|
- - "~>"
|
|
651
679
|
- !ruby/object:Gem::Version
|
|
652
|
-
version: 1.
|
|
680
|
+
version: 1.3.0
|
|
653
681
|
- !ruby/object:Gem::Dependency
|
|
654
682
|
name: rspec-collection_matchers
|
|
655
683
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -762,6 +790,46 @@ dependencies:
|
|
|
762
790
|
- - "~>"
|
|
763
791
|
- !ruby/object:Gem::Version
|
|
764
792
|
version: '3.5'
|
|
793
|
+
- !ruby/object:Gem::Dependency
|
|
794
|
+
name: better_errors
|
|
795
|
+
requirement: !ruby/object:Gem::Requirement
|
|
796
|
+
requirements:
|
|
797
|
+
- - "~>"
|
|
798
|
+
- !ruby/object:Gem::Version
|
|
799
|
+
version: '2.10'
|
|
800
|
+
- - ">="
|
|
801
|
+
- !ruby/object:Gem::Version
|
|
802
|
+
version: 2.10.1
|
|
803
|
+
type: :development
|
|
804
|
+
prerelease: false
|
|
805
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
806
|
+
requirements:
|
|
807
|
+
- - "~>"
|
|
808
|
+
- !ruby/object:Gem::Version
|
|
809
|
+
version: '2.10'
|
|
810
|
+
- - ">="
|
|
811
|
+
- !ruby/object:Gem::Version
|
|
812
|
+
version: 2.10.1
|
|
813
|
+
- !ruby/object:Gem::Dependency
|
|
814
|
+
name: binding_of_caller
|
|
815
|
+
requirement: !ruby/object:Gem::Requirement
|
|
816
|
+
requirements:
|
|
817
|
+
- - "~>"
|
|
818
|
+
- !ruby/object:Gem::Version
|
|
819
|
+
version: '1.0'
|
|
820
|
+
- - ">="
|
|
821
|
+
- !ruby/object:Gem::Version
|
|
822
|
+
version: 1.0.1
|
|
823
|
+
type: :development
|
|
824
|
+
prerelease: false
|
|
825
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
826
|
+
requirements:
|
|
827
|
+
- - "~>"
|
|
828
|
+
- !ruby/object:Gem::Version
|
|
829
|
+
version: '1.0'
|
|
830
|
+
- - ">="
|
|
831
|
+
- !ruby/object:Gem::Version
|
|
832
|
+
version: 1.0.1
|
|
765
833
|
description: Koalagator is an open source community calendaring platform
|
|
766
834
|
email:
|
|
767
835
|
- info@calagator.org
|
|
@@ -835,6 +903,7 @@ files:
|
|
|
835
903
|
- app/assets/stylesheets/calagator/typography.scss
|
|
836
904
|
- app/assets/stylesheets/calagator/utils.scss
|
|
837
905
|
- app/assets/stylesheets/calagator/variables.scss
|
|
906
|
+
- app/controllers/calagator/admin/bulk_imports_controller.rb
|
|
838
907
|
- app/controllers/calagator/admin/curations_controller.rb
|
|
839
908
|
- app/controllers/calagator/admin/users_controller.rb
|
|
840
909
|
- app/controllers/calagator/admin_controller.rb
|
|
@@ -863,6 +932,7 @@ files:
|
|
|
863
932
|
- app/javascript/calagator/calendar/lib/components.js
|
|
864
933
|
- app/javascript/calagator/calendar/lib/utils.js
|
|
865
934
|
- app/models/calagator/application_record.rb
|
|
935
|
+
- app/models/calagator/bulk_import.rb
|
|
866
936
|
- app/models/calagator/curation.rb
|
|
867
937
|
- app/models/calagator/event.rb
|
|
868
938
|
- app/models/calagator/event/browse.rb
|
|
@@ -888,6 +958,7 @@ files:
|
|
|
888
958
|
- app/models/calagator/venue/search_engine/sql.rb
|
|
889
959
|
- app/models/concerns/calagator/event_filterable.rb
|
|
890
960
|
- app/observers/calagator/cache_observer.rb
|
|
961
|
+
- app/views/calagator/admin/bulk_imports/new.html.erb
|
|
891
962
|
- app/views/calagator/admin/curations/_form.html.erb
|
|
892
963
|
- app/views/calagator/admin/curations/_index.html.erb
|
|
893
964
|
- app/views/calagator/admin/curations/edit.html.erb
|
|
@@ -913,6 +984,8 @@ files:
|
|
|
913
984
|
- app/views/calagator/events/_subnav.html.erb
|
|
914
985
|
- app/views/calagator/events/_subnav_custom.html.erb
|
|
915
986
|
- app/views/calagator/events/_table.html.erb
|
|
987
|
+
- app/views/calagator/events/_tabular.html.erb
|
|
988
|
+
- app/views/calagator/events/_tabular_table.html.erb
|
|
916
989
|
- app/views/calagator/events/duplicates.html.erb
|
|
917
990
|
- app/views/calagator/events/edit.html.erb
|
|
918
991
|
- app/views/calagator/events/index.atom.builder
|
|
@@ -921,6 +994,7 @@ files:
|
|
|
921
994
|
- app/views/calagator/events/new.html.erb
|
|
922
995
|
- app/views/calagator/events/search.html.erb
|
|
923
996
|
- app/views/calagator/events/show.html.erb
|
|
997
|
+
- app/views/calagator/events/tabular.html.erb
|
|
924
998
|
- app/views/calagator/shared/_calendar.html.erb
|
|
925
999
|
- app/views/calagator/shared/_subnav_curations.html.erb
|
|
926
1000
|
- app/views/calagator/shared/_subnav_pinned_venues.html.erb
|
|
@@ -1031,6 +1105,7 @@ files:
|
|
|
1031
1105
|
- lib/calagator/duplicate_checking/duplicate_finder.rb
|
|
1032
1106
|
- lib/calagator/duplicate_checking/duplicate_squasher.rb
|
|
1033
1107
|
- lib/calagator/engine.rb
|
|
1108
|
+
- lib/calagator/import_events_csv.rb
|
|
1034
1109
|
- lib/calagator/machine_tag.rb
|
|
1035
1110
|
- lib/calagator/strip_whitespace.rb
|
|
1036
1111
|
- lib/calagator/url_prefixer.rb
|
|
@@ -1080,14 +1155,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
1080
1155
|
requirements:
|
|
1081
1156
|
- - ">="
|
|
1082
1157
|
- !ruby/object:Gem::Version
|
|
1083
|
-
version:
|
|
1158
|
+
version: 3.1.0
|
|
1084
1159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1085
1160
|
requirements:
|
|
1086
1161
|
- - ">="
|
|
1087
1162
|
- !ruby/object:Gem::Version
|
|
1088
1163
|
version: '0'
|
|
1089
1164
|
requirements: []
|
|
1090
|
-
rubygems_version: 3.5.
|
|
1165
|
+
rubygems_version: 3.5.22
|
|
1091
1166
|
signing_key:
|
|
1092
1167
|
specification_version: 4
|
|
1093
1168
|
summary: A calendar for communities
|