• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geosolutions-it / MapStore2 / 12882591459

21 Jan 2025 08:07AM UTC coverage: 77.203% (+0.07%) from 77.13%
12882591459

Pull #10712

github

web-flow
Merge e1da172c8 into d3d0ee6c5
Pull Request #10712: Enhancing User Session #10657

30454 of 47261 branches covered (64.44%)

145 of 185 new or added lines in 15 files covered. (78.38%)

432 existing lines in 29 files now uncovered.

37881 of 49067 relevant lines covered (77.2%)

35.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.73
/web/client/components/map/openlayers/plugins/WMSLayer.js
1
/*
2
 * Copyright 2017, GeoSolutions Sas.
3
 * All rights reserved.
4
 *
5
 * This source code is licensed under the BSD-style license found in the
6
 * LICENSE file in the root directory of this source tree.
7
 */
8

9
import Layers from '../../../../utils/openlayers/Layers';
10
import isNil from 'lodash/isNil';
11
import isEqual from 'lodash/isEqual';
12
import union from 'lodash/union';
13
import isArray from 'lodash/isArray';
14
import assign from 'object-assign';
15
import axios from '../../../../libs/ajax';
16
import CoordinatesUtils from '../../../../utils/CoordinatesUtils';
17
import { getProjection } from '../../../../utils/ProjectionUtils';
18
import { getConfigProp } from '../../../../utils/ConfigUtils';
19

20
import {optionsToVendorParams} from '../../../../utils/VendorParamsUtils';
21
import {addAuthenticationToSLD, addAuthenticationParameter, getAuthenticationHeaders} from '../../../../utils/SecurityUtils';
22

23
import ImageLayer from 'ol/layer/Image';
24
import ImageWMS from 'ol/source/ImageWMS';
25
import {get} from 'ol/proj';
26
import TileLayer from 'ol/layer/Tile';
27
import TileWMS from 'ol/source/TileWMS';
28

29
import VectorTileSource from 'ol/source/VectorTile';
30
import VectorTileLayer from 'ol/layer/VectorTile';
31

32
import { isVectorFormat } from '../../../../utils/VectorTileUtils';
33
import { isValidResponse } from '../../../../utils/WMSUtils';
34
import { OL_VECTOR_FORMATS, applyStyle } from '../../../../utils/openlayers/VectorTileUtils';
35

36
import { proxySource, getWMSURLs, wmsToOpenlayersOptions, toOLAttributions, generateTileGrid } from '../../../../utils/openlayers/WMSUtils';
37

38
const loadFunction = (options, headers) => function(image, src) {
50✔
39
    // fixes #3916, see https://gis.stackexchange.com/questions/175057/openlayers-3-wms-styling-using-sld-body-and-post-request
40
    let img = image.getImage();
51✔
41
    let newSrc = proxySource(options.forceProxy, src);
50✔
42

43
    if (typeof window.btoa === 'function' && src.length >= (options.maxLengthUrl || getConfigProp('miscSettings')?.maxURLLength || Infinity)) {
50✔
44
        // GET ALL THE PARAMETERS OUT OF THE SOURCE URL**
45
        let [url, ...dataEntries] = src.split("&");
5✔
46
        url = proxySource(options.forceProxy, url);
5✔
47

48
        // SET THE PROPER HEADERS AND FINALLY SEND THE PARAMETERS
49
        axios.post(url, "&" + dataEntries.join("&"), {
5✔
50
            headers: {
51
                "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
52
                ...headers
53
            },
54
            responseType: 'arraybuffer'
55
        }).then(response => {
56
            if (response.status === 200) {
5!
57
                const uInt8Array = new Uint8Array(response.data);
5✔
58
                let i = uInt8Array.length;
5✔
59
                const binaryString = new Array(i);
5✔
60
                while (i--) {
5✔
UNCOV
61
                    binaryString[i] = String.fromCharCode(uInt8Array[i]);
×
62
                }
63
                const dataImg = binaryString.join('');
5✔
64
                const type = response.headers['content-type'];
5✔
65
                if (type.indexOf('image') === 0) {
5!
66
                    img.src = 'data:' + type + ';base64,' + window.btoa(dataImg);
5✔
67
                }
68
            }
69
        }).catch(e => {
UNCOV
70
            console.error(e);
×
71
        });
72
    } else {
73
        if (headers) {
45✔
74
            axios.get(newSrc, {
4✔
75
                headers,
76
                responseType: 'blob'
77
            }).then(response => {
78
                if (isValidResponse(response)) {
4!
79
                    image.getImage().src = URL.createObjectURL(response.data);
4✔
80
                } else {
81
                    // #10701 this is needed to trigger the imageloaderror event
82
                    // in ol otherwise this event is not triggered if you assign
83
                    // the xml content of the exception to the src attribute
UNCOV
84
                    image.getImage().src = null;
×
UNCOV
85
                    console.error("error: " + response.data);
×
86
                }
87
            }).catch(e => {
88
                console.error(e);
4✔
89
            });
90
        } else {
91
            img.src = newSrc;
41✔
92
        }
93
    }
94
};
95

96
const createLayer = (options, map, mapId) => {
1✔
97
    // the useForElevation in wms types will be deprecated
98
    // as support for existing configuration
99
    // we can use this fallback
100
    if (options.useForElevation) {
54✔
101
        return Layers.createLayer('elevation', {
4✔
102
            ...options,
103
            provider: 'wms'
104
        }, map, mapId);
105
    }
106
    const urls = getWMSURLs(isArray(options.url) ? options.url : [options.url]);
50✔
107
    const queryParameters = wmsToOpenlayersOptions(options) || {};
50!
108
    urls.forEach(url => addAuthenticationParameter(url, queryParameters, options.securityToken));
52✔
109
    const headers = getAuthenticationHeaders(urls[0], options.securityToken);
50✔
110
    const vectorFormat = isVectorFormat(options.format);
50✔
111

112
    if (options.singleTile && !vectorFormat) {
50✔
113
        return new ImageLayer({
8✔
114
            msId: options.id,
115
            opacity: options.opacity !== undefined ? options.opacity : 1,
8✔
116
            visible: options.visibility !== false,
117
            zIndex: options.zIndex,
118
            minResolution: options.minResolution,
119
            maxResolution: options.maxResolution,
120
            source: new ImageWMS({
121
                url: urls[0],
122
                crossOrigin: options.crossOrigin,
123
                attributions: toOLAttributions(options.credits),
124
                params: queryParameters,
125
                ratio: options.ratio || 1,
15✔
126
                imageLoadFunction: loadFunction(options, headers)
127
            })
128
        });
129
    }
130
    const sourceOptions = {
42✔
131
        attributions: toOLAttributions(options.credits),
132
        urls: urls,
133
        crossOrigin: options.crossOrigin,
134
        params: queryParameters,
135
        tileGrid: generateTileGrid(options, map),
136
        tileLoadFunction: loadFunction(options, headers)
137
    };
138
    const wmsSource = new TileWMS({ ...sourceOptions });
42✔
139
    const layerConfig = {
42✔
140
        msId: options.id,
141
        opacity: options.opacity !== undefined ? options.opacity : 1,
42✔
142
        visible: options.visibility !== false,
143
        zIndex: options.zIndex,
144
        minResolution: options.minResolution,
145
        maxResolution: options.maxResolution
146
    };
147
    let layer;
148
    if (vectorFormat) {
42✔
149
        layer = new VectorTileLayer({
5✔
150
            ...layerConfig,
151
            source: new VectorTileSource({
152
                ...sourceOptions,
153
                format: new OL_VECTOR_FORMATS[options.format]({
154
                    layerName: '_layer_'
155
                }),
UNCOV
156
                tileUrlFunction: (tileCoord, pixelRatio, projection) => wmsSource.tileUrlFunction(tileCoord, pixelRatio, projection)
×
157
            })
158
        });
159
    } else {
160

161
        layer = new TileLayer({
37✔
162
            ...layerConfig,
163
            source: wmsSource
164
        });
165
    }
166
    layer.set('map', map);
42✔
167
    if (vectorFormat) {
42✔
168
        layer.set('wmsSource', wmsSource);
5✔
169
        if (options.vectorStyle) {
5✔
170
            applyStyle(options.vectorStyle, layer, map);
2✔
171
        }
172
    }
173
    return layer;
42✔
174
};
175

176
const mustCreateNewLayer = (oldOptions, newOptions) => {
1✔
177
    return (oldOptions.singleTile !== newOptions.singleTile
17✔
178
        || oldOptions.securityToken !== newOptions.securityToken
179
        || oldOptions.ratio !== newOptions.ratio
180
        // no way to remove attribution when credits are removed, so have re-create the layer is needed. Seems to be solved in OL v5.3.0, due to the ol commit 9b8232f65b391d5d381d7a99a7cd070fc36696e9 (https://github.com/openlayers/openlayers/pull/7329)
181
        || oldOptions.credits !== newOptions.credits && !newOptions.credits
182
        || isVectorFormat(oldOptions.format) !== isVectorFormat(newOptions.format)
183
        || isVectorFormat(oldOptions.format) && isVectorFormat(newOptions.format) && oldOptions.format !== newOptions.format
184
        || oldOptions.localizedLayerStyles !== newOptions.localizedLayerStyles
185
        || oldOptions.tileSize !== newOptions.tileSize
186
        || oldOptions.forceProxy !== newOptions.forceProxy
187
        || oldOptions.tileGridStrategy !== newOptions.tileGridStrategy
188
        || !isEqual(oldOptions.tileGrids, newOptions.tileGrids)
189
    );
190
};
191

192
Layers.registerType('wms', {
1✔
193
    create: createLayer,
194
    update: (layer, newOptions, oldOptions, map) => {
195
        const newIsVector = isVectorFormat(newOptions.format);
17✔
196

197
        if (mustCreateNewLayer(oldOptions, newOptions)) {
17✔
198
            // TODO: do we need to clean anything before re-creating stuff from scratch?
199
            return createLayer(newOptions, map);
6✔
200
        }
201
        let needsRefresh = false;
11✔
202
        if (newIsVector && newOptions.vectorStyle && !isEqual(newOptions.vectorStyle, oldOptions.vectorStyle || {})) {
11!
UNCOV
203
            applyStyle(newOptions.vectorStyle, layer, map);
×
UNCOV
204
            needsRefresh = true;
×
205
        }
206

207
        const wmsSource = layer.get('wmsSource') || layer.getSource();
11✔
208
        const vectorSource = newIsVector ? layer.getSource() : null;
11!
209

210
        if (oldOptions.srs !== newOptions.srs) {
11!
211
            const normalizedSrs = CoordinatesUtils.normalizeSRS(newOptions.srs, newOptions.allowedSRS);
×
212
            const extent = get(normalizedSrs).getExtent() || getProjection(normalizedSrs).extent;
×
213
            if (newOptions.singleTile && !newIsVector) {
×
214
                layer.setExtent(extent);
×
215
            } else {
UNCOV
216
                const tileGrid = generateTileGrid(newOptions, map);
×
217
                wmsSource.tileGrid = tileGrid;
×
UNCOV
218
                if (vectorSource) {
×
UNCOV
219
                    vectorSource.tileGrid = tileGrid;
×
220
                }
221
            }
UNCOV
222
            needsRefresh = true;
×
223
        }
224

225
        if (oldOptions.credits !== newOptions.credits && newOptions.credits) {
11✔
226
            wmsSource.setAttributions(toOLAttributions(newOptions.credits));
3✔
227
            needsRefresh = true;
3✔
228
        }
229

230
        let changed = false;
11✔
231
        let oldParams;
232
        let newParams;
233
        if (oldOptions && wmsSource && wmsSource.updateParams) {
11!
234
            if (oldOptions.params && newOptions.params) {
11✔
235
                changed = union(
4✔
236
                    Object.keys(oldOptions.params),
237
                    Object.keys(newOptions.params)
238
                ).reduce((found, param) => {
239
                    if (newOptions.params[param] !== oldOptions.params[param]) {
5✔
240
                        return true;
3✔
241
                    }
242
                    return found;
2✔
243
                }, false);
244
            } else if ((!oldOptions.params && newOptions.params) || (oldOptions.params && !newOptions.params)) {
7!
UNCOV
245
                changed = true;
×
246
            }
247
            oldParams = wmsToOpenlayersOptions(oldOptions);
11✔
248
            newParams = wmsToOpenlayersOptions(newOptions);
11✔
249
            changed = changed || ["LAYERS", "STYLES", "FORMAT", "TRANSPARENT", "TILED", "VERSION", "_v_", "CQL_FILTER", "SLD", "VIEWPARAMS"].reduce((found, param) => {
11✔
250
                if (oldParams[param] !== newParams[param]) {
80✔
251
                    return true;
2✔
252
                }
253
                return found;
78✔
254
            }, false);
255

256
            needsRefresh = needsRefresh || changed;
11✔
257
        }
258

259
        if (oldOptions.minResolution !== newOptions.minResolution) {
11✔
260
            layer.setMinResolution(newOptions.minResolution === undefined ? 0 : newOptions.minResolution);
1!
261
        }
262
        if (oldOptions.maxResolution !== newOptions.maxResolution) {
11✔
263
            layer.setMaxResolution(newOptions.maxResolution === undefined ? Infinity : newOptions.maxResolution);
1!
264
        }
265
        if (needsRefresh) {
11✔
266
            // forces tile cache drop
267
            // this prevents old cached tiles at lower zoom levels to be
268
            // rendered during new params load
269
            wmsSource?.tileCache?.pruneExceptNewestZ?.();
8✔
270
            if (vectorSource) {
8!
UNCOV
271
                vectorSource.clear();
×
UNCOV
272
                vectorSource.refresh();
×
273
            }
274

275
            if (changed) {
8✔
276
                const params = assign(newParams, addAuthenticationToSLD(optionsToVendorParams(newOptions) || {}, newOptions));
5✔
277

278
                wmsSource.updateParams(assign(params, Object.keys(oldParams || {}).reduce((previous, key) => {
5!
279
                    return !isNil(params[key]) ? previous : assign(previous, {
45✔
280
                        [key]: undefined
281
                    });
282
                }, {})));
283
            }
284
        }
285
        return null;
11✔
286
    }
287
});
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc