decidim 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of decidim might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/docs/advanced/endorsable.md +1 -1
- data/docs/advanced/fixing_locales.md +88 -0
- data/docs/advanced/how_to_fix_metrics.md +2 -2
- data/docs/advanced/machine_translation_service.md +12 -0
- data/docs/advanced/profiling.md +43 -0
- data/docs/advanced/releases.md +28 -19
- data/docs/advanced/share_tokens.md +53 -0
- data/docs/advanced/templates.md +56 -0
- data/docs/customization/machine_translations.md +30 -0
- data/docs/customization/maps.md +610 -0
- data/docs/development_guide.md +27 -10
- data/docs/getting_started.md +3 -1
- data/docs/services/elections_bulletin_board.md +38 -0
- data/docs/services/maps.md +362 -0
- data/lib/decidim/version.rb +1 -1
- metadata +65 -43
- data/docs/services/geocoding.md +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdeead0aa618f802267b9ed377a9fc23d4c2a0a22e0ef3e094e9e62ccc895831
|
4
|
+
data.tar.gz: 1233ee1cff0faf014b42b598513e88f948a4cb3f0ea03ead28ba845a43ef1ab8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e021705268401293b0c5ac1d6819a7a4a923287704f6c821c4eb280c5da8e8fbf41793153cf22c25a9cc01b020a4dd7bd0dc006ee492525619a7ff87ff51922f
|
7
|
+
data.tar.gz: d0e7107f58300aa4569d6b50619cec053fd8691b1fcf592350913603a14bf6141ee7d8596baed3f4f6a27cc58c2b1fee757a6306c99061fb249b9ed6df6dd154
|
data/README.md
CHANGED
@@ -62,6 +62,7 @@ Test suite
|
|
62
62
|
|
63
63
|
# What do you need to do?
|
64
64
|
|
65
|
+
* [Official Documentation](https://docs.decidim.org/) **[NOT UP TO DATE]**
|
65
66
|
* [Getting started with Decidim](#getting-started-with-decidim)
|
66
67
|
* [Contribute to the project](#how-to-contribute)
|
67
68
|
* [Modules](#modules)
|
data/docs/advanced/endorsable.md
CHANGED
@@ -43,7 +43,7 @@ end
|
|
43
43
|
|
44
44
|
It is a good practice to give the opportunity to the admin to switch Endorsements on and off.
|
45
45
|
|
46
|
-
There are two switches that are normally defined in the manifest of the element in the following way:
|
46
|
+
There are two switches that are normally defined in the manifest of the element in the following way (usually this would be at component.rb in a Decidim engine):
|
47
47
|
|
48
48
|
```ruby
|
49
49
|
settings.attribute :endorsements_enabled, type: :boolean, default: true
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Fixing locales
|
2
|
+
|
3
|
+
Sometimes in production environments you are force to change the locales available for an organization.
|
4
|
+
|
5
|
+
However, this may be delicate, specially if you need to remove them.
|
6
|
+
|
7
|
+
## Change the available languages of an organization
|
8
|
+
|
9
|
+
When you create an organization, you choose the available languages for it (through the `/system/` url). However, when trying to edit it, the language selector is not available anymore. Here is a way to update that locales manually:
|
10
|
+
|
11
|
+
First, make sure that your initializer file has all the locales you want:
|
12
|
+
|
13
|
+
Edit the file `config/initializers/decidim.rb` and be sure to include all the necessary locales:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
...
|
17
|
+
# Change these lines to set your preferred locales
|
18
|
+
config.default_locale = :en
|
19
|
+
config.available_locales = [:en, :ca, :es, :fr, :pt]
|
20
|
+
..
|
21
|
+
```
|
22
|
+
|
23
|
+
Then you need to access the rails console and update the organization locales manually.
|
24
|
+
|
25
|
+
Access to your rails console and select your organization. If you have only one organization you can just run the command:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
o=Decidim::Organization.first
|
29
|
+
```
|
30
|
+
|
31
|
+
Check your current locales:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
o.available_locales
|
35
|
+
=> ["en", "ca", "es"]
|
36
|
+
```
|
37
|
+
|
38
|
+
Then add or remove locales and save the organization.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
o.available_locales += ["fr", "pt"]
|
42
|
+
=> ["en", "ca", "es", "pt", "fr"]
|
43
|
+
o.save!
|
44
|
+
```
|
45
|
+
|
46
|
+
If you want to change the default locale:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
o.default_locale = "fr"
|
50
|
+
o.save!
|
51
|
+
```
|
52
|
+
|
53
|
+
> If you need to remove locales from an organization read the next section!
|
54
|
+
|
55
|
+
## Fixing errors in locales
|
56
|
+
|
57
|
+
In certain cases (ie. when removing locales from an organization) some operations in Decidim may lead to errors 500 in the browser.
|
58
|
+
|
59
|
+
In order to solve that you can make use of these rake tasks:
|
60
|
+
|
61
|
+
### Synchronize Locales
|
62
|
+
|
63
|
+
```bash
|
64
|
+
bundle exec rake decidim:locales:sync_all
|
65
|
+
```
|
66
|
+
|
67
|
+
Run this task if you have changed `available_locales` or `default_locale` in `config/initializers/decidim.rb` and you think that some organization have values not supported by the Decidim installation.
|
68
|
+
|
69
|
+
Examples:
|
70
|
+
|
71
|
+
* `Decidim.available_locales` is set to `[:en, :ca, :fr]` and your organization has `available_locales` to `[:es, :ca]`, running this script will change it to `[:ca]` as `:es` is not supported.
|
72
|
+
* `organization.default_locale` is set to `:fr` and your `available_locales` to `[:en, :es]`, running this script will change `organization.default_locale` to `:en`.
|
73
|
+
|
74
|
+
It is safe to run this task as it respects organizations with less languages than the supported.
|
75
|
+
|
76
|
+
### Repair the search index
|
77
|
+
|
78
|
+
In order to provide a global search in Decidim, many content is indexed in a search table, each locale separately.
|
79
|
+
This means that, if you remove languages, some content can be orphan as the original resource do not exist anymore.
|
80
|
+
This leads to server 500 errors.
|
81
|
+
|
82
|
+
To repair the search index you can run the rake task:
|
83
|
+
|
84
|
+
```bash
|
85
|
+
bundle exec rake decidim:locales:rebuild_search
|
86
|
+
```
|
87
|
+
|
88
|
+
Be aware that this might take a long time as it will remove and recreate the whole search index for all organizations.
|
@@ -27,13 +27,13 @@ We cannot offer a definitive solution for duplicate metrics, other than to delet
|
|
27
27
|
For a given metric type (`rake decidim:metrics:list`) that has duplicates:
|
28
28
|
|
29
29
|
- Option 1: Remove individually each metric record per day.
|
30
|
-
- Option 2: Delete all metric records and recalculate them. [CHANGELOG](https://github.com/decidim/decidim/blob/0.18-stable/CHANGELOG.md#participants-metrics) of decidim version 0.18 has an example for "participants".
|
30
|
+
- Option 2: Delete all metric records and recalculate them. [CHANGELOG](https://github.com/decidim/decidim/blob/release/0.18-stable/CHANGELOG.md#participants-metrics) of decidim version 0.18 has an example for "participants".
|
31
31
|
|
32
32
|
For orphan records, you can do the following:
|
33
33
|
|
34
34
|
- Back up the database.
|
35
35
|
- Delete orphan records fromt the console (code is below).
|
36
|
-
- Delete "comments" metrics and recalculate them following the [aforementioned example](https://github.com/decidim/decidim/blob/0.18-stable/CHANGELOG.md#participants-metrics).
|
36
|
+
- Delete "comments" metrics and recalculate them following the [aforementioned example](https://github.com/decidim/decidim/blob/release/0.18-stable/CHANGELOG.md#participants-metrics).
|
37
37
|
|
38
38
|
### Some queries that may help
|
39
39
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Create your own machine translation service
|
2
|
+
|
3
|
+
You can use the `Decidim::Dev::DummyTranslator` service as a base. Any new translator service will need to implement the same API as this class.
|
4
|
+
|
5
|
+
## Integrating with async services
|
6
|
+
|
7
|
+
Some translation services are async, which means that some extra work is needed. This is the main overview:
|
8
|
+
|
9
|
+
- The Translation service will only send the translation request. It should have a way to send what resource, field and target locale are related to that translation.
|
10
|
+
- You'll need to create a custom controller in your application to receive the callback from the translation service when the translation is finished
|
11
|
+
- From that new endpoint, find a way to find the related resource, field and target locale. Then start a `Decidim::MachineTranslationSaveJob` with that data. This job will handle how to save the data in the DB.
|
12
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# How to profile a Decidim app
|
2
|
+
|
3
|
+
The developmen_app includes a bunch of gems that profile the application. Run the following command in the decidim root's folder:
|
4
|
+
|
5
|
+
```bash
|
6
|
+
bundle exec rake development_app
|
7
|
+
```
|
8
|
+
|
9
|
+
and then move into it and boot the server
|
10
|
+
|
11
|
+
```bash
|
12
|
+
cd developmen_app
|
13
|
+
bundle exec rails s
|
14
|
+
```
|
15
|
+
|
16
|
+
## Bullet
|
17
|
+
|
18
|
+
Bullet detects N+1 queries and suggests how to fix them, although it doesn't catch them all. It's currently configured in `config/initializers/bullet.rb` to log in the regular rails log and also in its own `log/bullet.log`. You'll now see entries like the following:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
user: xxx
|
22
|
+
GET /
|
23
|
+
USE eager loading detected
|
24
|
+
Decidim::Comments::Comment => [:author]
|
25
|
+
Add to your query: .includes([:author])
|
26
|
+
Call stack
|
27
|
+
```
|
28
|
+
|
29
|
+
It also warns you when there's an unnecessary eager load.
|
30
|
+
|
31
|
+
More details: https://github.com/flyerhzm/bullet
|
32
|
+
|
33
|
+
## Rack-mini-profiler
|
34
|
+
|
35
|
+
This gem can analyze memory, database, and call stack with flamegraphs. It will show up in development on the top left corner and it gives you all sorts of profiling insights about that page. It'll tell you where the response time was spend on in the call stack.
|
36
|
+
|
37
|
+
This gem is further enhanced with the `flamegraph`, `stackprof` and `memory_profiler` gems which provide more detailed analysis. Try out by appending `?pp=flamegraph`, `?pp=profile-gc` or `?pp=analyze-memory` to the URL. You can read more about these options at https://github.com/MiniProfiler/rack-mini-profiler#flamegraphs.
|
38
|
+
|
39
|
+
More details: https://github.com/MiniProfiler/rack-mini-profiler
|
40
|
+
|
41
|
+
## Profiling best practices
|
42
|
+
|
43
|
+
You need to take the insights of these gems with a grain of salt though, if you run this in development. Rails' development settings have nothing to do with a production set up where classes are not reloaded and assets are precompiled and served from a web server. Therefore, you should mimic these settings as much as possible if you want your findings to be realistic.
|
data/docs/advanced/releases.md
CHANGED
@@ -4,10 +4,10 @@ In order to release new version you need to be owner of all the gems at RubyGems
|
|
4
4
|
|
5
5
|
Remember to follow the Gitflow branching workflow.
|
6
6
|
|
7
|
-
## Create the
|
7
|
+
## Create the stable branch for the release
|
8
8
|
|
9
9
|
1. Go to develop with `git checkout develop`
|
10
|
-
1. Create the release branch `git checkout -b release/x.y.z && git push origin release/x.y.z
|
10
|
+
1. Create the release branch `git checkout -b release/x.y.z-stable && git push origin release/x.y.z-stable`.
|
11
11
|
1. If required, add the release branch to Crowdin so that any pending translations will generate a PR to this branch.
|
12
12
|
|
13
13
|
Mark `develop` as the reference to the next release:
|
@@ -39,7 +39,7 @@ Mark `develop` as the reference to the next release:
|
|
39
39
|
|
40
40
|
## Previous versions
|
41
41
|
|
42
|
-
Please check [0.XX-stable](https://github.com/decidim/decidim/blob/0.XX-stable/CHANGELOG.md) for previous changes.
|
42
|
+
Please check [0.XX-stable](https://github.com/decidim/decidim/blob/release/0.XX-stable/CHANGELOG.md) for previous changes.
|
43
43
|
```
|
44
44
|
|
45
45
|
1. Push the changes `git add . && git commit -m "Bump develop to next release version" && git push origin develop`
|
@@ -50,46 +50,55 @@ Release Candidates are the same as beta versions. They should be ready to go to
|
|
50
50
|
|
51
51
|
If this is a **Release Candidate version** release, the steps to follow are:
|
52
52
|
|
53
|
-
1.
|
53
|
+
1. Checkout the release stable branch `git checkout release/x.y-stable`.
|
54
54
|
1. Update `.decidim-version` to the new version `x.y.z.rc1`
|
55
55
|
1. Run `bin/rake update_versions`, this will update all references to the new version.
|
56
56
|
1. Run `bin/rake bundle`, this will update all the `Gemfile.lock` files
|
57
57
|
1. Run `bin/rake webpack`, this will update the JavaScript bundle.
|
58
|
-
1. Commit all the changes: `git add . && git commit -m "Bump to rcXX version" && git push origin release/x.y
|
59
|
-
1.
|
58
|
+
1. Commit all the changes: `git add . && git commit -m "Bump to rcXX version" && git push origin release/x.y-stable`.
|
59
|
+
1. Tag the release candidate with `git tag vX.Y.Z.rcN && git push origin vX.Y.Z.rcN`.
|
60
60
|
1. Usually, at this point, the release branch is deployed to meta-decidim during, at least, one week to validate the stability of the version.
|
61
61
|
|
62
62
|
### During the validation period
|
63
63
|
|
64
|
-
1. During the validation period bugfixes
|
65
|
-
1. During the validation period, translations to the officially supported languages must be added to Crowdin and when
|
64
|
+
1. During the validation period, bugfixes must be implemented directly to the current `release/x.y.z-stable` branch and ported to `develop`.
|
65
|
+
1. During the validation period, translations to the officially supported languages must be added to Crowdin and, when completed, merged into `release/x.y.z-stable`.
|
66
66
|
|
67
|
-
|
67
|
+
## Major/Minor versions
|
68
68
|
|
69
69
|
Release Candidates will be tested in a production server (usually meta-decidim) during some period of time (a week at least), when they are considered ready, it is time for them to be merged into `master`:
|
70
70
|
|
71
|
-
1.
|
71
|
+
1. Checkout the release stable branch `git checkout release/x.y-stable`.
|
72
72
|
1. Update `.decidim-version` by removing the `.rcN` suffix, leaving a clean version number like `x.y.z`
|
73
73
|
1. Run `bin/rake update_versions`, this will update all references to the new version.
|
74
74
|
1. Run `bin/rake bundle`, this will update all the `Gemfile.lock` files
|
75
75
|
1. Run `bin/rake webpack`, this will update the JavaScript bundle.
|
76
|
-
1. Commit all the changes: `git add . && git commit -m "Bump to v0.XX.0 final version" && git push origin release/x.y
|
77
|
-
1.
|
78
|
-
1.
|
76
|
+
1. Commit all the changes: `git add . && git commit -m "Bump to v0.XX.0 final version" && git push origin release/x.y-stable`.
|
77
|
+
1. Create the PR for the new version.
|
78
|
+
1. `git checkout master && git checkout -b release/x.y.z`
|
79
|
+
1. `git merge release/x.y-stable`
|
80
|
+
1. `git checkout --theirs *`
|
81
|
+
1. `git checkout --theirs .github/* \.*`
|
82
|
+
1. Review changes in `CHANGELOG.md`, manually update and create a "changelog" commit if required.
|
83
|
+
1. `git push origin release/x.y.z`
|
84
|
+
1. Create the PR. The base for this PR should be `master`, but GitHub may crash if there are a lot of changes. As a workaround create the branch against `develop` and, when created, change the base to `master`.
|
85
|
+
1. Still don't merge it.
|
86
|
+
1. Before merging the PR to upgrade `master`, check that the stable branch for the previous version exists. For instance, if we are going to release v0.22.0, there should be a `release/0.21-stable` branch in the repository. If such branch does not exists, it has to be created now, before merging the new release. So, if this is the release of v0.22.0, branch off `release/0.21-stable` from `master`. These stable branches will be able to receive bugfixes, backports and will be the origin of patch releases for older releases.
|
79
87
|
1. Merge (after proper peer review) the PR to `master` and remove `release/x.y.z` branch.
|
80
88
|
1. Run `git checkout master && bin/rake release_all`, this will create all the tags, push the commits and tags and release the gems to RubyGems.
|
81
89
|
1. Once all the gems are published you should create a new release at this repository, just go to the [releases page](https://github.com/decidim/decidim/releases) and create a new one.
|
82
|
-
1. Create the stable branch for the current version. From `master`: `git checkout -b x.y-stable && git push origin x.y-stable`.
|
90
|
+
1. Create the stable branch for the current version. From `master`: `git checkout -b release/x.y-stable && git push origin release/x.y-stable`.
|
83
91
|
1. Update Decidim's Docker repository as explained in the Docker images section below.
|
84
92
|
1. Update Crowdin synchronization configuration with Github:
|
85
|
-
1. Add the new `x.y-stable` branch.
|
93
|
+
1. Add the new `release/x.y-stable` branch.
|
86
94
|
1. Remove from Crowdin branches that are not officially supported anymore. That way they don't synchronize with Github.
|
95
|
+
1. Update the `CHANGELOG.MD` in `release/x.y-stable`. At the top you should have an `Unreleased` header with the `Added`, `Changed`, `Fixed` and `Removed` empty sections. After that, the header with the current version. Add the `Unreleased` section or create the new current version section.
|
87
96
|
|
88
|
-
|
97
|
+
## Releasing patch versions
|
89
98
|
|
90
|
-
Releasing new versions from
|
99
|
+
Releasing new versions from a ***release/x.y-stable*** branch is quite easy. The process is very similar from releasing a new Decidim version:
|
91
100
|
|
92
|
-
1. Checkout the branch you want to release: `git checkout -b
|
101
|
+
1. Checkout the branch you want to release: `git checkout -b release/x.y-stable`
|
93
102
|
1. Update `.decidim-version` to the new version number.
|
94
103
|
1. Run `bin/rake update_versions`, this will update all references to the new version.
|
95
104
|
1. Run `bin/rake bundle`, this will update all the `Gemfile.lock` files
|
@@ -100,6 +109,6 @@ Releasing new versions from an ***x.y-stable*** branch is quite easy. The proces
|
|
100
109
|
1. Once all the gems are published you should create a new release at this repository, just go to the [releases page](https://github.com/decidim/decidim/releases) and create a new one.
|
101
110
|
1. Update Decidim's Docker repository as explained in the Docker images section.
|
102
111
|
|
103
|
-
|
112
|
+
## Docker images for each release
|
104
113
|
|
105
114
|
1. After each release, you should update our [Docker repository](https://github.com/decidim/docker) so new images are build for the new release. To do it, just update `DECIDIM_VERSION` at [circle.yml](https://github.com/decidim/docker/blob/master/circle.yml).
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Share tokens
|
2
|
+
|
3
|
+
Share tokens can be assigned to any model to provide a system to share unpublished resources with expirable and manageable tokens.
|
4
|
+
|
5
|
+
A share token is created by a user with an expiration time, and can be added as a query param to access otherwise restricted locations.
|
6
|
+
|
7
|
+
## Add share tokens to a model
|
8
|
+
|
9
|
+
The model must `include Decidim::ShareableWithToken` and implement `shareable_url(share_token)`, which should return the public url for the resource you want to share, including the token as a query parameter.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# Public: Public URL for your_resource with given share token as query parameter
|
13
|
+
def shareable_url(share_token)
|
14
|
+
your_resource_public_path(self, share_token: share_token.token)
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
## Set permissions
|
19
|
+
|
20
|
+
You should change permissions logic for the resource to check if there's a `share_token` query parameter in the request url, and call `Decidim::ShareToken.use!` to both check if the token is valid, and if it is, to *use it* (which increments `times_used` variable and sets `last_used_at` to current time).
|
21
|
+
|
22
|
+
It should do something similar to this:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
token = context[:share_token]
|
26
|
+
|
27
|
+
return unless token.present?
|
28
|
+
|
29
|
+
allow! if Decidim::ShareToken.use!(token_for: your_resource, token: token)
|
30
|
+
```
|
31
|
+
|
32
|
+
## Manage tokens
|
33
|
+
|
34
|
+
Render the partial `decidim-admin/app/views/decidim/admin/share_tokens/_share_tokens.html.erb` inside a view, with:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
locals: { share_tokens: your_share_tokens_variable }
|
38
|
+
```
|
39
|
+
|
40
|
+
to let admins see and manage tokens for that resource.
|
41
|
+
|
42
|
+
## Link to url with token
|
43
|
+
|
44
|
+
Implement a `share` action (see below) in the resource controller (admin scope), redirecting to a url with a newly generated token, so you can call `share_my_resource_url`.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
def share
|
48
|
+
@your_resource = YourResource.find(params[:id]) # or whatever
|
49
|
+
share_token = @your_resource.share_tokens.create!(user: current_user, organization: current_organization)
|
50
|
+
|
51
|
+
redirect_to share_token.url
|
52
|
+
end
|
53
|
+
```
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Templates
|
2
|
+
|
3
|
+
Templates can be defined from their own section in the admin panel to store and use objects with given values and use them to create new ones using these values as default.
|
4
|
+
|
5
|
+
## Model
|
6
|
+
|
7
|
+
The only requisite to create a template for a model is that the model class includes the `Decidim::Templates::Templatable` concern.
|
8
|
+
|
9
|
+
## Controller
|
10
|
+
|
11
|
+
A controller must be created in `decidim-templates/app/controllers/decidim/templates/admin` for the template management actions: `index`, `new`, `create`, `edit`, `update`, `delete` and the additional `copy`, `apply`, `skip` and `preview` actions.
|
12
|
+
|
13
|
+
## Commands
|
14
|
+
|
15
|
+
You should create at least the custom `create`, `copy` and `apply` commands for the model templates in `decidim-templates/app/commands/decidim/templates/admin`, and can use the general `destroy` and `update` commands in the controller, which need to be called only with the `Template` itself.
|
16
|
+
|
17
|
+
## Routes
|
18
|
+
|
19
|
+
The following routes should be defined in `decidim-templates/lib/decidim/templates/admin_engine.rb`.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
resources :$MODEL_templates do
|
23
|
+
member do
|
24
|
+
post :copy
|
25
|
+
|
26
|
+
resource :$MODEL, module: :$MODEL_templates # To manage the templatable resource
|
27
|
+
end
|
28
|
+
|
29
|
+
collection do
|
30
|
+
post :apply # To use when creating an object from a template
|
31
|
+
post :skip # To use when creating an object without a template
|
32
|
+
get :preview # To provide a preview for the template in the object creation view
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
## Views
|
38
|
+
|
39
|
+
All views related to a model's template management must be created inside `decidim-templates/app/views/decidim/templates/admin/$MODEL_templates`.
|
40
|
+
|
41
|
+
## Testing
|
42
|
+
|
43
|
+
The factory for a specific model's template should be defined in `decidim-templates/lib/decidim/templates/test/factories.rb`, inside the general `:template` factory.
|
44
|
+
|
45
|
+
## Other
|
46
|
+
|
47
|
+
Add the route to the model templates index inside `decidim-templates/app/controllers/decidim/templates/admin/application_controller.rb`, providing the title and the index root.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
def template_types
|
51
|
+
@template_types ||= {
|
52
|
+
I18n.t("template_types.questionnaires", scope: "decidim.templates") => decidim_admin_templates.questionnaire_templates_path,
|
53
|
+
I18n.t("template_types.$MODEL_PLURAL", scope: "decidim.templates") => decidim_admin_templates.$MODEL_templates_path,
|
54
|
+
}
|
55
|
+
end
|
56
|
+
```
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Using machine translations
|
2
|
+
|
3
|
+
For multilingual organizations, Decidim includes a way to integrate with amachine translation service. The aim of this integration is to provide machine translations for any user-generated content.
|
4
|
+
|
5
|
+
## Flow description
|
6
|
+
|
7
|
+
Every time a user creates or updates a translatable resource (that is, an instance of a resource that implements the `Decidim::TranslatableResource` concern), this workflow is triggered:
|
8
|
+
|
9
|
+
- A background job starts for the resource. This background job lists the fields that have been changed, and checks if any of the fields is considered translatable.
|
10
|
+
- For each translatable field that is changed, it lists the locales that need to be translated.
|
11
|
+
- For each combination field/locale a new job is fired.
|
12
|
+
- This job calls the machine translation service, which will handle how to translate that given text.
|
13
|
+
|
14
|
+
This workflow will only start if the machine translation service is configured in the installation, and the organization has the service enabled.
|
15
|
+
|
16
|
+
## Enabling the integration, installation-wise
|
17
|
+
|
18
|
+
This is an option in the Decidim initializer:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
config.enable_machine_translations = true
|
22
|
+
config.machine_translation_service = "MyApp::MyOwnTranslationService"
|
23
|
+
```
|
24
|
+
|
25
|
+
The class will need to be implemented, or reuse one from the community. Check the docs on how to implement a machine translation service.
|
26
|
+
|
27
|
+
## Enabling the integration, organization-wise
|
28
|
+
|
29
|
+
Each organization will be able to enable/disable machine translations if they want to. They can do that from the organization configuration.
|
30
|
+
|
@@ -0,0 +1,610 @@
|
|
1
|
+
# Custom map providers
|
2
|
+
|
3
|
+
Decidim can be configured to use multiple different
|
4
|
+
[map service providers][link-docs-maps] but it can be also extended to use any
|
5
|
+
possible service provider out there.
|
6
|
+
|
7
|
+
If you want to create your own provider integration, you will need to find a
|
8
|
+
service provider that provides all the following services:
|
9
|
+
|
10
|
+
- [A geocoding server][link-wiki-geocoding] in order to turn user entered
|
11
|
+
addresses into [geocoordinates][link-wiki-geocoordinates].
|
12
|
+
- [A geocoding autocompletion server][link-wiki-autocompletion] in order to
|
13
|
+
suggest and predict addresses based on the user input and turning these
|
14
|
+
suggested addresses into [geocoordinates][link-wiki-geocoordinates].
|
15
|
+
- [A map tile server][link-wiki-tile-server] for the dynamic maps, preferrably
|
16
|
+
one that is compatible with the default [Leaflet][link-leaflet] map library.
|
17
|
+
- [A static map image server][link-wiki-static-maps] for the static map images
|
18
|
+
e.g. on the proposal pages. This service is optional as Decidim will use the
|
19
|
+
dynamic map tiles to generate a similar map element if the static map image
|
20
|
+
cannot be provided.
|
21
|
+
|
22
|
+
One option is to host some or all of these services yourself as there are open
|
23
|
+
source alternatives available for all of these services. More information about
|
24
|
+
self hosting is available at the
|
25
|
+
[maps and geocoding configuration][link-docs-maps-multiple-providers]
|
26
|
+
documentation.
|
27
|
+
|
28
|
+
You may also decide to [disable some of the services][link-docs-maps-disable]
|
29
|
+
that are not available at your service provider but in order to get the full out
|
30
|
+
of Decidim, it is recommended to find a service provider with all these
|
31
|
+
services.
|
32
|
+
|
33
|
+
In case you want to use different service providers for the different categories
|
34
|
+
of map services, that is also possible. Instructions for this are provided in
|
35
|
+
the [maps and geocoding configuration][link-docs-maps-multiple-providers]
|
36
|
+
documentation.
|
37
|
+
|
38
|
+
## Creating your own map service provider
|
39
|
+
|
40
|
+
First thing you will need is to define a service provider module which also
|
41
|
+
defines all the services your provider is able to serve. An example service
|
42
|
+
provider module looks as follows:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
module Decidim
|
46
|
+
module Map
|
47
|
+
module Provider
|
48
|
+
module Geocoding
|
49
|
+
autoload :YourProvider, "decidim/map/provider/geocoding/your_provider"
|
50
|
+
end
|
51
|
+
module Autocomplete
|
52
|
+
autoload :YourProvider, "decidim/map/provider/autocomplete/your_provider"
|
53
|
+
end
|
54
|
+
module DynamicMap
|
55
|
+
autoload :YourProvider, "decidim/map/provider/dynamic_map/your_provider"
|
56
|
+
end
|
57
|
+
module StaticMap
|
58
|
+
autoload :YourProvider, "decidim/map/provider/static_map/your_provider"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
Please note that you will need to place the utility classes for each category of
|
66
|
+
services under the paths defined for the autoloading functionality.
|
67
|
+
|
68
|
+
### Defining the geocoding utility
|
69
|
+
|
70
|
+
For the geocoding functionality, Decidim uses the [Geocoder gem][link-geocoder]
|
71
|
+
which does most of the heavy lifting. It is not necessary to use this gem but
|
72
|
+
in case your target service is already integrated with that gem, it makes this
|
73
|
+
step much easier for you. Take a look at the list of
|
74
|
+
[supported geocoding APIs][link-geocoder-apis] for the Geocoder gem.
|
75
|
+
|
76
|
+
In case your API is supported by the Geocoder gem, the only thing you need to do
|
77
|
+
to create your geocoding utility is to create the following empty class:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
module Decidim
|
81
|
+
module Map
|
82
|
+
module Provider
|
83
|
+
module Geocoding
|
84
|
+
class YourProvider < ::Decidim::Map::Geocoding
|
85
|
+
# ... add your customizations here ...
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
If the target service has some other "lookup handle" defined in the Geocoder gem
|
94
|
+
than `:your_provider`, you may want to override the `handle` method in the
|
95
|
+
geocoding utility's class you just defined. This is passed for the Geocoder gem
|
96
|
+
as your lookup handle. An example of this can be seen in the
|
97
|
+
[`Decidim::Map::Provider::Geocoding::Osm`][link-code-osm-geocoder] class which
|
98
|
+
changes the handle to `:nominatim` instead of the default `:osm` which is not an
|
99
|
+
existing lookup handle in the Geocoder gem.
|
100
|
+
|
101
|
+
In case you want to customize the geocoding utility for your provider, you can
|
102
|
+
define the following methods in the utility class:
|
103
|
+
|
104
|
+
- `search(query, options = {})` - A common method for searching the geocoding
|
105
|
+
API and returning an array of results. The results array contains the Geocoder
|
106
|
+
gem's result objects of type
|
107
|
+
[`Geocoder::Result::Base`][link-code-geocoder-result] or the result type
|
108
|
+
specific to your API. If the first parameter is an address string, the method
|
109
|
+
does a forward geocoding request finding the closest matching coordinate pairs
|
110
|
+
for that address. If the first parameter is a coordinate pair array, the
|
111
|
+
method does a reverse geocoding request finding the closest matching addresses
|
112
|
+
for the search.
|
113
|
+
- `coordinates(address, options = {})` - A method that searches the best
|
114
|
+
matching coordinates for the given address string. Only returns one coordinate
|
115
|
+
pair as an array.
|
116
|
+
- `address(coordinates, options = {})` - A method that searches the best
|
117
|
+
matching address for the given coordinate pair array. Only returns one address
|
118
|
+
as a string.
|
119
|
+
|
120
|
+
Customization may be needed if you are not happy with the default results
|
121
|
+
returned by the Geocoder gem. For instance, in some occasions you might want to
|
122
|
+
pass extra query options to the geocoding API or sort the results differently
|
123
|
+
than what was returned by the API and what is already done in Decidim by
|
124
|
+
default.
|
125
|
+
|
126
|
+
In order to provide configuration options for the Geocoder gem's lookup, you can
|
127
|
+
pass them directly through the maps configuration with the following syntax:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
config.maps = {
|
131
|
+
provider: :your_provider,
|
132
|
+
api_key: Rails.application.secrets.maps[:api_key],
|
133
|
+
geocoding: { extra_option: "value", another_option: "value" }
|
134
|
+
}
|
135
|
+
```
|
136
|
+
|
137
|
+
This would equal to configuring the Geocoder gem with the following code:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
Geocoder.configure(
|
141
|
+
your_provider: {
|
142
|
+
api_key: Rails.application.secrets.maps[:api_key],
|
143
|
+
extra_option: "value",
|
144
|
+
another_option: "value"
|
145
|
+
}
|
146
|
+
)
|
147
|
+
```
|
148
|
+
|
149
|
+
Each geocoding API may require their own configuration options. Please refer to
|
150
|
+
the Geocoder gem's [supported geocoding APIs][link-geocoder-apis] documentation
|
151
|
+
to find out the available options for your API.
|
152
|
+
|
153
|
+
### Defining the geocoding autocompletion maps utility
|
154
|
+
|
155
|
+
For the geocoding autocompletion map functionality, you should preferrably use
|
156
|
+
a service provider that is compatible with [Photon][link-photon] which is
|
157
|
+
already integrated with Decidim.
|
158
|
+
|
159
|
+
If this is not possible, you can also create a custom geocoding autocompletion
|
160
|
+
maps utility for your own service provider by defining the following empty class
|
161
|
+
to start with:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
module Decidim
|
165
|
+
module Map
|
166
|
+
module Provider
|
167
|
+
module Autocomplete
|
168
|
+
class YourProvider < ::Decidim::Map::Autocomplete
|
169
|
+
# ... add your customizations here ...
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
```
|
176
|
+
|
177
|
+
In case you want to customize the geocoding autocompletion map utility for your
|
178
|
+
provider, you can define the following methods in the utility class:
|
179
|
+
|
180
|
+
- `builder_class` - Returns a class for the geocoding autocompletion builder
|
181
|
+
that is used to create the input fields for the autocompleted addresses in the
|
182
|
+
front-end. By default, this would be
|
183
|
+
`Decidim::Map::Provider::Autocomplete::YourProvider::Builder` or if that is
|
184
|
+
not defined, defaults to `Decidim::Map::Autocomplete::Builder`. See below for
|
185
|
+
further notes about the builder class.
|
186
|
+
- `builder_options` - A method that prepares the options for the builder
|
187
|
+
instance that is used to create the maps in the front-end. By default, this
|
188
|
+
is an empty hash that needs to be configured for each provider.
|
189
|
+
|
190
|
+
To see an example how to customize the static map utility, take a look at the
|
191
|
+
[HERE Maps geocoding autocomletion utility][link-code-here-autocomplete].
|
192
|
+
|
193
|
+
In order to provide configuration options for the geocoding autocompletion, you
|
194
|
+
can pass them directly through the maps configuration with the following syntax:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
config.maps = {
|
198
|
+
provider: :your_provider,
|
199
|
+
api_key: Rails.application.secrets.maps[:api_key],
|
200
|
+
autocomplete: {
|
201
|
+
url: "https://photon.example.org/api/"
|
202
|
+
}
|
203
|
+
}
|
204
|
+
```
|
205
|
+
|
206
|
+
And then you can use these options in your provider utility as follows e.g. in
|
207
|
+
the `builder_options` method:
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
def builder_options
|
211
|
+
{ url: configuration.fetch(:url, nil) }.compact
|
212
|
+
end
|
213
|
+
```
|
214
|
+
|
215
|
+
You will also need to define a builder class inside your provider utility class
|
216
|
+
as follows:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
module Decidim
|
220
|
+
module Map
|
221
|
+
module Provider
|
222
|
+
module Autocomplete
|
223
|
+
class Here < ::Decidim::Map::Autocomplete
|
224
|
+
# ... other customizations go gere ...
|
225
|
+
|
226
|
+
# This is the actual builder customization where you could define e.g.
|
227
|
+
# the JavaScript asset which is used to initialize the geocoding
|
228
|
+
# autocompletion functionality in the front-end:
|
229
|
+
class Builder < Decidim::Map::Autocomplete::Builder
|
230
|
+
def javascript_snippets
|
231
|
+
template.javascript_include_tag("decidim/geocoding/provider/your_provider")
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
```
|
240
|
+
|
241
|
+
To see an example of the front-end JavaScript code that handles the geocoding
|
242
|
+
requests, you can take a look at the
|
243
|
+
[HERE Maps example][link-code-here-autocomplete-js]. You will have to listen to
|
244
|
+
the `geocoder-suggest.decidim` JavaScript event on all elements that have the
|
245
|
+
`data-decidim-geocoding` attribute defined which contains all the configurations
|
246
|
+
returned by the builder's `builder_options` method as mentioned above. For
|
247
|
+
example, if you passed the following configuration from that method:
|
248
|
+
|
249
|
+
```js
|
250
|
+
{ url: "https://photon.example.org/api/", other_config: "foo" }
|
251
|
+
```
|
252
|
+
|
253
|
+
This would be available in the JavaScript as follows:
|
254
|
+
|
255
|
+
```js
|
256
|
+
$(document).on("ready", () => {
|
257
|
+
$("[data-decidim-geocoding]").each((_i, el) => {
|
258
|
+
console.log($(el).data("decidim-geocoding"));
|
259
|
+
// => This would print out:
|
260
|
+
// {url: "https://photon.example.org/api/", otherConfig: "foo"}
|
261
|
+
});
|
262
|
+
});
|
263
|
+
```
|
264
|
+
|
265
|
+
When you hook into the `geocoder-suggest.decidim` event on these methods, the
|
266
|
+
event callback will be provided three arguments:
|
267
|
+
|
268
|
+
- `event` - The event that you hooked into
|
269
|
+
- `query` - The text to be queried, i.e. what the user entered into the input
|
270
|
+
- `callback` - A callback method which you will need to call with your geocoding
|
271
|
+
autocompletion results once the request to the API has finished in the
|
272
|
+
front-end.
|
273
|
+
|
274
|
+
The `callback` method expects one argument which is the array of result objects.
|
275
|
+
The result objects need to contain the following keys:
|
276
|
+
|
277
|
+
- `key` - The key which will be matched against the user entered input
|
278
|
+
- `value` - The value which will be added to the address input if the user
|
279
|
+
decides to select this value
|
280
|
+
|
281
|
+
Optionally, you can also include a `coordinates` key in the result object which
|
282
|
+
contains an array of two cordinates (latitude and longitude respectively). You
|
283
|
+
can also include any other data you might need in the front-end for these
|
284
|
+
results but it will be not used by Decidim.
|
285
|
+
|
286
|
+
The final code would look something like follows:
|
287
|
+
|
288
|
+
```js
|
289
|
+
$(document).on("ready", () => {
|
290
|
+
$("[data-decidim-geocoding]").each((_i, el) => {
|
291
|
+
const $input = $(el);
|
292
|
+
const config = $input.data("decidim-geocoding");
|
293
|
+
|
294
|
+
$input.on("geocoder-suggest.decidim", (event, query, callback) => {
|
295
|
+
currentSuggestionQuery = setTimeout(() => {
|
296
|
+
$.ajax({
|
297
|
+
method: "GET",
|
298
|
+
url: config.url,
|
299
|
+
data: { apiKey: config.apiKey },
|
300
|
+
dataType: "json"
|
301
|
+
}).done((resp) => {
|
302
|
+
if (resp.suggestions) {
|
303
|
+
return callback(resp.suggestions.map((item) => {
|
304
|
+
return {
|
305
|
+
key: item.label,
|
306
|
+
value: item.label,
|
307
|
+
coordinates: [item.latitude, item.longitude],
|
308
|
+
yourExtraData: item.yourExtraData
|
309
|
+
}
|
310
|
+
}));
|
311
|
+
}
|
312
|
+
return null;
|
313
|
+
});
|
314
|
+
});
|
315
|
+
});
|
316
|
+
});
|
317
|
+
```
|
318
|
+
|
319
|
+
If your autocompletion API does not provide the coordinates information along
|
320
|
+
with the autocompletion requests, you can hook into another event to do extra
|
321
|
+
queries for the geocoordinates as follows:
|
322
|
+
|
323
|
+
```js
|
324
|
+
$(document).on("ready", () => {
|
325
|
+
$("geocoder-suggest-select.decidim", (ev, selectedItem) => {
|
326
|
+
console.log(selectedItem);
|
327
|
+
// => This would print out what you returned for the `callback` as shown
|
328
|
+
// above.
|
329
|
+
|
330
|
+
// NOTE: YOU DON'T NEED THIS IF YOUR RESPONSE OBJECTS ALREADY CONTAINED THE
|
331
|
+
// COORDINATES IN THE `coordinates` KEY OF EACH RESULT OBJECT!
|
332
|
+
// Then, once you know the coordinates, you trigger the following event on
|
333
|
+
// the same input (obviously, you need to query the API first):
|
334
|
+
const coordinates = [1.123, 2.234];
|
335
|
+
$(ev.target).trigger("geocoder-suggest-coordinates.decidim", [coordinates]);
|
336
|
+
});
|
337
|
+
});
|
338
|
+
```
|
339
|
+
|
340
|
+
Finally, if you want to pass these coordinates to the same form where your
|
341
|
+
address field is located at, you can use the `Decidim.attachGeocoding()` method
|
342
|
+
as follows:
|
343
|
+
|
344
|
+
```js
|
345
|
+
$(document).ready(function() {
|
346
|
+
Decidim.attachGeocoding($("#your_address_input"));
|
347
|
+
});
|
348
|
+
```
|
349
|
+
|
350
|
+
Now the latitude and longitude coordinates would be passed to the same form
|
351
|
+
where the address input is located at. For example, if the address input had the
|
352
|
+
name `record[address]`, new hidden fields would be now generated for the
|
353
|
+
geocoding autocomplete suggestion's coordinates with the following names:
|
354
|
+
|
355
|
+
- `record[latitude]` for the latitude coordinate
|
356
|
+
- `record[longitude]` for the longitude coordinate
|
357
|
+
|
358
|
+
Then, you can read these values along with the form's POST data in order to
|
359
|
+
store the coordinates for your records in the back-end. This is not 100%
|
360
|
+
necessary but it improves the accuracy of the geocoding functionality and it
|
361
|
+
also avoids unnecessary double requests to the geocoding API (front-end +
|
362
|
+
back-end).
|
363
|
+
|
364
|
+
### Defining the dynamic maps utility
|
365
|
+
|
366
|
+
For the dynamic map functionality, you should primarily use a service provider
|
367
|
+
that is compatible with the [Leaflet library][link-leaflet] that ships with
|
368
|
+
Decidim. You can also integrate to services that are not compatible with Leaflet
|
369
|
+
but it will cause you more work and is not covered by this guide.
|
370
|
+
|
371
|
+
Please note that you don't necessarily even need to create your own dynamic maps
|
372
|
+
utility if your service provider is already compatible with the
|
373
|
+
[`Decidim::Map::Provider::DynamicMap::Osm`][link-code-osm-dynamic] provider. In
|
374
|
+
order to configure your custom OSM compatible service provider take a look at
|
375
|
+
the [maps and geocoding configuration][link-docs-maps-osm] documentation.
|
376
|
+
|
377
|
+
If your service provider is not fully compatible with the default OSM provider,
|
378
|
+
you can start writing your customizations by creating an empty dynamic map
|
379
|
+
provider utility with the following code:
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
module Decidim
|
383
|
+
module Map
|
384
|
+
module Provider
|
385
|
+
module DynamicMap
|
386
|
+
class YourProvider < ::Decidim::Map::DynamicMap
|
387
|
+
# ... add your customizations here ...
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
```
|
394
|
+
|
395
|
+
In case you want to customize the dynamic map utility for your provider, you can
|
396
|
+
define the following methods in the utility class:
|
397
|
+
|
398
|
+
- `builder_class` - Returns a class for the dynamic map builder that is used
|
399
|
+
to create the maps in the front-end. By default, this would be
|
400
|
+
`Decidim::Map::Provider::DynamicMap::YourProvider::Builder` or if that is not
|
401
|
+
defined, defaults to `Decidim::Map::DynamicMap::Builder`. See below for
|
402
|
+
further notes about the builder class.
|
403
|
+
- `builder_options` - A method that prepares the options for the builder
|
404
|
+
instance that is used to create the maps in the front-end. By default, this
|
405
|
+
prepares the tile layer configurations for the Leaflet map.
|
406
|
+
|
407
|
+
In addition, you may want to customize the Builder class in case you are not
|
408
|
+
happy with the default dynamic map builder functionality. To see an example how
|
409
|
+
to customize the builder, take a look at the
|
410
|
+
[HERE Maps builder class][link-code-here-dynamic]. Please note that the custom
|
411
|
+
dynamic map builder needs to extend the
|
412
|
+
[`Decidim::Map::DynamicMap::Builder`][link-code-dynamic-map] class as you can
|
413
|
+
also see from the HERE Maps example.
|
414
|
+
|
415
|
+
The builder class works directly with the view layer and can refer to the view
|
416
|
+
in question or any methods available for the view using the `template` object
|
417
|
+
inside the builder. You may be already familiar with a similar builder concept
|
418
|
+
if you have ever used the [Rails Form Builder][link-rails-form-builder].
|
419
|
+
|
420
|
+
In order to provide configuration options for the dynamic maps, you can pass
|
421
|
+
them directly through the maps configuration with the following syntax:
|
422
|
+
|
423
|
+
```ruby
|
424
|
+
config.maps = {
|
425
|
+
provider: :your_provider,
|
426
|
+
api_key: Rails.application.secrets.maps[:api_key],
|
427
|
+
dynamic: {
|
428
|
+
tile_layer: {
|
429
|
+
url: "https://tiles.example.org/{z}/{x}/{y}.png?key={apiKey}&{foo}&style={style}",
|
430
|
+
api_key: true,
|
431
|
+
foo: "bar=baz",
|
432
|
+
style: "bright-style",
|
433
|
+
attribution: %{
|
434
|
+
<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors
|
435
|
+
}.strip
|
436
|
+
}
|
437
|
+
}
|
438
|
+
}
|
439
|
+
```
|
440
|
+
|
441
|
+
This will cause the following options to be available for the builder instance
|
442
|
+
by default:
|
443
|
+
|
444
|
+
```ruby
|
445
|
+
{
|
446
|
+
tile_layer: {
|
447
|
+
url: "https://tiles.example.org/{z}/{x}/{y}.png?key={apiKey}&{foo}&style={style}",
|
448
|
+
configuration: {
|
449
|
+
api_key: Rails.application.secrets.maps[:api_key],
|
450
|
+
foo: "bar=baz",
|
451
|
+
style: "bright",
|
452
|
+
attribution: %{
|
453
|
+
<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors
|
454
|
+
}.strip
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
```
|
459
|
+
|
460
|
+
And by default, this will cause the Leaflet tile layer to be configured as
|
461
|
+
follows:
|
462
|
+
|
463
|
+
```js
|
464
|
+
L.tileLayer(
|
465
|
+
"https://tiles.example.org/{z}/{x}/{y}.png?key={apiKey}&{foo}&style={style}",
|
466
|
+
{
|
467
|
+
apiKey: "your_secret_key",
|
468
|
+
foo: "bar=baz",
|
469
|
+
style: "bright",
|
470
|
+
attribution: '<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap</a> contributors'
|
471
|
+
}
|
472
|
+
).addTo(map);
|
473
|
+
```
|
474
|
+
|
475
|
+
### Defining the static maps utility
|
476
|
+
|
477
|
+
For the static map functionality, you should preferrably use a service provider
|
478
|
+
that is compatible with [osm-static-maps][link-osm-static-maps] which is already
|
479
|
+
integrated with Decidim.
|
480
|
+
|
481
|
+
If this is not possible, you can also create a custom static maps utility for
|
482
|
+
your own service provider by defining the following empty class to start with:
|
483
|
+
|
484
|
+
```ruby
|
485
|
+
module Decidim
|
486
|
+
module Map
|
487
|
+
module Provider
|
488
|
+
module StaticMap
|
489
|
+
class YourProvider < ::Decidim::Map::StaticMap
|
490
|
+
# ... add your customizations here ...
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
```
|
497
|
+
|
498
|
+
If you want to use dynamic map elements for the static maps as well, you can
|
499
|
+
leave the static map utility empty as shown above. Decidim will create a dynamic
|
500
|
+
map replacement for the static map image in case the static map utility will not
|
501
|
+
return a proper map URL.
|
502
|
+
|
503
|
+
In case you want to customize the static map utility for your provider, you can
|
504
|
+
define the following methods in the utility class:
|
505
|
+
|
506
|
+
- `link(latitude:, longitude:, options: {})` - Returns a link for the given
|
507
|
+
geographic location where the static map image is linked to. By default, this
|
508
|
+
will return a link to www.openstreetmap.org.
|
509
|
+
- `url(latitude:, longitude:, options: {})` - Returns a URL for loading the
|
510
|
+
static map image from the service provider. By default, this will return a
|
511
|
+
link to the configured static map URL with the following URL query parameters:
|
512
|
+
- `latitude` - The value for the `latitude` option provided for the method.
|
513
|
+
- `longitude` - The value for the `longitude` option provided for the method.
|
514
|
+
- `zoom` - The value for key `:zoom` in the options hash (default: 15).
|
515
|
+
- `width` - The value for key `:width` in the options hash (default: 120).
|
516
|
+
- `height` - The value for key `:height` in the options hash (default: 120).
|
517
|
+
- `url_params(latitude:, longitude:, options: {})` - Returns a hash of prepared
|
518
|
+
URL parameters for the `url` method. For the default parameters, see the
|
519
|
+
explanations above for the `url` method.
|
520
|
+
- `image_data(latitude:, longitude:, options: {})` - Does a request to the URL
|
521
|
+
defined by the `url` method and returns the raw binary data in the response
|
522
|
+
body of that request. This data will be cached by Decidim once fetched from
|
523
|
+
the API to speed up further displays of the same static map.
|
524
|
+
|
525
|
+
To see an example how to customize the static map utility, take a look at the
|
526
|
+
[HERE Maps static map utility][link-code-here-static].
|
527
|
+
|
528
|
+
In order to provide configuration options for the static maps, you can pass them
|
529
|
+
directly through the maps configuration with the following syntax:
|
530
|
+
|
531
|
+
```ruby
|
532
|
+
config.maps = {
|
533
|
+
provider: :your_provider,
|
534
|
+
api_key: Rails.application.secrets.maps[:api_key],
|
535
|
+
static: {
|
536
|
+
url: "https://staticmap.example.org/",
|
537
|
+
foo: "bar",
|
538
|
+
style: "bright"
|
539
|
+
}
|
540
|
+
}
|
541
|
+
```
|
542
|
+
|
543
|
+
And then you can use these options in your provider utility as follows e.g. in
|
544
|
+
the `url_params` method:
|
545
|
+
|
546
|
+
```ruby
|
547
|
+
def url_params(latitude:, longitude:, options: {})
|
548
|
+
super.merge(
|
549
|
+
style: configuration.fetch(:style, "dark"),
|
550
|
+
foo: configuration.fetch(:foo, "baz")
|
551
|
+
)
|
552
|
+
end
|
553
|
+
```
|
554
|
+
|
555
|
+
When calling the `url` method with the latitude of `1.123` and longitude of
|
556
|
+
`2.456`, the utility would now generate the following URL with these
|
557
|
+
configurations and customizations:
|
558
|
+
|
559
|
+
```bash
|
560
|
+
https://staticmap.example.org/?latitude=1.123&longitude=2.456&zoom=15&width=120&height=120&style=bright&foo=bar
|
561
|
+
```
|
562
|
+
|
563
|
+
If you want to use the dynamic map replacements for the static map images, do
|
564
|
+
not configure `static` section for your maps:
|
565
|
+
|
566
|
+
```ruby
|
567
|
+
config.maps = {
|
568
|
+
provider: :your_provider,
|
569
|
+
api_key: Rails.application.secrets.maps[:api_key]
|
570
|
+
# static: { ... } # LEAVE THIS OUT
|
571
|
+
}
|
572
|
+
```
|
573
|
+
|
574
|
+
Even if you decide to use the dynamic map replacements, you will still need to
|
575
|
+
define the static map utility because it is used to generate the link where
|
576
|
+
users will be pointed at when they click the map image. In this case, the static
|
577
|
+
map utility can be empty as you won't need any customization for it to work.
|
578
|
+
|
579
|
+
## Configuring your own map service provider
|
580
|
+
|
581
|
+
After you have finished all the steps shown above, you will need to configure
|
582
|
+
your service provider for Decidim. The configuration key for the example service
|
583
|
+
provider referred to in this documentation would be `:your_provider`. For
|
584
|
+
configuration, refer to the [maps and geocoding configuration][link-docs-maps]
|
585
|
+
documentation.
|
586
|
+
|
587
|
+
[link-code-dynamic-map]: /decidim-core/lib/decidim/map/dynamic_map.rb
|
588
|
+
[link-code-geocoder-result]: https://github.com/alexreisner/geocoder/blob/master/lib/geocoder/results/base.rb
|
589
|
+
[link-code-here-autocomplete]: /decidim-core/lib/decidim/map/provider/autocomplete/here.rb
|
590
|
+
[link-code-here-autocomplete-js]: /decidim-core/app/assets/javascripts/decidim/geocoding/provider/here.js.es6
|
591
|
+
[link-code-here-dynamic]: /decidim-core/lib/decidim/map/provider/dynamic_map/here.rb
|
592
|
+
[link-code-here-static]: /decidim-core/lib/decidim/map/provider/static_map/here.rb
|
593
|
+
[link-code-osm-dynamic]: /decidim-core/lib/decidim/map/provider/dynamic_map/osm.rb
|
594
|
+
[link-code-osm-geocoder]: /decidim-core/lib/decidim/map/provider/geocoding/osm.rb
|
595
|
+
[link-docs-maps]: /docs/services/maps.md
|
596
|
+
[link-docs-maps-disable]: /docs/services/maps.md#disabling
|
597
|
+
[link-docs-maps-osm]: /docs/services/maps.md#configuring-open-street-maps-based-service-providers
|
598
|
+
[link-docs-maps-multiple-providers]: /docs/services/maps.md#combining-multiple-service-providers
|
599
|
+
[link-geocoder]: https://github.com/alexreisner/geocoder
|
600
|
+
[link-geocoder-apis]: https://github.com/alexreisner/geocoder/blob/master/README_API_GUIDE.md
|
601
|
+
[link-leaflet]: https://leafletjs.com/
|
602
|
+
[link-osm-static-maps]: https://github.com/jperelli/osm-static-maps
|
603
|
+
[link-photon]: https://github.com/komoot/photon
|
604
|
+
[link-rails-form-builder]: https://guides.rubyonrails.org/form_helpers.html#customizing-form-builders
|
605
|
+
[link-wiki-autocompletion]: https://en.wikipedia.org/wiki/Autocomplete
|
606
|
+
[link-wiki-geocoding]: https://en.wikipedia.org/wiki/Geocoding
|
607
|
+
[link-wiki-geocoordinates]: https://en.wikipedia.org/wiki/Geographic_coordinate_system
|
608
|
+
[link-wiki-map-tiles]: https://wiki.openstreetmap.org/wiki/Tiles
|
609
|
+
[link-wiki-static-maps]: https://wiki.openstreetmap.org/wiki/Static_map_images
|
610
|
+
[link-wiki-tile-server]: https://en.wikipedia.org/wiki/Tile_Map_Service
|