apidae 0.11.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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