apidae 0.11.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 765dd17ae6901f726e634a675934148a79715022
4
- data.tar.gz: bab182d1cc1367ed70b10dfda1bb1d3a08f0d47c
3
+ metadata.gz: '07291fb2c40fdbc091aff918c45c201602a5d58c'
4
+ data.tar.gz: 76f4566eb71404f129add27100872f1263ae868b
5
5
  SHA512:
6
- metadata.gz: a019141cef8e85dc8806cd73c31dfbc02e5f95758c9be26825a7c8b647a4cb99ff2fd41af12723f8c867e9b52095d583ee195011dd5d8d2cf2de2c6d1775f5d1
7
- data.tar.gz: 6695e5409d28e870ee3096db3737e88f3db3cc701ec5362860b8eab60c65ba45678ff20e6dbc780a9dc6db1c478a2c58baaf24d2a3eb1c6eff088738c52dde77
6
+ metadata.gz: fa72db3de71d37e56b2c8908d703419a72fc5f0efd2d9f03ce91233ae0d68bd402f4a49d775fa22856a2109f83c7bb8bb54593224cc1e14377f696afc2e6d811
7
+ data.tar.gz: e1a0c2c71710947ea1b47266e2bb995ba5a44cec98190b3358168e21681ce9b2da4d3c479932514620929da4758affe03cece6e8693cf2f4458e327af108f7a8
@@ -2,5 +2,24 @@ module Apidae
2
2
  class ApplicationController < ActionController::Base
3
3
  protect_from_forgery with: :exception
4
4
  before_action Rails.application.config.apidae_auth
5
+ before_action :check_user_data!
6
+
7
+ def apidae_user
8
+ send(Rails.application.config.apidae_user) if Rails.application.config.respond_to?(:apidae_user)
9
+ end
10
+
11
+ def user_is_admin?
12
+ apidae_user && Rails.application.config.respond_to?(:apidae_admin) && Rails.application.config.apidae_admin.call(apidae_user)
13
+ end
14
+
15
+ def user_has_data?
16
+ apidae_user && apidae_user.respond_to?(:apidae_projects_ids) && !apidae_user.apidae_projects_ids.blank?
17
+ end
18
+
19
+ def check_user_data!
20
+ unless user_has_data? || user_is_admin?
21
+ redirect_to main_app.root_path, alert: "Il n'y a aucun projet Apidae associé à votre compte."
22
+ end
23
+ end
5
24
  end
6
25
  end
@@ -3,11 +3,20 @@ require_dependency "apidae/application_controller"
3
3
  module Apidae
4
4
  class DashboardController < ApplicationController
5
5
  def index
6
- @objects = Obj.count
7
- @selections = Selection.count
8
- @projects = Project.count
6
+ if user_is_admin?
7
+ @objects = Obj.count
8
+ @selections = Selection.count
9
+ @projects = Project.count
10
+ @last_imports = FileImport.order(id: :desc).take(100)
11
+ else
12
+ projects = Project.where(apidae_id: apidae_user.apidae_projects_ids)
13
+ selections = Selection.where(apidae_project_id: projects.select(:id).map {|p| p.id})
14
+ @projects = projects.count
15
+ @selections = selections.uniq.count
16
+ @objects = SelectionObject.where(apidae_selection_id: selections.map {|s| s.id}.uniq).map {|so| so.apidae_object_id}.uniq.count
17
+ @last_imports = FileImport.where(apidae_id: apidae_user.apidae_projects_ids).order(id: :desc).take(100)
18
+ end
9
19
  @references = Reference.count
10
- @last_imports = FileImport.order(id: :desc).take(100)
11
20
  end
12
21
  end
13
22
  end
@@ -10,8 +10,13 @@ module Apidae
10
10
  if params[:selection_id]
11
11
  @selection = Selection.find(params[:selection_id])
12
12
  @objects = @selection.objects.select(:id, :apidae_id, :title_data, :apidae_type, :updated_at)
13
- else
13
+ elsif user_is_admin?
14
14
  @objects = Obj.all.select(:id, :apidae_id, :title_data, :apidae_type, :updated_at)
15
+ else
16
+ projects_ids = Project.where(apidae_id: apidae_user.apidae_projects_ids).map {|p| p.id}
17
+ @objects = Obj.joins(:selections).where("apidae_selections.apidae_project_id IN (?)", projects_ids)
18
+ .select("apidae_objs.id, apidae_objs.apidae_id, apidae_objs.title_data, apidae_objs.apidae_type, apidae_objs.updated_at")
19
+ .distinct("apidae_objs.apidae_id").to_a
15
20
  end
16
21
  end
17
22
 
@@ -5,7 +5,11 @@ module Apidae
5
5
  before_action :set_project, only: [:edit, :update, :destroy]
6
6
 
7
7
  def index
8
- @projects = Project.all
8
+ if user_is_admin?
9
+ @projects = Project.all
10
+ else
11
+ @projects = Project.where(apidae_id: apidae_user.apidae_projects_ids)
12
+ end
9
13
  end
10
14
 
11
15
  def new
@@ -5,7 +5,12 @@ module Apidae
5
5
  before_action :set_selection, only: [:show, :edit, :update, :destroy, :refresh]
6
6
 
7
7
  def index
8
- @selections = Selection.all
8
+ if user_is_admin?
9
+ @selections = Selection.all
10
+ else
11
+ projects_ids = Project.where(apidae_id: apidae_user.apidae_projects_ids).map {|p| p.id}
12
+ @selections = Selection.where(apidae_project_id: projects_ids)
13
+ end
9
14
  end
10
15
 
11
16
  def show
@@ -1,5 +1,9 @@
1
1
  module Apidae
2
2
  module ApplicationHelper
3
3
  include Apidae::ApidaeHelper
4
+
5
+ def apidae_user
6
+ send(Rails.application.config.apidae_user) if Rails.application.config.respond_to?(:apidae_user)
7
+ end
4
8
  end
5
9
  end
@@ -0,0 +1,376 @@
1
+ module Apidae
2
+ class ApidaeDataParser
3
+ PHONE = 201
4
+ EMAIL = 204
5
+ WEBSITE = 205
6
+
7
+ MODE_AUTO = 'auto'
8
+ MODE_MANUAL = 'manual'
9
+
10
+ MONDAY = 'MON'
11
+ TUESDAY = 'TUE'
12
+ WEDNESDAY = 'WED'
13
+ THURSDAY = 'THU'
14
+ FRIDAY = 'FRI'
15
+ SATURDAY = 'SAT'
16
+ SUNDAY = 'SUN'
17
+
18
+ ALL_DAYS = [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
19
+
20
+ WEEKDAYS_MAP = {
21
+ 'LUNDI' => MONDAY,
22
+ 'MARDI' => TUESDAY,
23
+ 'MERCREDI' => WEDNESDAY,
24
+ 'JEUD' => THURSDAY,
25
+ 'VENDREDI' => FRIDAY,
26
+ 'SAMEDI' => SATURDAY,
27
+ 'DIMANCHE' => SUNDAY
28
+ }
29
+
30
+ def self.parse_versioned_fields(data_hash)
31
+ version_fields = data_hash[:champsAspect] || []
32
+ matched_fields = []
33
+ version_fields.each do |f|
34
+ case f
35
+ when 'nom'
36
+ matched_fields << 'title'
37
+ when 'presentation.descriptifCourt'
38
+ matched_fields << 'short_desc'
39
+ when 'presentation.descriptifDetaille'
40
+ matched_fields << 'long_desc'
41
+ when 'illustrations'
42
+ matched_fields << 'pictures'
43
+ when 'multimedias'
44
+ matched_fields << 'attachments'
45
+ when 'informations.moyensCommunication'
46
+ matched_fields << 'contact'
47
+ when 'descriptifsThematises'
48
+ matched_fields << 'theme_desc'
49
+ when 'ouverture.periodesOuvertures', 'ouverture.periodeEnClair'
50
+ matched_fields << 'openings_desc'
51
+ matched_fields << 'openings'
52
+ when 'ouverture.periodeEnClairAutomatique'
53
+ matched_fields << 'openings_desc_mode'
54
+ when 'descriptionTarif.tarifsEnClair', 'descriptionTarif.periodes'
55
+ matched_fields << 'rates_desc'
56
+ matched_fields << 'rates'
57
+ when 'descriptionTarif.tarifsEnClairAutomatique'
58
+ matched_fields << 'rates_desc_mode'
59
+ when 'prestations.equipements'
60
+ matched_fields << 'equipments'
61
+ when 'prestations.activites'
62
+ matched_fields << 'activities'
63
+ when 'prestations.services'
64
+ matched_fields << 'services'
65
+ when 'localisation.environnements'
66
+ matched_fields << 'environments'
67
+ when 'prestations.complementAccueil'
68
+ matched_fields << 'extra'
69
+ when 'localisation.geolocalisation.complement'
70
+ matched_fields << 'access'
71
+ else
72
+ end
73
+ end
74
+ matched_fields.uniq
75
+ end
76
+
77
+ def self.parse_title(data_hash, *locales)
78
+ {title: node_value(data_hash, :nom, *locales)}
79
+ end
80
+
81
+ def self.parse_owner_data(data_hash)
82
+ unless data_hash.blank?
83
+ {owner_name: data_hash[:nom], owner_id: data_hash[:id]}
84
+ end
85
+ end
86
+
87
+ def self.parse_desc_data(data_hash, private_data, *locales)
88
+ unless data_hash.blank?
89
+ {
90
+ short_desc: node_value(data_hash, :descriptifCourt, *locales),
91
+ long_desc: node_value(data_hash, :descriptifDetaille, *locales),
92
+ theme_desc: data_hash[:descriptifsThematises].blank? ? {} : Hash[data_hash[:descriptifsThematises].map {|th| [node_id(th, :theme), node_value(th, :description, *locales)]}],
93
+ private_desc: private_data.blank? ? {} : Hash[private_data.map {|d| [d[:nomTechnique], node_value(d, :descriptif, *locales)]}]
94
+ }
95
+ end
96
+ end
97
+
98
+ def self.parse_pictures_data(pictures_array, *locales)
99
+ pics_data = {}
100
+ unless pictures_array.blank?
101
+ l = locales.blank? ? [DEFAULT_LOCALE] : locales
102
+ l.each do |locale|
103
+ pics_data[locale] = []
104
+ pictures_array.select { |p| p.is_a?(Hash) && !p[:traductionFichiers].blank? }.each do |pic|
105
+ pics_data[locale] << {
106
+ id: pic[:identifiant],
107
+ name: localized_value(pic, :nom, locale),
108
+ url: pic[:traductionFichiers][0][:url].gsub('http:', 'https:'),
109
+ description: localized_value(pic, :legende, locale),
110
+ credits: localized_value(pic, :copyright, locale),
111
+ expiration_date: pic[:dateLimiteDePublication]
112
+ }
113
+ end
114
+ end
115
+ end
116
+ {pictures: pics_data}
117
+ end
118
+
119
+ def self.parse_attachments_data(attachments_array, *locales)
120
+ atts_data = {}
121
+ unless attachments_array.blank?
122
+ l = locales.blank? ? [DEFAULT_LOCALE] : locales
123
+ l.each do |locale|
124
+ atts_data[locale] = []
125
+ attachments_array.select { |att| att.is_a?(Hash) && !att[:traductionFichiers].blank? }.each do |att|
126
+ atts_data[locale] << {
127
+ id: att[:identifiant],
128
+ name: localized_value(att, :nom, locale),
129
+ url: att[:traductionFichiers][0][:url].gsub('http:', 'https:'),
130
+ type: att[:type],
131
+ description: localized_value(att, :legende, locale)
132
+ }
133
+ end
134
+ end
135
+ end
136
+ {attachments: atts_data}
137
+ end
138
+
139
+ def self.parse_contact_data(information_hash, contacts_list)
140
+ contact_details = {contacts: contacts_list}
141
+ unless information_hash.blank?
142
+ contact_entries = information_hash[:moyensCommunication] || []
143
+ contact_entries.each do |c|
144
+ case c[:type][:id]
145
+ when PHONE
146
+ contact_details[:telephone] ||= []
147
+ contact_details[:telephone] << c[:coordonnees][:fr]
148
+ when EMAIL
149
+ contact_details[:email] ||= []
150
+ contact_details[:email] << c[:coordonnees][:fr]
151
+ when WEBSITE
152
+ contact_details[:website] ||= []
153
+ contact_details[:website] << c[:coordonnees][:fr]
154
+ else
155
+ end
156
+ end
157
+ end
158
+ contact_details
159
+ end
160
+
161
+ def self.parse_location_data(location_hash, type_data_hash, territories)
162
+ loc_data = {}
163
+ unless location_hash.blank?
164
+ address_hash = location_hash[:adresse]
165
+ computed_address = []
166
+ unless address_hash.blank?
167
+ computed_address << address_hash[:adresse1] unless address_hash[:adresse1].blank?
168
+ computed_address << address_hash[:adresse2] unless address_hash[:adresse2].blank?
169
+ computed_address << address_hash[:adresse3] unless address_hash[:adresse3].blank?
170
+ end
171
+ loc_data.merge!({address: computed_address})
172
+ loc_data.merge!({place: type_data_hash[:nomLieu]}) if type_data_hash
173
+ geoloc_details = location_hash[:geolocalisation]
174
+ if geoloc_details && geoloc_details[:valide] && geoloc_details[:geoJson]
175
+ loc_data[:latitude] = geoloc_details[:geoJson][:coordinates][1]
176
+ loc_data[:longitude] = geoloc_details[:geoJson][:coordinates][0]
177
+ end
178
+ loc_data[:access] = node_value(geoloc_details, :complement) if geoloc_details
179
+ loc_data[:environments] = location_hash[:environnements].map {|e| e[:id]} if location_hash[:environnements]
180
+ end
181
+ loc_data[:territories] = territories.map {|t| t[:id]} unless territories.blank?
182
+ loc_data
183
+ end
184
+
185
+ # Note : use internal format for openings storage (ideally Apihours one, to merge data from both sources)
186
+ def self.parse_openings(openings_hash, *locales)
187
+ if openings_hash && openings_hash[:periodeEnClair]
188
+ {
189
+ openings_desc: node_value(openings_hash, :periodeEnClair, *locales),
190
+ openings_desc_mode: openings_hash[:periodeEnClairGenerationMode] == 'AUTOMATIQUE' ? MODE_AUTO : MODE_MANUAL,
191
+ openings: build_openings(openings_hash, *locales),
192
+ time_periods: lists_ids(openings_hash[:indicationsPeriode])
193
+ }
194
+ end
195
+ end
196
+
197
+ def self.parse_rates(rates_hash, *locales)
198
+ if rates_hash
199
+ desc = rates_hash[:gratuit] ? {DEFAULT_LOCALE => 'gratuit'} : node_value(rates_hash, :tarifsEnClair, *locales)
200
+ values = rates_hash[:periodes].blank? ? [] : rates_hash[:periodes].map {|p| build_rate(p)}
201
+ methods = rates_hash[:modesPaiement].blank? ? [] : rates_hash[:modesPaiement].map {|p| p[:id]}
202
+ {
203
+ rates_desc: desc, rates: values, payment_methods: methods,
204
+ rates_desc_mode: rates_hash[:tarifsEnClairGenerationMode] == 'AUTOMATIQUE' ? MODE_AUTO : MODE_MANUAL,
205
+ includes: node_value(rates_hash, :leTarifComprend, *locales),
206
+ excludes: node_value(rates_hash, :leTarifNeComprendPas, *locales)
207
+ }
208
+ end
209
+ end
210
+
211
+ def self.parse_type_data(apidae_obj, type_hash, presta_hash, business_hash, *locales)
212
+ data_hash = type_hash || {}
213
+ prestations_hash = presta_hash || {}
214
+ apidae_obj.apidae_subtype = lists_ids(data_hash[:typesManifestation]).first if apidae_obj.apidae_type == Obj::FEM
215
+ apidae_obj.apidae_subtype = node_id(data_hash, :rubrique) if apidae_obj.apidae_type == Obj::EQU
216
+ apidae_obj.apidae_subtype = lists_ids(data_hash[:typesHebergement]).first if apidae_obj.apidae_type == Obj::SPA
217
+ {
218
+ categories: lists_ids(data_hash[:categories], data_hash[:typesDetailles], data_hash[:activiteCategories]),
219
+ themes: lists_ids(data_hash[:themes]),
220
+ capacity: (data_hash[:capacite] || {})
221
+ .merge(presta_hash ? {group_min: presta_hash[:tailleGroupeMin], group_max: presta_hash[:tailleGroupeMax],
222
+ age_min: presta_hash[:ageMin], age_max: presta_hash[:ageMax]} : {}),
223
+ classification: nodes_ids(data_hash[:classement], data_hash[:classementPrefectoral], data_hash[:classification]) +
224
+ lists_ids(data_hash[:classementsGuides]) + lists_ids(data_hash[:classements]),
225
+ labels: lists_ids(data_hash[:labels], data_hash[:labelsChartesQualite], prestations_hash[:labelsTourismeHandicap]) +
226
+ (node_id(data_hash, :typeLabel) ? [node_id(data_hash, :typeLabel)] : []),
227
+ chains: lists_ids(data_hash[:chaines]) + nodes_ids(data_hash[:chaineEtLabel]),
228
+ area: apidae_obj.apidae_type == Obj::DOS ? data_hash.except(:classification) : node_value(data_hash, :lieuDePratique),
229
+ track: apidae_obj.apidae_type == Obj::EQU ? data_hash[:itineraire] : nil,
230
+ products: lists_ids(data_hash[:typesProduit], data_hash[:aopAocIgps], data_hash[:specialites]),
231
+ audience: lists_ids(prestations_hash[:typesClientele]),
232
+ animals: prestations_hash[:animauxAcceptes] == 'ACCEPTES',
233
+ extra: apidae_obj.apidae_type == Obj::SPA ? node_value(data_hash, :formuleHebergement, *locales) : node_value(prestations_hash, :complementAccueil, *locales),
234
+ duration: apidae_obj.apidae_type == Obj::SPA ? {days: data_hash[:nombreJours], nights: data_hash[:nombreNuits]} : data_hash[:dureeSeance],
235
+ certifications: data_hash[:agrements].blank? ? [] : data_hash[:agrements].map {|a| {id: a[:type][:id], identifier: a[:numero]}},
236
+ business: business_hash
237
+ }
238
+ end
239
+
240
+ def self.parse_service_data(data_hash, type_data_hash)
241
+ if data_hash
242
+ {
243
+ services: lists_ids(data_hash[:services]),
244
+ equipments: lists_ids(data_hash[:equipements]),
245
+ comfort: lists_ids(data_hash[:conforts]),
246
+ activities: lists_ids(data_hash[:activites], type_data_hash ? type_data_hash[:activites] : [],
247
+ type_data_hash ? type_data_hash[:activitesSportives] : [],
248
+ type_data_hash ? type_data_hash[:activitesCulturelles] : []),
249
+ challenged: lists_ids(data_hash[:tourismesAdaptes]),
250
+ languages: lists_ids(data_hash[:languesParlees])
251
+ }
252
+ end
253
+ end
254
+
255
+ def self.parse_tags_data(pres_data_hash, crit_data_hash, linked_data_hash)
256
+ tags = {}
257
+ if pres_data_hash
258
+ tags[:promo] = lists_ids(pres_data_hash[:typologiesPromoSitra])
259
+ end
260
+ unless crit_data_hash.blank?
261
+ tags[:internal] = crit_data_hash.map {|c| c[:id]}
262
+ end
263
+ unless linked_data_hash.blank? || linked_data_hash[:liensObjetsTouristiquesTypes].blank?
264
+ tags[:linked] = linked_data_hash[:liensObjetsTouristiquesTypes]
265
+ .map {|l| {apidae_id: l[:objetTouristique][:id], apidae_type: l[:objetTouristique][:type], category: l[:type]}}
266
+ end
267
+ tags
268
+ end
269
+
270
+ def self.parse_booking(reservation_hash, *locales)
271
+ if reservation_hash
272
+ {
273
+ booking_desc: node_value(reservation_hash, :complement, *locales),
274
+ booking_entities: reservation_hash[:organismes]
275
+ }
276
+ end
277
+ end
278
+
279
+ def self.parse_town(location_hash)
280
+ if location_hash
281
+ address_hash = location_hash[:adresse]
282
+ (!address_hash.blank? && address_hash[:commune]) ? Town.find_by_apidae_id(address_hash[:commune][:id]) : nil
283
+ else
284
+ nil
285
+ end
286
+ end
287
+
288
+ def self.parse_entity_fields(information_hash, type_data_hash)
289
+ if information_hash && information_hash[:structureGestion]
290
+ {entity_id: information_hash[:structureGestion][:id], service_provider_id: node_id(type_data_hash, :prestataireActivites)}
291
+ end
292
+ end
293
+
294
+ def self.node_id(node, key)
295
+ node[key][:id] if node && node[key]
296
+ end
297
+
298
+ private
299
+
300
+ def self.build_rate(rate_period)
301
+ {
302
+ id: rate_period[:identifiant], start_date: rate_period[:dateDebut], end_date: rate_period[:dateFin],
303
+ values: rate_period[:tarifs].blank? ? [] : rate_period[:tarifs].map {|t| {min: t[:minimum], max: t[:maximum], type: t[:type][:id], details: node_value(t, :precisionTarif)}}
304
+ }
305
+ end
306
+
307
+ def self.build_openings(openings_data, *locales)
308
+ openings_list = openings_data[:periodesOuvertures]
309
+ closing_days = openings_data[:fermeturesExceptionnelles]
310
+ if openings_list.blank?
311
+ []
312
+ else
313
+ openings_list.map do |o|
314
+ {
315
+ id: o[:identifiant],
316
+ external_id: o[:identifiantTechnique],
317
+ start_date: o[:dateDebut],
318
+ end_date: o[:dateFin],
319
+ closing_days: closing_days.blank? ? [] : closing_days.map {|d| d[:dateSpeciale]},
320
+ details: node_value(o, :complementHoraire, *locales),
321
+ time_periods: [
322
+ {
323
+ type: 'opening',
324
+ weekdays: compute_weekdays(o),
325
+ time_frames: (o[:horaireOuverture].blank? && o[:horaireFermeture].blank?) ? [] : [{start_time: o[:horaireOuverture], end_time: o[:horaireFermeture], recurrence: nil}]
326
+ }
327
+ ]
328
+ }
329
+ end
330
+ end
331
+ end
332
+
333
+ def self.compute_weekdays(opening_data)
334
+ if opening_data[:type] == 'OUVERTURE_TOUS_LES_JOURS'
335
+ ALL_DAYS
336
+ elsif opening_data[:type] == 'OUVERTURE_SAUF' && opening_data[:ouverturesJournalieres]
337
+ closed_weekdays = opening_data[:ouverturesJournalieres].map {|d| WEEKDAYS_MAP[d[:jour]]}
338
+ ALL_DAYS - closed_weekdays
339
+ elsif opening_data[:type] == 'OUVERTURE_SEMAINE' && opening_data[:ouverturesJournalieres]
340
+ opening_data[:ouverturesJournalieres].map {|d| WEEKDAYS_MAP[d[:jour]]}
341
+ else
342
+ []
343
+ end
344
+ end
345
+
346
+ def self.node_value(node, key, *locales)
347
+ l = locales.blank? ? [DEFAULT_LOCALE] : locales
348
+ locales_map = Hash[l.map {|loc| [localized_key(loc), loc]}]
349
+ if node && node[key]
350
+ node[key].slice(*locales_map.keys).transform_keys {|k| locales_map[k]}
351
+ else
352
+ {}
353
+ end
354
+ end
355
+
356
+ def self.localized_value(node, key, loc)
357
+ if node && node[key]
358
+ node[key][localized_key(loc)]
359
+ else
360
+ ''
361
+ end
362
+ end
363
+
364
+ def self.lists_ids(*lists)
365
+ lists.blank? ? [] : lists.map {|l| l.blank? ? [] : l.map {|elt| elt[:id]}}.flatten.uniq
366
+ end
367
+
368
+ def self.nodes_ids(*nodes)
369
+ nodes.blank? ? [] : nodes.select {|n| !n.blank?}.map {|n| n[:id]}
370
+ end
371
+
372
+ def self.localized_key(loc = DEFAULT_LOCALE)
373
+ "libelle#{loc.camelize.gsub('-', '')}".to_sym
374
+ end
375
+ end
376
+ end