diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 28497fef..04f8ea40 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - laiv tags: - 'v[0-9]+.[0-9]+.[0-9]+*' pull_request: diff --git a/.nvmrc b/.nvmrc index 3c032078..a45fd52c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 +24 diff --git a/app/assets/javascripts/application.coffee.erb b/app/assets/javascripts/application.coffee.erb index ca169258..4de259a2 100644 --- a/app/assets/javascripts/application.coffee.erb +++ b/app/assets/javascripts/application.coffee.erb @@ -138,7 +138,7 @@ $ -> $(document).on 'click', '.sidebar-toggler', () -> width = $('.sidebar').width() zoom = $('.ol-zoom') - scale = $('.ol-scale-line') + scale = $('.ol-scale-line, .ol-scale-bar') geoloc = $('.geolocation') addr_search = $('.address-search-field') $('.sidebar').toggle() @@ -189,13 +189,14 @@ $ -> else error.push response.error when 2 - unless $('.radio-type').is(':checked') - error.push "<%= I18n.t('requests.desktop.new.error.required.type') %>" + if <%= Settings::Client.skip_type_selection %> + validate_categories(error) + else + unless $('.radio-type').is(':checked') + error.push "<%= I18n.t('requests.desktop.new.error.required.type') %>" when 3 - unless $('#request_service_code_1').val() - error.push "<%= I18n.t('requests.desktop.new.error.required.category') %>" - unless $('#request_description').val().trim() != '' - error.push "<%= I18n.t('requests.desktop.new.error.required.description') %>" + if !<%= Settings::Client.skip_type_selection %> + validate_categories(error) else if $(@).data('next') == 1 @@ -218,6 +219,12 @@ $ -> KS.buildError(error) false + validate_categories= (error) -> + unless $('#request_service_code_1').val() + error.push "<%= I18n.t('requests.desktop.new.error.required.category') %>" + unless $('#request_description').val().trim() != '' + error.push "<%= I18n.t('requests.desktop.new.error.required.description') %>" + $('.start-card').find('.btn-primary').toArray()[0].focus() if $('.start-card').is(':visible') $(document).on 'click', '.update-position', () -> diff --git a/app/assets/javascripts/maps.coffee.erb b/app/assets/javascripts/maps.coffee.erb index 5bb59419..d41138ed 100644 --- a/app/assets/javascripts/maps.coffee.erb +++ b/app/assets/javascripts/maps.coffee.erb @@ -9,7 +9,6 @@ KS.projection = -> else console.log 'Proj4J ist nicht geladen!' -KS.maxZoom = <%= Settings::Map.zoom[:max] %> KS.projectionWGS84 = ol.proj.get 'EPSG:4326' #KS.zoomEvent = false KS.requests_path = "<%= Settings::Route.requests_path %>/" @@ -44,6 +43,17 @@ KS.GeolocationControl = () -> ol.inherits(KS.GeolocationControl, ol.control.Control) KS.ViewSwitcherControl = () -> + if <%= Settings::Map.overlap_layers %> + elem = KS.ViewSwitcherControlMultiple() + else + elem = KS.ViewSwitcherControlSingle() + + new ol.control.Control + element: elem + target: {}.target +ol.inherits(KS.ViewSwitcherControl, ol.control.Control) + +KS.ViewSwitcherControlSingle = () -> span = document.createElement('span') span.className = 'image' image = document.createElement('img') @@ -68,11 +78,119 @@ KS.ViewSwitcherControl = () -> elem = document.createElement('div') elem.className = 'view-switcher ol-control' elem.appendChild(btn) + elem - new ol.control.Control - element: elem - target: {}.target -ol.inherits(KS.ViewSwitcherControl, ol.control.Control) +KS.ViewSwitcherControlMultiple = () -> + elem = document.createElement('div') + elem.className = 'view-switcher ol-control multiple' + text_span = document.createElement('span') + text_span.className = 'text' + text_span.innerHTML = "<%= I18n.t(:map_settings) %>" + elem.appendChild(text_span) + + switchLayers = [] + for layer in <%= Settings::Map.wmts_layers.to_json %> + switchLayers.push layer + for layer in <%= Settings::Map.wms_layers.to_json %> + switchLayers.push layer + + switchLayers.sort (a, b) -> + a.switcher_sorting - b.switcher_sorting + + expand = document.createElement('div') + expand.className = 'expand' + expand.setAttribute 'style', 'display: none' + for layer in switchLayers + if layer.addbefore + for additional in layer.addbefore + if additional == 'hr_spacer' + expand.appendChild document.createElement('hr') + else + additional_text = document.createElement('span') + additional_text.className = 'text' + additional_text.innerHTML = additional + expand.appendChild(additional_text) + + child = KS.ViewSwitcherControlMultipleItem(layer) + expand.appendChild child if child + + $(expand).on 'change', 'input[data-action=visibility]', (elem) -> + item = event.target + for l in KS.layers.layers + if l.get('id') == item.value + l.setVisible(item.checked) + if item.checked + $('#layer_opacity_' + item.value).show() + else + $('#layer_opacity_' + item.value).hide() + + $(expand).on 'change', 'input[data-action=opacity]', (elem) -> + item = $(event.target) + for l in KS.layers.layers + if l.get('id') == item.data('layer') + l.setOpacity(parseFloat(item.val())) + + elem.appendChild expand + + toggler = document.createElement('div') + toggler.className = 'map-settings-toggler' + text_span = document.createElement('span') + toggler.appendChild(text_span) + + toggleMapSettings = () -> + expand = $('.view-switcher .expand') + expand.toggle() + if expand.is(':visible') + expand.addClass('open') + else + expand.removeClass('open') + KS.positionViewSwitcher() + + toggler.addEventListener('click', toggleMapSettings, false) + elem.appendChild toggler + elem + +KS.ViewSwitcherControlMultipleItem = (layer) -> + div = document.createElement('div') + div.classList.add('form-check') + if layer.parent + div.classList.add('offset-1') + label = document.createElement('label') + label.classList.add('form-check-label') + label_for = '' + + label_for = 'layer_overlap_' + layer.id + check = document.createElement('input') + check.setAttribute('type', 'checkbox') + check.setAttribute('name', label_for) + check.setAttribute('id', label_for) + check.setAttribute('value', layer.id) + check.classList.add('form-check-input') + check.setAttribute('checked', 'checked') if layer.visible + check.setAttribute('data-action', 'visibility') + div.appendChild(check) + + label.setAttribute('for', label_for) + label.appendChild document.createTextNode(layer.label) + div.appendChild(label) + + if layer.opacity_adjustable + range_for = 'layer_opacity_' + layer.id + opacity_range = document.createElement('input') + opacity_range.setAttribute('name', range_for) + opacity_range.setAttribute('id', range_for) + opacity_range.setAttribute('type', 'range') + opacity_range.setAttribute('min', 0) + opacity_range.setAttribute('max', 1) + opacity_range.setAttribute('value', 1) + opacity_range.setAttribute('step', 0.01) + opacity_range.setAttribute('data-layer', layer.id) + opacity_range.setAttribute('data-action', 'opacity') + unless layer.visible + opacity_range.setAttribute('style', 'display: none;') + div.appendChild(opacity_range) + + div class KS.Map constructor: (@projection = KS.projection()) -> @@ -86,13 +204,30 @@ class KS.Map ) KS.popupCloser = document.getElementById('popup-closer') - mapView = new ol.View + options = { projection: @projection center: <%= Settings::Map.center %> - zoom: <%= Settings::Map.zoom[:initial] %> - maxZoom: KS.maxZoom - minZoom: <%= Settings::Map.zoom[:min] %> enableRotation: false + } + + minZoom = <%= Settings::Map.zoom[:min] if Settings::Map.zoom %> + maxZoom = <%= Settings::Map.zoom[:max] if Settings::Map.zoom %> + initialZoom = <%= Settings::Map.zoom[:initial] if Settings::Map.zoom %> + + minResolution = <%= Settings::Map.resolution ? Settings::Map.resolution[:min] : false %> + maxResolution = <%= Settings::Map.resolution ? Settings::Map.resolution[:max] : false %> + initialResolution = <%= Settings::Map.resolution ? Settings::Map.resolution[:initial] : false %> + + if minResolution && maxResolution && initialResolution + options['minResolution'] = minResolution + options['maxResolution'] = maxResolution + options['resolution'] = initialResolution + else + options['minZoom'] = minZoom if minZoom + options['maxZoom'] = maxZoom if maxZoom + options['zoom'] = initialZoom if initialZoom + + mapView = new ol.View(options) if region = KS.getUrlParam('region') $.ajax(url: "#{KS.areas_path}®ion=#{region}&search_class=authority", dataType: 'json').done (response) -> @@ -112,7 +247,15 @@ class KS.Map return @olMap addControls = (map) -> - map.addControl new ol.control.ScaleLine + if <%= Settings::Map.scale_bar %> + scaleLineControl = new ol.control.ScaleLine( + bar: true + text: true + minWidth: 80 + ) + map.addControl scaleLineControl + else + map.addControl new ol.control.ScaleLine map.on 'pointermove', (e) -> pixel = map.getEventPixel(e.originalEvent) @@ -349,10 +492,16 @@ class KS.Layers constructor: (map, overlay = true) -> @active = 0 @layers = [] + for layer in <%= Settings::Map.wmts_layers.to_json %> do (layer, @layers) -> @layers.push new ol.layer.Tile id: layer.id + type: layer.type + label: layer.label + sorting: layer.sorting + switcher_sorting: layer.switcher_sorting || layer.sorting + opacity_adjustable: layer.opacity_adjustable extent: layer.extent source: new ol.source.WMTS url: layer.url @@ -370,14 +519,23 @@ class KS.Layers do (layer, @layers) -> @layers.push new ol.layer.Image id: layer.id + type: layer.type + label: layer.label + switcher_sorting: layer.switcher_sorting || layer.sorting + opacity_adjustable: layer.opacity_adjustable + sorting: layer.sorting extent: layer.extent source: new ol.source.ImageWMS url: layer.url params: "LAYERS": layer.content "FORMAT": layer.format + attributions: if layer.attribution? then layer.attribution else null visible: layer.visible + @layers.sort (a, b) -> + a.get('sorting') - b.get('sorting') + @layers.push new ol.layer.Vector id: "features" source: new ol.source.Cluster @@ -683,8 +841,13 @@ if id = KS.getUrlParam('request') url += '&mobile=true' $.ajax(url: url, dataType: 'script') +KS.positionViewSwitcher= () -> + if $('.view-switcher.multiple').size() > 0 + $('.map-card').css('top', $('.view-switcher.multiple').height() + 60); + $ -> KS.olMap = new KS.Map + KS.positionViewSwitcher() $(document).on('click', 'a.describe', (event) -> if (layer = KS.layers.findById('new_feature')) && (features = layer.getSource().getFeatures()).length > 0 diff --git a/app/assets/stylesheets/application.sass b/app/assets/stylesheets/application.sass index 832fa0d8..41117612 100644 --- a/app/assets/stylesheets/application.sass +++ b/app/assets/stylesheets/application.sass @@ -16,7 +16,7 @@ *= require_tree . *= require_self */ - + @font-face font-family: 'PT Sans' src: url(asset-path('PTS55F_W.ttf')) @@ -291,6 +291,39 @@ header .sidebar-toggler.open span:before content: '\F104' +.view-switcher .map-settings-toggler + background-color: #d9edf7 + border-bottom: 1px solid #bce8f1 + border-bottom-right-radius: 4px + border-right: 1px solid #bce8f1 + border-top: 1px solid #bce8f1 + border-top-right-radius: 4px + cursor: pointer + left: 25% + padding: 0 20px + position: absolute + text-align: center + top: 100% + width: 50% + z-index: 1010 + +.view-switcher .map-settings-toggler span:before + font-family: 'Font Awesome 5 Free' + font-weight: 900 + content: "\F107" + +.view-switcher + .expand.open + .map-settings-toggler span:before + content: "\F106" + +.view-switcher span.text + display: block + font-weight: bold + text-align: center + +.view-switcher .expand span.text + margin-bottom: 0.5em + .address-search-field position: absolute background-color: #337ab7 diff --git a/app/assets/stylesheets/maps.sass b/app/assets/stylesheets/maps.sass index 7affe4fa..4b2d8297 100644 --- a/app/assets/stylesheets/maps.sass +++ b/app/assets/stylesheets/maps.sass @@ -41,7 +41,7 @@ left: .5em top: 6.75em - .view-switcher + .view-switcher:not(.multiple) left: .5em top: 9.5em @@ -57,6 +57,7 @@ span.text display: none + .ol-scale-bar, .ol-scale-line background: none background-color: transparent @@ -75,6 +76,7 @@ left: 325px top: 90px + .ol-scale-bar, .ol-scale-line left: 325px background: none @@ -103,7 +105,8 @@ border: none padding: 0 -.ol-control button +.ol-control button, +.ol-control.multiple font-weight: normal font-size: 15px background-color: #337ab7 @@ -125,10 +128,26 @@ width: 130px height: 34px +.ol-control.multiple + height: auto + text-align: left + padding: 0.5em + +.ol-control.multiple label + font-weight: normal + margin-bottom: 0.5em + +.ol-control.multiple label input + margin-right: 0.5em + +.ol-control.multiple hr + margin: 0.5em 0 + .ol-touch .ol-control button font-size: $h1-font-size +.ol-scale-bar-inner, .ol-scale-line-inner font-weight: bold color: #333 diff --git a/app/controllers/places_controller.rb b/app/controllers/places_controller.rb index 6eebec3e..c8c11cd6 100644 --- a/app/controllers/places_controller.rb +++ b/app/controllers/places_controller.rb @@ -11,7 +11,7 @@ def index end if @pattern.present? @places = [] - if Settings::AddressSearch.search_request_id_enabled && @pattern =~ /^(\d*)$/ + if Settings::Geocodr.search_request_id_enabled && @pattern =~ /^(\d*)$/ Request.where( detailed_status: Settings::Map.default_requests_states, service_request_id: ::Regexp.last_match(1) diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index 96f71918..414877b0 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -94,11 +94,12 @@ def new format.js do return new_mobile_request if @mobile + @type = params[:type] if params[:type] if params[:switch_type] @type = params[:type] else @service = Service.find(service_code) if service_code - @request = Request.new(type: @service&.type) + @request = Request.new(type: @service&.type || @type) end render "requests/#{context}/new" end diff --git a/app/helpers/requests_helper.rb b/app/helpers/requests_helper.rb index 9ec96525..d127689e 100644 --- a/app/helpers/requests_helper.rb +++ b/app/helpers/requests_helper.rb @@ -36,7 +36,7 @@ def statuses(request) end def categories(type, current = nil) - categories = Service.collection.select { |s| s.type == type }.map(&:group).uniq + categories = services_by_type(type) unless current categories.insert 0, [t('placeholder.select.category'), @@ -48,7 +48,7 @@ def categories(type, current = nil) def services(category = nil, current = nil) services = Service.collection.select { |s| s.group == category }.map do |s| [s.service_name, s.service_code] - end.insert 0, [t('placeholder.select.service'), { disabled: true, class: :placeholder }] + end.insert 0, [t('placeholder.select.service'), { disabled: true, class: :placeholder, selected: true }] options_for_select services, current end @@ -56,14 +56,22 @@ def service Service.find(service_code) if service_code end + def multiple_main_categories?(type) + services_by_type(type).size > 1 + end + + def services_by_type(type) + Service.collection.select { |s| s.type == type }.map(&:group).uniq + end + def d3_document_url(request) street = '' housenumber = '' housenumber_addition = '' - uri = URI(Settings::AddressSearch.url) + uri = URI(Settings::Geocodr.url) query = "#{request.long},#{request.lat}" - uri.query = URI.encode_www_form(key: Settings::AddressSearch.api_key, query: query, type: 'reverse', + uri.query = URI.encode_www_form(key: Settings::Geocodr.api_key, query: query, type: 'reverse', class: 'address', radius: '100', in_epsg: '4326') res = if (proxy = ENV['HTTP_PROXY'] || ENV.fetch('http_proxy', nil)).present? # Workaround for open-uri https-proxy problem diff --git a/app/models/geocodr.rb b/app/models/geocodr.rb new file mode 100644 index 00000000..d9e7d514 --- /dev/null +++ b/app/models/geocodr.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'open-uri' + +class Geocodr + class << self + def config + @config ||= Settings::Geocodr + end + + def address(issue) + order_features(issue, config.address_search_class).select do |feature| + next if feature['objektgruppe'] != config.address_object_group + return format_address(feature) + end + I18n.t 'geocodr.no_match' + end + + def address_dms(issue) + order_features(issue, config.address_search_class).select do |feature| + next if feature['objektgruppe'] != config.address_object_group + return feature + end + I18n.t 'geocodr.no_match' + end + + def parcel(issue) + order_features(issue, config.parcel_search_class).map do |feature| + next if feature['objektgruppe'] != config.parcel_object_group + return feature['flurstueckskennzeichen'] + end + I18n.t 'geocodr.no_match' + end + + def property_owner(issue) + order_features(issue, config.property_owner_search_class).map do |feature| + next if feature['objektgruppe'] != config.property_owner_object_group + return feature['eigentuemer'] + end + I18n.t 'geocodr.no_match' + end + + def search_places(pattern) + query = "#{Settings::Geocodr.try :localisator} #{pattern}".strip + request_features(query, config.places_search_class, type: :search, shape: :bbox).map { |p| Place.new(p).as_json } + end + + def find(address) + request_features(address, config.places_search_class, type: :search, out_epsg: 4326) + end + + def valid?(address) + return false unless address =~ /(\d{5})/ + attr = { zip: Regexp.last_match(1) } + address.delete! Regexp.last_match(1), ',' + return false unless address =~ /([a-zA-Zß .]*)\s(\d*)([a-zA-Z ]*)/ + attr.merge street: Regexp.last_match(1), no: Regexp.last_match(2), no_addition: Regexp.last_match(3) + end + + private + + def format_address(feature) + addr = feature['strasse_name'] + addr << " #{feature['hausnummer']}" if feature['hausnummer'].present? + addr << feature['hausnummer_zusatz'] if feature['hausnummer_zusatz'].present? + addr << " (#{feature['gemeindeteil_name']})" if feature['gemeindeteil_name'].present? + addr + end + + def order_features(issue, search_class) + return [] if (features = request_features(issue, search_class)).blank? + features.pluck('properties').sort_by { |a| a['entfernung'] } + end + + def request_features(issue, search_class, type: :reverse, shape: nil, out_epsg: nil) + uri = URI.parse(config.url) + query = issue + query = [issue.position.x, issue.position.y].join(',') if issue.respond_to?(:position) && issue.position.present? + uri.query = URI.encode_www_form(request_feature_params(query, type, search_class, shape, out_epsg)) + request_and_parse_features uri + end + + def request_feature_params(query, type, search_class, shape, out_epsg) + uri_params = { key: config.api_key, query:, type:, class: search_class, in_epsg: 4326, limit: 5 } + uri_params[:shape] = shape if shape.present? + uri_params[:out_epsg] = out_epsg if out_epsg.present? + uri_params + end + + def request_and_parse_features(uri) + if (res = uri.open(request_uri_options)) && res.status.include?('OK') + JSON.parse(res.read).try(:[], 'features') + end + rescue OpenURI::HTTPError + Rails.logger.error "Geocodr Error: #{$ERROR_INFO.inspect}, #{$ERROR_INFO.message}\n" + Rails.logger.error $ERROR_INFO.backtrace.join("\n ") + nil + end + + def request_uri_options + uri_options = { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE } + uri_options[:proxy] = URI.parse(config.proxy) if config.respond_to?(:proxy) && config.proxy.present? + uri_options + end + end +end diff --git a/app/models/place.rb b/app/models/place.rb index 32942ea5..7fadffca 100644 --- a/app/models/place.rb +++ b/app/models/place.rb @@ -6,32 +6,39 @@ class Place attr_accessor :type, :properties, :geometry def as_json(_options = {}) - { label: label(properties), bbox: bbox(geometry), transform_bbox: geometry['transform_bbox'], - feature_id: properties['feature_id'] } + { + label: format_label(properties), + bbox: format_bbox(geometry), + transform_bbox: geometry['transform_bbox'], + feature_id: properties['feature_id'] + } end private - def label(properties) - title = properties['_title_'] - title_without_community = title.split(', ')[-1] - case properties['objektgruppe'] - when 'Gemeinde' - title - when 'Gemeindeteil' - title_without_community - else - properties['abkuerzung'].blank? ? title_without_community : "#{title_without_community} (#{properties['abkuerzung']})" - end + def format_label(properties) + addr = if properties['objektgruppe'] == Settings::Geocodr.places_object_group || properties['abkuerzung'].blank? + properties['_title_'].split(', ')[-1] + else + "#{properties['_title_'].split(', ')[-1]} (#{properties['abkuerzung']})" + end + addr << " (#{properties['gemeindeteil_name']})" if properties['gemeindeteil_name'].present? + addr end - def bbox(geometry) - if geometry['type'] == 'Point' - [geometry['coordinates'][0], geometry['coordinates'][1], geometry['coordinates'][0], - geometry['coordinates'][1]] - else - [geometry['coordinates'][0][0][0], geometry['coordinates'][0][0][1], - geometry['coordinates'][0][2][0], geometry['coordinates'][0][2][1]] - end + def format_bbox(geometry) + return format_bbox_point(geometry) if geometry['type'] == 'Point' + format_bbox_prectangl(geometry) + end + + def format_bbox_point(geometry) + [geometry['coordinates'][0], geometry['coordinates'][1], geometry['coordinates'][0], geometry['coordinates'][1]] + end + + def format_bbox_prectangl(geometry) + [ + geometry['coordinates'][0][0][0], geometry['coordinates'][0][0][1], + geometry['coordinates'][0][1][0], geometry['coordinates'][0][1][1] + ] end end diff --git a/app/views/maps/_desktop.html.erb b/app/views/maps/_desktop.html.erb index de525eb5..f494b51a 100644 --- a/app/views/maps/_desktop.html.erb +++ b/app/views/maps/_desktop.html.erb @@ -23,7 +23,7 @@
- <%= text_field(:places, :search, class: 'form-control', placeholder: t(Settings::AddressSearch.search_request_id_enabled ? '.search' : '.address_search')) %> + <%= text_field(:places, :search, class: 'form-control', placeholder: t(Settings::Geocodr.search_request_id_enabled ? '.search' : '.address_search')) %>
@@ -38,7 +38,7 @@
-
+
<% %i[pending received in_process processed rejected].each do |st| -%>
@@ -49,13 +49,15 @@
<% unless service_code -%> -
+
- <% %i[problem idea].each do |type| -%> -
- <%= check_box_tag "show_#{type}", nil, true, class: 'show-feature', id: type, data: { key: 'typ' } %> - <%= label_tag type, t(type, scope: 'service.types', count: 1), class: 'check-label' %> -
+ <% %i(problem idea).each do |type| -%> + <% if Settings::Client.send "service_type_#{type}" %> +
+ <%= check_box_tag "show_#{type}", nil, true, class: 'show-feature', id: type, data: { key: 'typ' } %> + <%= label_tag type, t(type, scope: 'service.types', count: 1), class: 'check-label' %> +
+ <% end -%> <% end -%> <% if Settings::Client.respond_to?(:also_archived) && Settings::Client.also_archived -%>
diff --git a/app/views/observations/_new.html.erb b/app/views/observations/_new.html.erb index 48df58c9..7c2cfa30 100644 --- a/app/views/observations/_new.html.erb +++ b/app/views/observations/_new.html.erb @@ -17,20 +17,20 @@ <%= hidden_field_tag :area_code, @area_code if @area_code %> <%= hidden_field_tag :geometry, @geom if @geom %> <% %w[problem idea].each do |type| -%> -
-
- <%= check_box_tag type.pluralize, true, false, class: 'check-all', data: { type: type } %> - <%= label_tag type.pluralize, t("service.types.#{type}", count: 2), class: 'col-form-label' %> -
- - <% service_names(type).each do |service| -%> + <% if Settings::Client.send "service_type_#{type}" %> +
- <%= check_box_tag "#{type}_service[]", service[:id], false, class: type, - id: "#{type}_#{service[:id]}" %> - <%= label_tag "#{type}_#{service[:id]}", service[:name], class: 'check-label' %> + <%= check_box_tag type.pluralize, true, false, class: 'check-all', data: { type: type } %> + <%= label_tag type.pluralize, t("service.types.#{type}", count: 2), class: 'col-form-label' %>
- <% end -%> -
+ <% service_names(type).each do |service| -%> +
+ <%= check_box_tag "#{type}_service[]", service[:id], false, class: type, id: "#{type}_#{service[:id]}" %> + <%= label_tag "#{type}_#{service[:id]}", service[:name], class: 'check-label' %> +
+ <% end -%> +
+ <% end -%> <% end unless service_code -%> <% if service_code -%> <% service = service_name(service_code) -%> @@ -40,8 +40,7 @@ <%= label_tag type.pluralize, t("service.types.#{type}", count: 2), class: 'col-form-label' %>
- <%= check_box_tag "#{type}_service_sub[]", (code = service.service_code), true, class: type, - id: "#{type}_#{code}" %> + <%= check_box_tag "#{type}_service_sub[]", (code = service.service_code), true, class: type, id: "#{type}_#{code}" %> <%= label_tag "#{type}_#{code}", service.service_name, class: 'check-label' %>
@@ -55,4 +54,4 @@
<% end -%> -
+
\ No newline at end of file diff --git a/app/views/places/mobile/_results.html.erb b/app/views/places/mobile/_results.html.erb index 16a014c5..1f58e295 100644 --- a/app/views/places/mobile/_results.html.erb +++ b/app/views/places/mobile/_results.html.erb @@ -3,24 +3,13 @@
<%= t('.results') %>
<% @places.each do |place| -%> - <% if place.geometry['transform_bbox'] %> + <% if place['transform_bbox'] -%> <% @transform = true -%> - <% else %> + <% else -%> <% @transform = false -%> - <% end %> - <% if place.geometry['type'] == 'Point' %> - <% @bbox = [place.geometry['coordinates'][0], place.geometry['coordinates'][1], place.geometry['coordinates'][0], place.geometry['coordinates'][1]] -%> - <% else %> - <% @bbox = [place.geometry['coordinates'][0][0][0], place.geometry['coordinates'][0][0][1], place.geometry['coordinates'][0][2][0], place.geometry['coordinates'][0][2][1]] -%> - <% end %> - <%= link_to(map_path(bbox: @bbox, mobile: @mobile), remote: true, class: 'list-group-item', data: { transform: @transform }) do %> - <% if place.properties['objektgruppe'] == 'Gemeindeteil' %> - <%= place.properties['_title_'].split(', ')[-1] %> - <% elsif not place.properties['abkuerzung'].blank? %> - <%= "#{place.properties['_title_'].split(', ')[-1]} (#{place.properties['abkuerzung']})" %> - <% else %> - <%= place.properties['_title_'].split(', ')[-1] %> - <% end %> + <% end -%> + <%= link_to(map_path(bbox: place[:bbox], mobile: @mobile), remote: true, class: 'list-group-item', :data => { :transform => @transform }) do %> + <%= place[:label] %> <% end %> <% end -%> diff --git a/app/views/requests/_edit.html.erb b/app/views/requests/_edit.html.erb index 5cda9400..9820c95e 100644 --- a/app/views/requests/_edit.html.erb +++ b/app/views/requests/_edit.html.erb @@ -53,7 +53,7 @@
<%= f.label(:media, Request.human_attribute_name(:media), class: 'col-form-label') %>
- <%= f.file_field(:media, multiple: false, accept: 'image/png,image/jpeg') %> + <%= f.file_field(:media, multiple: false, accept: Settings::Client.supported_file_types) %>
diff --git a/app/views/requests/desktop/_campaign_form.html.erb b/app/views/requests/desktop/_campaign_form.html.erb index 8c7ca68c..7ba75a87 100644 --- a/app/views/requests/desktop/_campaign_form.html.erb +++ b/app/views/requests/desktop/_campaign_form.html.erb @@ -33,7 +33,7 @@ <%= f.label(:media, Request.human_attribute_name(:media), class: 'col-12 col-form-label') %>
<%= t('.photo_hint') %>
- <%= f.file_field(:media, multiple: false, accept: 'image/png,image/jpeg') %> + <%= f.file_field(:media, multiple: false, accept: Settings::Client.supported_file_types) %>
diff --git a/app/views/requests/desktop/_category_select.html.erb b/app/views/requests/desktop/_category_select.html.erb index 1ee8e7cc..969139c4 100644 --- a/app/views/requests/desktop/_category_select.html.erb +++ b/app/views/requests/desktop/_category_select.html.erb @@ -1,9 +1,11 @@
-
- <%= select_tag(:request_category, categories(type, category), id: :request_category_1, - class: 'form-select', data: { update: :request_service_code_1 }) %> -
+ <% if multiple_main_categories?(type) -%> +
+ <%= select_tag(:request_category, categories(type, category), + id: :request_category_1, class: 'form-select', data: { update: :request_service_code_1 }) %> +
+ <% end -%>
<%= select_tag(:request_service_code, services(category, service_code), id: :request_service_code_1, class: 'form-select', name: 'request[service_code][]', @@ -23,15 +25,16 @@
<% if multi_requests_enabled? -%> +
\ No newline at end of file diff --git a/app/views/requests/mobile/_new.html.erb b/app/views/requests/mobile/_new.html.erb index a6be8a2e..4b145b67 100644 --- a/app/views/requests/mobile/_new.html.erb +++ b/app/views/requests/mobile/_new.html.erb @@ -13,24 +13,26 @@
<% unless login_required? -%>
<%= t('.problem_or_idea') %>
<% end -%>
- <%= radio_button :request, :type, 'problem', class: 'radio-type' %> <%= label_tag :request_type_problem, - t('problem', scope: 'service.types', count: 1), class: 'check-label' %> -
-
- <%= radio_button :request, :type, 'idea', class: 'radio-type' %> <%= label_tag :request_type_idea, - t('idea', scope: 'service.types', count: 1), class: 'check-label' %> + <%= radio_button :request, :type, 'problem', class: 'radio-type' %> + <%= label_tag :request_type_problem, t('problem', scope: 'service.types', count: 1), class: 'check-label' %>
+ <% if Settings::Client.service_type_idea %> +
+ <%= radio_button :request, :type, 'idea', class: 'radio-type' %> + <%= label_tag :request_type_idea, t('idea', scope: 'service.types', count: 1), class: 'check-label' %> +
+ <% end -%> <% if login_required? -%>
- <%= radio_button :request, :type, 'tip', class: 'radio-type' %> <%= label_tag :request_type_tip, - t('tip', scope: 'service.types', count: 1), class: 'check-label' %> + <%= radio_button :request, :type, 'tip', class: 'radio-type' %> + <%= label_tag :request_type_tip, t('tip', scope: 'service.types', count: 1), class: 'check-label' %>
<% end -%>
<% unless login_required? -%>
+ data-idea="<%= t('.describe_idea') %>">
<% end -%> @@ -88,7 +90,8 @@ <%= label_tag(:request_media, Request.human_attribute_name(:media), class: 'col-12 col-form-label') %> <% unless login_required? -%>
<%= t('.photo_hint') %>
<% end -%>
- <%= file_field(:request, :media, multiple: false, accept: 'image/png,image/jpeg', capture: 'environment') %> + <%= file_field(:request, :media, multiple: false, accept: Settings::Client.supported_file_types, + capture: Settings::Client.file_upload_capture) %>
<% unless login_required? -%> diff --git a/app/views/requests/mobile/_show.html.erb b/app/views/requests/mobile/_show.html.erb index dbd98a47..effbf1ed 100644 --- a/app/views/requests/mobile/_show.html.erb +++ b/app/views/requests/mobile/_show.html.erb @@ -53,10 +53,12 @@
<% end -%>
-
-

<%= Service.human_attribute_name(:group) %>

-

<%= @request.service.group %>

-
+ <% if multiple_main_categories?(@request.type) %> +
+

<%= Service.human_attribute_name(:group) %>

+

<%= @request.service.group %>

+
+ <% end -%>

<%= Service.human_attribute_name(:service_name) %>

<%= @request.service %>

@@ -124,7 +126,7 @@ <%= hidden_field_tag :mobile, @mobile %>
- <%= f.file_field(:media, multiple: false, accept: 'image/png,image/jpeg') %> + <%= f.file_field(:media, multiple: false, accept: Settings::Client.supported_file_types) %>
diff --git a/app/views/starts/_mobile.html.erb b/app/views/starts/_mobile.html.erb index 44c5d5c3..5af84e87 100644 --- a/app/views/starts/_mobile.html.erb +++ b/app/views/starts/_mobile.html.erb @@ -22,4 +22,4 @@ <%= render(partial: 'shared/statistic', locals: { css_col: 'col-12' }) %>
-
+
\ No newline at end of file diff --git a/config/locales/de.yml b/config/locales/de.yml index 4fd2899b..622b7133 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -494,3 +494,4 @@ de: top5: "Top 5" request_count: "Meldungen (mit gewählten Filtern)" notice: "Für weiterführende Analysen nutzen Sie gerne unseren RSS-Feed, die API, oder kontaktieren Sie uns." + diff --git a/config/settings.sample.yml b/config/settings.sample.yml index 7e79aa5d..0fc11be6 100644 --- a/config/settings.sample.yml +++ b/config/settings.sample.yml @@ -30,6 +30,8 @@ development: &default new_icon_anchor_y: 50 service_type_idea: true service_type_problem: true + skip_type_selection: false + default_type: show_social_icons: true show_email: show_abuses: @@ -45,6 +47,8 @@ development: &default show_status_updates_for_supporter: additional_content: false start_date: 28.03.2012 + supported_file_types: image/png,image/jpeg + file_upload_capture: environment max_image_size: 5242880 show_privacy_policy: false @@ -59,9 +63,9 @@ development: &default resource_servers: city_sdk: - site: http://172.17.0.1:3001/citysdk/ + site: https://klarschiff.de/citysdk/ format: :json - api_key: + api_key: 1234567890abcdefghijklmnopqrstuv address_search: url: https://geo.sv.rostock.de/geocodr/query? @@ -69,6 +73,21 @@ development: &default localisator: rostock search_request_id_enabled: true + geocodr: + address_object_group: Adresse HRO + address_search_class: address_hro + api_key: 1234567890abcdefghijklmnopqrstuv + localisator: rostock # darf leer sein + parcel_object_group: Flurstück + parcel_search_class: parcel + places_object_group: Adresse + places_search_class: address + property_owner_object_group: Flurstückseigentümer + property_owner_search_class: property_owner + proxy: + url: https://geo.sv.rostock.de/geocodr/query? + search_request_id_enabled: true + protocol_mail: recipient: recipient@klarschiff.de sender: sender@klarschiff.de @@ -80,6 +99,8 @@ development: &default map: show_trust: true + overlap_layers: false + scale_bar: false default_requests_states: PENDING, RECEIVED, IN_PROCESS, PROCESSED, REJECTED center: [308555, 6000550] mv_bbox_25833: [206885, 5890624, 460857, 6060841] @@ -136,6 +157,7 @@ development: &default initial: 6 max: 14 min: 5 + resolution: false request: permissable_states: