Merge branch 'master' into feature/add-communities-page
# Conflicts: # Gemfile.lock # package.json # yarn.lock
This commit is contained in:
commit
7e5cbe87ed
527 changed files with 147625 additions and 149175 deletions
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,4 +1,4 @@
|
|||
blank_issues_enabled: false
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: There is an issue with the default map layer shown on the front page
|
||||
url: https://github.com/gravitystorm/openstreetmap-carto
|
||||
|
|
12
.github/ISSUE_TEMPLATE/feature.yml
vendored
12
.github/ISSUE_TEMPLATE/feature.yml
vendored
|
@ -4,18 +4,26 @@ description: You want to request a feature, share an idea or have a question.
|
|||
# labels:
|
||||
# assignees:
|
||||
body:
|
||||
- type: textarea
|
||||
id: idea
|
||||
attributes:
|
||||
label: Problem
|
||||
description: Please describe the problem or use case that is the cause for your feature request or idea.
|
||||
placeholder:
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: idea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please describe you feature request, idea or question.
|
||||
description: Please describe your feature request, idea or question.
|
||||
placeholder:
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: Please add screenshots if they can help us understand your request/idea/question.
|
||||
description: Please add screenshots or mockups if they can help us understand your request/idea/question.
|
||||
placeholder:
|
||||
validations:
|
||||
required: false
|
||||
|
|
9
.github/workflows/docker.yml
vendored
9
.github/workflows/docker.yml
vendored
|
@ -2,13 +2,16 @@ name: Docker
|
|||
on:
|
||||
- push
|
||||
- pull_request
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-{{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
test:
|
||||
name: Docker
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v2.4.0
|
||||
uses: actions/checkout@v3
|
||||
- name: Poke config
|
||||
run: |
|
||||
cp config/example.storage.yml config/storage.yml
|
||||
|
@ -23,8 +26,8 @@ jobs:
|
|||
sleep 15 # let the DB warm up a little
|
||||
- name: Prepare Database
|
||||
run: |
|
||||
docker-compose run --rm web rake db:migrate
|
||||
docker-compose run web bundle exec rake i18n:js:export
|
||||
docker-compose run --rm web bundle exec rails db:migrate
|
||||
docker-compose run --rm web bundle exec rails i18n:js:export
|
||||
docker-compose run --rm web osmosis --rx docker/null-island.osm.xml --wd host=db database=openstreetmap user=openstreetmap password=openstreetmap validateSchemaVersion=no
|
||||
- name: Test Basic Website
|
||||
run: |
|
||||
|
|
73
.github/workflows/lint.yml
vendored
73
.github/workflows/lint.yml
vendored
|
@ -2,6 +2,9 @@ name: Lint
|
|||
on:
|
||||
- push
|
||||
- pull_request
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-{{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
env:
|
||||
os: ubuntu-20.04
|
||||
ruby: 2.7
|
||||
|
@ -11,23 +14,12 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2.4.0
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup ruby
|
||||
uses: actions/setup-ruby@v1.1.3
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ env.ruby }}
|
||||
- name: Cache gems
|
||||
uses: actions/cache@v2.1.7
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: bundle-${{ env.os }}-${{ env.ruby }}-${{ hashFiles('Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
bundle-${{ env.os }}-${{ env.ruby }}-
|
||||
- name: Install gems
|
||||
run: |
|
||||
gem install bundler
|
||||
bundle config set deployment true
|
||||
bundle install --jobs 4 --retry 3
|
||||
bundler-cache: true
|
||||
- name: Run rubocop
|
||||
run: bundle exec rubocop --format fuubar
|
||||
erblint:
|
||||
|
@ -35,23 +27,12 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2.4.0
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup ruby
|
||||
uses: actions/setup-ruby@v1.1.3
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ env.ruby }}
|
||||
- name: Cache gems
|
||||
uses: actions/cache@v2.1.7
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: bundle-${{ env.os }}-${{ env.ruby }}-${{ hashFiles('Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
bundle-${{ env.os }}-${{ env.ruby }}-
|
||||
- name: Install gems
|
||||
run: |
|
||||
gem install bundler
|
||||
bundle config set deployment true
|
||||
bundle install --jobs 4 --retry 3
|
||||
bundler-cache: true
|
||||
- name: Run erblint
|
||||
run: bundle exec erblint .
|
||||
eslint:
|
||||
|
@ -59,30 +40,19 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2.4.0
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup ruby
|
||||
uses: actions/setup-ruby@v1.1.3
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ env.ruby }}
|
||||
- name: Cache gems
|
||||
uses: actions/cache@v2.1.7
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: bundle-${{ env.os }}-${{ env.ruby }}-${{ hashFiles('Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
bundle-${{ env.os }}-${{ env.ruby }}-
|
||||
bundler-cache: true
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2.1.7
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: yarn-${{ env.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
yarn-${{ env.os }}-
|
||||
- name: Install gems
|
||||
run: |
|
||||
gem install bundler
|
||||
bundle config set deployment true
|
||||
bundle install --jobs 4 --retry 3
|
||||
- name: Install node modules
|
||||
run: bundle exec rake yarn:install
|
||||
- name: Create dummy database configuration
|
||||
|
@ -94,22 +64,11 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2.4.0
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup ruby
|
||||
uses: actions/setup-ruby@v1.1.3
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ env.ruby }}
|
||||
- name: Cache gems
|
||||
uses: actions/cache@v2.1.7
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: bundle-${{ env.os }}-${{ env.ruby }}-${{ hashFiles('Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
bundle-${{ env.os }}-${{ env.ruby }}-
|
||||
- name: Install gems
|
||||
run: |
|
||||
gem install bundler
|
||||
bundle config set deployment true
|
||||
bundle install --jobs 4 --retry 3
|
||||
bundler-cache: true
|
||||
- name: Run brakeman
|
||||
run: bundle exec brakeman -q
|
||||
|
|
26
.github/workflows/tests.yml
vendored
26
.github/workflows/tests.yml
vendored
|
@ -2,12 +2,15 @@ name: Tests
|
|||
on:
|
||||
- push
|
||||
- pull_request
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-{{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
test:
|
||||
name: Ubuntu ${{ matrix.ubuntu }}, Ruby ${{ matrix.ruby }}
|
||||
strategy:
|
||||
matrix:
|
||||
ubuntu: [18.04, 20.04]
|
||||
ubuntu: [20.04]
|
||||
ruby: [2.7, 3.0]
|
||||
runs-on: ubuntu-${{ matrix.ubuntu }}
|
||||
env:
|
||||
|
@ -15,20 +18,14 @@ jobs:
|
|||
OPENSTREETMAP_MEMCACHE_SERVERS: 127.0.0.1
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v2.4.0
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup ruby
|
||||
uses: actions/setup-ruby@v1.1.3
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
- name: Cache gems
|
||||
uses: actions/cache@v2.1.7
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: bundle-ubuntu-${{ matrix.ubuntu }}-ruby-${{ matrix.ruby }}-${{ hashFiles('Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
bundle-ubuntu-${{ matrix.ubuntu }}-ruby-${{ matrix.ruby }}-
|
||||
bundler-cache: true
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2.1.7
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: yarn-ubuntu-${{ matrix.ubuntu }}-${{ hashFiles('yarn.lock') }}
|
||||
|
@ -37,12 +34,7 @@ jobs:
|
|||
- name: Install packages
|
||||
run: |
|
||||
sudo apt-get -yqq update
|
||||
sudo apt-get -yqq install memcached
|
||||
- name: Install gems
|
||||
run: |
|
||||
gem install bundler
|
||||
bundle config set deployment true
|
||||
bundle install --jobs 4 --retry 3
|
||||
sudo apt-get -yqq install memcached libvips-dev
|
||||
- name: Create database
|
||||
run: |
|
||||
sudo systemctl start postgresql
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,7 +6,6 @@
|
|||
.vagrant
|
||||
app/assets/javascripts/i18n
|
||||
config/environments/*.local.yml
|
||||
config/piwik.yml
|
||||
config/settings.local.yml
|
||||
config/settings/*.local.yml
|
||||
coverage
|
||||
|
|
|
@ -55,9 +55,6 @@ Rails/HasManyOrHasOneDependent:
|
|||
Rails/HttpPositionalArguments:
|
||||
Enabled: false
|
||||
|
||||
Rails/InverseOf:
|
||||
Enabled: false
|
||||
|
||||
Rails/ReflectionClassName:
|
||||
Enabled: false
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config`
|
||||
# on 2021-09-14 19:29:59 UTC using RuboCop version 1.21.0.
|
||||
# on 2022-02-23 19:11:04 UTC using RuboCop version 1.25.1.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
|
@ -14,30 +14,18 @@ require:
|
|||
- rubocop-rails
|
||||
- rubocop-rake
|
||||
|
||||
# Offense count: 524
|
||||
# Offense count: 550
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
||||
# URISchemes: http, https
|
||||
Layout/LineLength:
|
||||
Max: 270
|
||||
|
||||
# Offense count: 62
|
||||
# Cop supports --auto-correct.
|
||||
Lint/AmbiguousOperatorPrecedence:
|
||||
Exclude:
|
||||
- 'app/controllers/geocoder_controller.rb'
|
||||
- 'app/models/user.rb'
|
||||
- 'lib/bounding_box.rb'
|
||||
- 'lib/osm.rb'
|
||||
- 'lib/rich_text.rb'
|
||||
- 'lib/short_link.rb'
|
||||
- 'test/controllers/api/old_nodes_controller_test.rb'
|
||||
- 'test/lib/short_link_test.rb'
|
||||
|
||||
# Offense count: 34
|
||||
# Configuration parameters: AllowSafeAssignment.
|
||||
Lint/AssignmentInCondition:
|
||||
Exclude:
|
||||
- 'app/controllers/accounts_controller.rb'
|
||||
- 'app/controllers/api/traces_controller.rb'
|
||||
- 'app/controllers/api/user_preferences_controller.rb'
|
||||
- 'app/controllers/application_controller.rb'
|
||||
|
@ -53,22 +41,12 @@ Lint/AssignmentInCondition:
|
|||
- 'lib/osm.rb'
|
||||
- 'script/deliver-message'
|
||||
|
||||
# Offense count: 8
|
||||
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches.
|
||||
Lint/DuplicateBranch:
|
||||
Exclude:
|
||||
- 'app/controllers/api_controller.rb'
|
||||
- 'app/controllers/diary_entries_controller.rb'
|
||||
- 'app/controllers/geocoder_controller.rb'
|
||||
- 'app/helpers/browse_tags_helper.rb'
|
||||
- 'lib/password_hash.rb'
|
||||
|
||||
# Offense count: 643
|
||||
# Offense count: 665
|
||||
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
|
||||
Metrics/AbcSize:
|
||||
Max: 189
|
||||
|
||||
# Offense count: 69
|
||||
# Offense count: 73
|
||||
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
|
||||
# IgnoredMethods: refine
|
||||
Metrics/BlockLength:
|
||||
|
@ -82,14 +60,14 @@ Metrics/BlockNesting:
|
|||
# Offense count: 25
|
||||
# Configuration parameters: CountComments, CountAsOne.
|
||||
Metrics/ClassLength:
|
||||
Max: 337
|
||||
Max: 313
|
||||
|
||||
# Offense count: 58
|
||||
# Configuration parameters: IgnoredMethods.
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 25
|
||||
|
||||
# Offense count: 716
|
||||
# Offense count: 742
|
||||
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
|
||||
Metrics/MethodLength:
|
||||
Max: 179
|
||||
|
@ -99,21 +77,19 @@ Metrics/MethodLength:
|
|||
Metrics/ParameterLists:
|
||||
Max: 6
|
||||
|
||||
# Offense count: 62
|
||||
# Offense count: 59
|
||||
# Configuration parameters: IgnoredMethods.
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 26
|
||||
|
||||
# Offense count: 528
|
||||
# Offense count: 550
|
||||
Minitest/MultipleAssertions:
|
||||
Max: 54
|
||||
Max: 52
|
||||
|
||||
# Offense count: 3
|
||||
# Offense count: 1
|
||||
Naming/AccessorMethodName:
|
||||
Exclude:
|
||||
- 'app/controllers/application_controller.rb'
|
||||
- 'app/helpers/title_helper.rb'
|
||||
- 'lib/osm.rb'
|
||||
|
||||
# Offense count: 8
|
||||
# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros.
|
||||
|
@ -123,12 +99,7 @@ Naming/AccessorMethodName:
|
|||
# MethodDefinitionMacros: define_method, define_singleton_method
|
||||
Naming/PredicateName:
|
||||
Exclude:
|
||||
- 'app/models/changeset.rb'
|
||||
- 'app/models/old_node.rb'
|
||||
- 'app/models/old_relation.rb'
|
||||
- 'app/models/old_way.rb'
|
||||
- 'app/models/user.rb'
|
||||
- 'lib/classic_pagination/pagination.rb'
|
||||
|
||||
# Offense count: 5
|
||||
# Configuration parameters: Database, Include.
|
||||
|
@ -155,12 +126,26 @@ Rails/HelperInstanceVariable:
|
|||
Exclude:
|
||||
- 'app/helpers/title_helper.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Offense count: 16
|
||||
# Configuration parameters: IgnoreScopes, Include.
|
||||
# Include: app/models/**/*.rb
|
||||
Rails/InverseOf:
|
||||
Exclude:
|
||||
- 'app/models/changeset.rb'
|
||||
- 'app/models/diary_entry.rb'
|
||||
- 'app/models/friendship.rb'
|
||||
- 'app/models/issue.rb'
|
||||
- 'app/models/message.rb'
|
||||
- 'app/models/note.rb'
|
||||
- 'app/models/user.rb'
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: Include.
|
||||
# Include: app/controllers/**/*.rb
|
||||
Rails/LexicallyScopedActionFilter:
|
||||
Exclude:
|
||||
- 'app/controllers/oauth2_applications_controller.rb'
|
||||
- 'app/controllers/oauth2_authorizations_controller.rb'
|
||||
|
||||
# Offense count: 5
|
||||
# Configuration parameters: Include.
|
||||
|
@ -182,13 +167,6 @@ Rails/OutputSafety:
|
|||
- 'lib/rich_text.rb'
|
||||
- 'test/helpers/application_helper_test.rb'
|
||||
|
||||
# Offense count: 91
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
# SupportedStyles: strict, flexible
|
||||
Rails/TimeZone:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Rake/Desc:
|
||||
|
@ -198,15 +176,15 @@ Rake/Desc:
|
|||
- 'lib/tasks/subscribe_diary_authors.rake'
|
||||
- 'lib/tasks/subscribe_old_changesets.rake'
|
||||
|
||||
# Offense count: 602
|
||||
# Offense count: 617
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
# SupportedStyles: always, always_true, never
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 73
|
||||
# Offense count: 72
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: Strict.
|
||||
# Configuration parameters: Strict, AllowedNumbers.
|
||||
Style/NumericLiterals:
|
||||
MinDigits: 15
|
||||
|
|
59
CONFIGURE.md
59
CONFIGURE.md
|
@ -30,9 +30,7 @@ If you create a user by signing up to your local website, you need to confirm th
|
|||
$ bundle exec rails console
|
||||
>> user = User.find_by(:display_name => "My New User Name")
|
||||
=> #[ ... ]
|
||||
>> user.status = "active"
|
||||
=> "active"
|
||||
>> user.save!
|
||||
>> user.activate!
|
||||
=> true
|
||||
>> quit
|
||||
```
|
||||
|
@ -56,26 +54,26 @@ $ bundle exec rails console
|
|||
|
||||
## OAuth Consumer Keys
|
||||
|
||||
Three of the built-in applications communicate via the API, and therefore need OAuth consumer keys configured. These are:
|
||||
There are two built-in applications which communicate via the API, and therefore need to be registered as OAuth 2 applications. These are:
|
||||
|
||||
* iD
|
||||
* The website itself (for the Notes functionality)
|
||||
|
||||
For example, to use the iD editor you need to register it as an OAuth application.
|
||||
For iD, do the following:
|
||||
|
||||
Do the following:
|
||||
* Log into your Rails Port instance - e.g. http://localhost:3000
|
||||
* Click on your user name to go to your user page
|
||||
* Click on "my settings" on the user page
|
||||
* Click on "oauth settings" on the My settings page
|
||||
* Click on 'Register your application'.
|
||||
* Unless you have set up alternatives, use Name: "Local iD" and URL: "http://localhost:3000"
|
||||
* Check the 'modify the map' box.
|
||||
* Everything else can be left with the default blank values.
|
||||
* Click the "Register" button
|
||||
* On the next page, copy the "consumer key"
|
||||
* Go to "[OAuth 2 applications](http://localhost:3000/oauth2/applications)" on the My settings page.
|
||||
* Click on "Register new application".
|
||||
* Unless you have set up alternatives, use Name: "Local iD" and Main Application URL: "http://localhost:3000"
|
||||
* Check boxes for the following Permissions
|
||||
* 'Read user preferences'
|
||||
* 'Modify user preferences'
|
||||
* 'Modify the map'
|
||||
* 'Read private GPS traces'
|
||||
* 'Upload GPS traces'
|
||||
* 'Modify notes'
|
||||
* On the next page, copy the "Client ID"
|
||||
* Edit config/settings.local.yml in your rails tree
|
||||
* Add the "id_key" configuration key and the consumer key as the value
|
||||
* Add the "id_application" configuration with the "Client ID" as the value
|
||||
* Restart your rails server
|
||||
|
||||
An example excerpt from settings.local.yml:
|
||||
|
@ -83,11 +81,32 @@ An example excerpt from settings.local.yml:
|
|||
```
|
||||
# Default editor
|
||||
default_editor: "id"
|
||||
# OAuth consumer key for iD
|
||||
id_key: "8lFmZPsagHV4l3rkAHq0hWY5vV3Ctl3oEFY1aXth"
|
||||
# OAuth 2 Client ID for iD
|
||||
id_application: "Snv…OA0"
|
||||
```
|
||||
|
||||
Follow the same process for registering and configuring the website/Notes (`oauth_key`), or to save time, simply reuse the same consumer key for each.
|
||||
To allow [Notes](https://wiki.openstreetmap.org/wiki/Notes) and changeset discussions to work, follow a similar process, this time registering an OAuth 2 application for the web site:
|
||||
|
||||
* Go to "[OAuth 2 applications](http://localhost:3000/oauth2/applications)" on the My settings page.
|
||||
* Click on "Register new application".
|
||||
* Use Name: "OpenStreetMap Web Site" and Redirect URIs: "http://localhost:3000"
|
||||
* Check boxes for the following Permissions
|
||||
* 'Modify the map'
|
||||
* 'Modify notes'
|
||||
* On the next page, copy the "Client Secret" and "Client ID"
|
||||
* Edit config/settings.local.yml in your rails tree
|
||||
* Add the "oauth_application" configuration with the "Client ID" as the value
|
||||
* Add the "oauth_key" configuration with the "Client Secret" as the value
|
||||
* Restart your rails server
|
||||
|
||||
An example excerpt from settings.local.yml:
|
||||
|
||||
```
|
||||
# OAuth 2 Client ID for the web site
|
||||
oauth_application: "SGm8QJ6tmoPXEaUPIZzLUmm1iujltYZVWCp9hvGsqXg"
|
||||
# OAuth 2 Client Secret for the web site
|
||||
oauth_key: "eRHPm4GtEnw9ovB1Iw7EcCLGtUb66bXbAAspv3aJxlI"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ bundle exec rails test:all
|
|||
|
||||
You can view test coverage statistics by browsing the `coverage` directory.
|
||||
|
||||
The tests are automatically run on Pull Requests and other commits with the
|
||||
results shown on [Travis CI](https://travis-ci.org/openstreetmap/openstreetmap-website).
|
||||
The tests are automatically run on Pull Requests and other commits via github
|
||||
actions. The results shown are within the PR display on github.
|
||||
|
||||
## Static Analysis
|
||||
|
||||
|
@ -79,14 +79,6 @@ database, and update the list of available keys manually.
|
|||
Adding or removing keys to this list is therefore discouraged, but contributions
|
||||
to the descriptive texts are welcome.
|
||||
|
||||
## Code Documentation
|
||||
|
||||
To generate the HTML documentation of the API/rails code, run the command
|
||||
|
||||
```
|
||||
rake doc:app
|
||||
```
|
||||
|
||||
## Committing
|
||||
|
||||
When you submit patches, the project maintainer has to read them and
|
||||
|
|
|
@ -10,13 +10,12 @@ RUN apt-get update \
|
|||
default-jre-headless \
|
||||
file \
|
||||
firefox-geckodriver \
|
||||
imagemagick \
|
||||
libarchive-dev \
|
||||
libffi-dev \
|
||||
libgd-dev \
|
||||
libmagickwand-dev \
|
||||
libpq-dev \
|
||||
libsasl2-dev \
|
||||
libvips-dev \
|
||||
libxml2-dev \
|
||||
libxslt1-dev \
|
||||
locales \
|
||||
|
|
21
Gemfile
21
Gemfile
|
@ -1,7 +1,7 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
# Require rails
|
||||
gem "rails", "6.1.4.1"
|
||||
gem "rails", "7.0.4"
|
||||
|
||||
# Require json for multi_json
|
||||
gem "json"
|
||||
|
@ -36,23 +36,26 @@ gem "image_optim_rails"
|
|||
# Use argon2 for password hashing
|
||||
gem "argon2"
|
||||
|
||||
# Support brotli compression for assets
|
||||
gem "sprockets-exporters_pack"
|
||||
|
||||
# Load rails plugins
|
||||
gem "actionpack-page_caching", ">= 1.2.0"
|
||||
gem "activerecord-import"
|
||||
gem "active_record_union"
|
||||
gem "bootstrap", "~> 4.5.0"
|
||||
gem "bootstrap_form", "~> 4.0"
|
||||
gem "bootstrap", "~> 5.1.0"
|
||||
gem "bootstrap_form", "~> 5.0"
|
||||
gem "cancancan"
|
||||
gem "composite_primary_keys", "~> 13.0.0", "!= 13.0.1"
|
||||
gem "composite_primary_keys", "~> 14.0.0"
|
||||
gem "config"
|
||||
gem "delayed_job_active_record"
|
||||
gem "frozen_record"
|
||||
gem "http_accept_language", "~> 2.1.1"
|
||||
gem "i18n-js", ">= 3.0.0"
|
||||
gem "i18n-js", "~> 3.9.2"
|
||||
gem "oauth-plugin", ">= 0.5.1"
|
||||
gem "openstreetmap-deadlock_retry", ">= 1.3.1", :require => "deadlock_retry"
|
||||
gem "rack-cors"
|
||||
gem "rails-i18n", "~> 6.0.0"
|
||||
gem "rails-i18n", "~> 7.0.0"
|
||||
gem "rinku", ">= 2.0.6", :require => "rails_rinku"
|
||||
gem "strong_migrations"
|
||||
gem "validates_email_format_of", ">= 1.5.1"
|
||||
|
@ -74,7 +77,7 @@ gem "omniauth-rails_csrf_protection", "~> 1.0"
|
|||
gem "omniauth-windowslive"
|
||||
|
||||
# Doorkeeper for OAuth2
|
||||
gem "doorkeeper"
|
||||
gem "doorkeeper", "~> 5.5.4"
|
||||
gem "doorkeeper-i18n"
|
||||
|
||||
# Markdown formatting support
|
||||
|
@ -145,14 +148,14 @@ group :test do
|
|||
gem "erb_lint", :require => false
|
||||
gem "factory_bot_rails"
|
||||
gem "minitest", "~> 5.1"
|
||||
gem "puma", "~> 5.3"
|
||||
gem "puma", "~> 5.6"
|
||||
gem "rails-controller-testing"
|
||||
gem "rubocop"
|
||||
gem "rubocop-minitest"
|
||||
gem "rubocop-performance"
|
||||
gem "rubocop-rails"
|
||||
gem "rubocop-rake"
|
||||
gem "selenium-webdriver", "~> 3.142.7"
|
||||
gem "selenium-webdriver"
|
||||
gem "simplecov", :require => false
|
||||
gem "simplecov-lcov", :require => false
|
||||
gem "webmock"
|
||||
|
|
445
Gemfile.lock
445
Gemfile.lock
|
@ -1,132 +1,138 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
aasm (5.2.0)
|
||||
aasm (5.3.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
actioncable (6.1.4.1)
|
||||
actionpack (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
actioncable (7.0.4)
|
||||
actionpack (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.1.4.1)
|
||||
actionpack (= 6.1.4.1)
|
||||
activejob (= 6.1.4.1)
|
||||
activerecord (= 6.1.4.1)
|
||||
activestorage (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
actionmailbox (7.0.4)
|
||||
actionpack (= 7.0.4)
|
||||
activejob (= 7.0.4)
|
||||
activerecord (= 7.0.4)
|
||||
activestorage (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.1.4.1)
|
||||
actionpack (= 6.1.4.1)
|
||||
actionview (= 6.1.4.1)
|
||||
activejob (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.0.4)
|
||||
actionpack (= 7.0.4)
|
||||
actionview (= 7.0.4)
|
||||
activejob (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.1.4.1)
|
||||
actionview (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
rack (~> 2.0, >= 2.0.9)
|
||||
actionpack (7.0.4)
|
||||
actionview (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
rack (~> 2.0, >= 2.2.0)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionpack-page_caching (1.2.4)
|
||||
actionpack (>= 4.0.0)
|
||||
actiontext (6.1.4.1)
|
||||
actionpack (= 6.1.4.1)
|
||||
activerecord (= 6.1.4.1)
|
||||
activestorage (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
actiontext (7.0.4)
|
||||
actionpack (= 7.0.4)
|
||||
activerecord (= 7.0.4)
|
||||
activestorage (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
actionview (7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
active_record_union (1.3.0)
|
||||
activerecord (>= 4.0)
|
||||
activejob (6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
activejob (7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
activerecord (6.1.4.1)
|
||||
activemodel (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
activerecord-import (1.2.0)
|
||||
activerecord (>= 3.2)
|
||||
activestorage (6.1.4.1)
|
||||
actionpack (= 6.1.4.1)
|
||||
activejob (= 6.1.4.1)
|
||||
activerecord (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
marcel (~> 1.0.0)
|
||||
activemodel (7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
activerecord (7.0.4)
|
||||
activemodel (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
activerecord-import (1.4.0)
|
||||
activerecord (>= 4.2)
|
||||
activestorage (7.0.4)
|
||||
actionpack (= 7.0.4)
|
||||
activejob (= 7.0.4)
|
||||
activerecord (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (6.1.4.1)
|
||||
activesupport (7.0.4)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
annotate (3.1.1)
|
||||
activerecord (>= 3.2, < 7.0)
|
||||
addressable (2.8.1)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
annotate (3.2.0)
|
||||
activerecord (>= 3.2, < 8.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
argon2 (2.1.1)
|
||||
ffi (~> 1.14)
|
||||
ffi-compiler (~> 1.0)
|
||||
ast (2.4.2)
|
||||
autoprefixer-rails (10.3.3.0)
|
||||
autoprefixer-rails (10.4.7.0)
|
||||
execjs (~> 2)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.539.0)
|
||||
aws-sdk-core (3.124.0)
|
||||
aws-partitions (1.628.0)
|
||||
aws-sdk-core (3.144.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.525.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.52.0)
|
||||
aws-sdk-core (~> 3, >= 3.122.0)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.58.0)
|
||||
aws-sdk-core (~> 3, >= 3.127.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.109.0)
|
||||
aws-sdk-core (~> 3, >= 3.122.0)
|
||||
aws-sdk-s3 (1.114.0)
|
||||
aws-sdk-core (~> 3, >= 3.127.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.4)
|
||||
aws-sigv4 (1.4.0)
|
||||
aws-sigv4 (1.5.1)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
better_errors (2.9.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
better_html (1.0.16)
|
||||
actionview (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
better_html (2.0.1)
|
||||
actionview (>= 6.0)
|
||||
activesupport (>= 6.0)
|
||||
ast (~> 2.0)
|
||||
erubi (~> 1.4)
|
||||
html_tokenizer (~> 0.0.6)
|
||||
parser (>= 2.4)
|
||||
smart_properties
|
||||
binding_of_caller (1.0.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootsnap (1.9.3)
|
||||
msgpack (~> 1.0)
|
||||
bootstrap (4.5.3)
|
||||
bootsnap (1.13.0)
|
||||
msgpack (~> 1.2)
|
||||
bootstrap (5.1.3)
|
||||
autoprefixer-rails (>= 9.1.0)
|
||||
popper_js (>= 1.14.3, < 2)
|
||||
popper_js (>= 2.9.3, < 3)
|
||||
sassc-rails (>= 2.0.0)
|
||||
bootstrap_form (4.5.0)
|
||||
bootstrap_form (5.1.0)
|
||||
actionpack (>= 5.2)
|
||||
activemodel (>= 5.2)
|
||||
brakeman (5.1.2)
|
||||
brakeman (5.3.1)
|
||||
brotli (0.4.0)
|
||||
browser (5.3.1)
|
||||
builder (3.2.4)
|
||||
bzip2-ffi (1.1.0)
|
||||
ffi (~> 1.0)
|
||||
cancancan (3.3.0)
|
||||
canonical-rails (0.2.13)
|
||||
rails (>= 4.1, <= 7.0)
|
||||
capybara (3.36.0)
|
||||
cancancan (3.4.0)
|
||||
canonical-rails (0.2.14)
|
||||
rails (>= 4.1, <= 7.1)
|
||||
capybara (3.37.1)
|
||||
addressable
|
||||
matrix
|
||||
mini_mime (>= 0.1.3)
|
||||
|
@ -135,45 +141,45 @@ GEM
|
|||
rack-test (>= 0.6.3)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
xpath (~> 3.2)
|
||||
childprocess (3.0.0)
|
||||
childprocess (4.1.0)
|
||||
coderay (1.1.3)
|
||||
composite_primary_keys (13.0.0)
|
||||
activerecord (~> 6.1.0)
|
||||
concurrent-ruby (1.1.9)
|
||||
config (3.1.0)
|
||||
composite_primary_keys (14.0.4)
|
||||
activerecord (~> 7.0.2)
|
||||
concurrent-ruby (1.1.10)
|
||||
config (4.0.0)
|
||||
deep_merge (~> 1.2, >= 1.2.1)
|
||||
dry-validation (~> 1.0, >= 1.0.0)
|
||||
connection_pool (2.2.5)
|
||||
crack (0.4.5)
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
dalli (3.1.0)
|
||||
dalli (3.2.2)
|
||||
debug_inspector (1.1.0)
|
||||
deep_merge (1.2.1)
|
||||
delayed_job (4.1.9)
|
||||
activesupport (>= 3.0, < 6.2)
|
||||
delayed_job_active_record (4.1.6)
|
||||
activerecord (>= 3.0, < 6.2)
|
||||
deep_merge (1.2.2)
|
||||
delayed_job (4.1.10)
|
||||
activesupport (>= 3.0, < 8.0)
|
||||
delayed_job_active_record (4.1.7)
|
||||
activerecord (>= 3.0, < 8.0)
|
||||
delayed_job (>= 3.0, < 5)
|
||||
digest (3.1.0)
|
||||
docile (1.4.0)
|
||||
doorkeeper (5.5.4)
|
||||
railties (>= 5)
|
||||
doorkeeper-i18n (5.2.3)
|
||||
doorkeeper-i18n (5.2.4)
|
||||
doorkeeper (>= 5.2)
|
||||
dry-configurable (0.13.0)
|
||||
dry-configurable (0.15.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 0.6)
|
||||
dry-container (0.9.0)
|
||||
dry-container (0.10.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-configurable (~> 0.13, >= 0.13.0)
|
||||
dry-core (0.7.1)
|
||||
dry-core (0.8.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-inflector (0.2.1)
|
||||
dry-initializer (3.0.4)
|
||||
dry-inflector (0.3.0)
|
||||
dry-initializer (3.1.1)
|
||||
dry-logic (1.2.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 0.5, >= 0.5)
|
||||
dry-schema (1.8.0)
|
||||
dry-schema (1.10.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-configurable (~> 0.13, >= 0.13.0)
|
||||
dry-core (~> 0.5, >= 0.5)
|
||||
|
@ -186,48 +192,32 @@ GEM
|
|||
dry-core (~> 0.5, >= 0.5)
|
||||
dry-inflector (~> 0.1, >= 0.1.2)
|
||||
dry-logic (~> 1.0, >= 1.0.2)
|
||||
dry-validation (1.7.0)
|
||||
dry-validation (1.8.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-container (~> 0.7, >= 0.7.1)
|
||||
dry-core (~> 0.5, >= 0.5)
|
||||
dry-initializer (~> 3.0)
|
||||
dry-schema (~> 1.8, >= 1.8.0)
|
||||
erb_lint (0.1.1)
|
||||
erb_lint (0.2.0)
|
||||
activesupport
|
||||
better_html (~> 1.0.7)
|
||||
html_tokenizer
|
||||
better_html (>= 2.0.1)
|
||||
parser (>= 2.7.1.4)
|
||||
rainbow
|
||||
rubocop
|
||||
smart_properties
|
||||
erubi (1.10.0)
|
||||
erubi (1.11.0)
|
||||
execjs (2.8.1)
|
||||
exifr (1.3.9)
|
||||
factory_bot (6.2.0)
|
||||
factory_bot (6.2.1)
|
||||
activesupport (>= 5.0.0)
|
||||
factory_bot_rails (6.2.0)
|
||||
factory_bot (~> 6.2.0)
|
||||
railties (>= 5.0.0)
|
||||
faraday (1.8.0)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0.1)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.1)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday (2.5.2)
|
||||
faraday-net_http (>= 2.0, < 3.1)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-net_http (1.0.1)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
ffi (1.15.4)
|
||||
faraday-net_http (3.0.0)
|
||||
ffi (1.15.5)
|
||||
ffi-compiler (1.0.1)
|
||||
ffi (>= 1.0.0)
|
||||
rake
|
||||
|
@ -242,12 +232,11 @@ GEM
|
|||
activesupport (>= 5.0)
|
||||
hashdiff (1.0.1)
|
||||
hashie (5.0.0)
|
||||
html_tokenizer (0.0.7)
|
||||
htmlentities (4.3.4)
|
||||
http_accept_language (2.1.1)
|
||||
i18n (1.8.11)
|
||||
i18n (1.12.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n-js (3.9.0)
|
||||
i18n-js (3.9.2)
|
||||
i18n (>= 0.6.6)
|
||||
image_optim (0.31.1)
|
||||
exifr (~> 1.2, >= 1.2.2)
|
||||
|
@ -255,35 +244,36 @@ GEM
|
|||
image_size (>= 1.5, < 4)
|
||||
in_threads (~> 1.3)
|
||||
progress (~> 3.0, >= 3.0.1)
|
||||
image_optim_rails (0.4.3)
|
||||
image_optim_rails (0.5.0)
|
||||
image_optim (~> 0.24)
|
||||
rails
|
||||
railties
|
||||
sprockets
|
||||
image_processing (1.12.1)
|
||||
image_processing (1.12.2)
|
||||
mini_magick (>= 4.9.5, < 5)
|
||||
ruby-vips (>= 2.0.17, < 3)
|
||||
image_size (3.0.1)
|
||||
in_threads (1.5.4)
|
||||
jbuilder (2.11.3)
|
||||
image_size (3.0.2)
|
||||
in_threads (1.6.0)
|
||||
jbuilder (2.11.5)
|
||||
actionview (>= 5.0.0)
|
||||
activesupport (>= 5.0.0)
|
||||
jmespath (1.4.0)
|
||||
jquery-rails (4.4.0)
|
||||
jmespath (1.6.1)
|
||||
jquery-rails (4.5.0)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.6.1)
|
||||
jwt (2.3.0)
|
||||
json (2.6.2)
|
||||
jwt (2.5.0)
|
||||
kgio (2.11.4)
|
||||
kramdown (2.3.1)
|
||||
kramdown (2.4.0)
|
||||
rexml
|
||||
libxml-ruby (3.2.1)
|
||||
listen (3.7.0)
|
||||
libxml-ruby (3.2.3)
|
||||
listen (3.7.1)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
logstasher (2.1.5)
|
||||
activesupport (>= 5.2)
|
||||
request_store
|
||||
loofah (2.12.0)
|
||||
loofah (2.18.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.7.1)
|
||||
|
@ -294,15 +284,28 @@ GEM
|
|||
method_source (1.0.0)
|
||||
mini_magick (4.11.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.6.1)
|
||||
minitest (5.14.4)
|
||||
msgpack (1.4.2)
|
||||
mini_portile2 (2.8.0)
|
||||
minitest (5.16.3)
|
||||
msgpack (1.5.6)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
net-imap (0.2.3)
|
||||
digest
|
||||
net-protocol
|
||||
strscan
|
||||
net-pop (0.1.1)
|
||||
digest
|
||||
net-protocol
|
||||
timeout
|
||||
net-protocol (0.1.3)
|
||||
timeout
|
||||
net-smtp (0.3.1)
|
||||
digest
|
||||
net-protocol
|
||||
timeout
|
||||
nio4r (2.5.8)
|
||||
nokogiri (1.12.5)
|
||||
mini_portile2 (~> 2.6.1)
|
||||
nokogiri (1.13.8)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
oauth (0.4.7)
|
||||
oauth-plugin (0.5.1)
|
||||
|
@ -310,8 +313,8 @@ GEM
|
|||
oauth (~> 0.4.4)
|
||||
oauth2 (>= 0.5.0)
|
||||
rack
|
||||
oauth2 (1.4.7)
|
||||
faraday (>= 0.8, < 2.0)
|
||||
oauth2 (1.4.10)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
jwt (>= 1.0, < 3.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
|
@ -325,7 +328,7 @@ GEM
|
|||
omniauth-github (2.0.0)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-oauth2 (~> 1.7.1)
|
||||
omniauth-google-oauth2 (1.0.0)
|
||||
omniauth-google-oauth2 (1.0.1)
|
||||
jwt (>= 2.0)
|
||||
oauth2 (~> 1.1)
|
||||
omniauth (~> 2.0)
|
||||
|
@ -336,57 +339,56 @@ GEM
|
|||
omniauth-oauth (1.2.0)
|
||||
oauth
|
||||
omniauth (>= 1.0, < 3)
|
||||
omniauth-oauth2 (1.7.2)
|
||||
oauth2 (~> 1.4)
|
||||
omniauth-oauth2 (1.7.3)
|
||||
oauth2 (>= 1.4, < 3)
|
||||
omniauth (>= 1.9, < 3)
|
||||
omniauth-openid (2.0.1)
|
||||
omniauth (>= 1.0, < 3.0)
|
||||
rack-openid (~> 1.4.0)
|
||||
omniauth-rails_csrf_protection (1.0.0)
|
||||
omniauth-rails_csrf_protection (1.0.1)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-windowslive (0.0.12)
|
||||
multi_json (~> 1.12)
|
||||
omniauth-oauth2 (~> 1.4)
|
||||
openstreetmap-deadlock_retry (1.3.1)
|
||||
parallel (1.21.0)
|
||||
parser (3.0.3.1)
|
||||
parallel (1.22.1)
|
||||
parser (3.1.2.1)
|
||||
ast (~> 2.4.1)
|
||||
pg (1.2.3)
|
||||
popper_js (1.16.0)
|
||||
pg (1.4.3)
|
||||
popper_js (2.11.5)
|
||||
progress (3.6.0)
|
||||
public_suffix (4.0.6)
|
||||
puma (5.5.2)
|
||||
public_suffix (5.0.0)
|
||||
puma (5.6.5)
|
||||
nio4r (~> 2.0)
|
||||
quad_tile (1.0.1)
|
||||
r2 (0.2.7)
|
||||
racc (1.6.0)
|
||||
rack (2.2.3)
|
||||
rack (2.2.4)
|
||||
rack-cors (1.1.1)
|
||||
rack (>= 2.0.0)
|
||||
rack-openid (1.4.2)
|
||||
rack (>= 1.1.0)
|
||||
ruby-openid (>= 2.1.8)
|
||||
rack-protection (2.1.0)
|
||||
rack-protection (2.2.2)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-test (2.0.2)
|
||||
rack (>= 1.3)
|
||||
rack-uri_sanitizer (0.0.2)
|
||||
rails (6.1.4.1)
|
||||
actioncable (= 6.1.4.1)
|
||||
actionmailbox (= 6.1.4.1)
|
||||
actionmailer (= 6.1.4.1)
|
||||
actionpack (= 6.1.4.1)
|
||||
actiontext (= 6.1.4.1)
|
||||
actionview (= 6.1.4.1)
|
||||
activejob (= 6.1.4.1)
|
||||
activemodel (= 6.1.4.1)
|
||||
activerecord (= 6.1.4.1)
|
||||
activestorage (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
rails (7.0.4)
|
||||
actioncable (= 7.0.4)
|
||||
actionmailbox (= 7.0.4)
|
||||
actionmailer (= 7.0.4)
|
||||
actionpack (= 7.0.4)
|
||||
actiontext (= 7.0.4)
|
||||
actionview (= 7.0.4)
|
||||
activejob (= 7.0.4)
|
||||
activemodel (= 7.0.4)
|
||||
activerecord (= 7.0.4)
|
||||
activestorage (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 6.1.4.1)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
railties (= 7.0.4)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
|
@ -394,48 +396,50 @@ GEM
|
|||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.4.2)
|
||||
rails-html-sanitizer (1.4.3)
|
||||
loofah (~> 2.3)
|
||||
rails-i18n (6.0.0)
|
||||
rails-i18n (7.0.5)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 7)
|
||||
railties (6.1.4.1)
|
||||
actionpack (= 6.1.4.1)
|
||||
activesupport (= 6.1.4.1)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.0.4)
|
||||
actionpack (= 7.0.4)
|
||||
activesupport (= 7.0.4)
|
||||
method_source
|
||||
rake (>= 0.13)
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
rainbow (3.0.0)
|
||||
zeitwerk (~> 2.5)
|
||||
rainbow (3.1.1)
|
||||
rake (13.0.6)
|
||||
rb-fsevent (0.11.0)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
regexp_parser (2.2.0)
|
||||
request_store (1.5.0)
|
||||
regexp_parser (2.5.0)
|
||||
request_store (1.5.1)
|
||||
rack (>= 1.4)
|
||||
rexml (3.2.5)
|
||||
rinku (2.0.6)
|
||||
rotp (6.2.0)
|
||||
rubocop (1.23.0)
|
||||
rubocop (1.36.0)
|
||||
json (~> 2.3)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.0.0.0)
|
||||
parser (>= 3.1.2.1)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml
|
||||
rubocop-ast (>= 1.12.0, < 2.0)
|
||||
rexml (>= 3.2.5, < 4.0)
|
||||
rubocop-ast (>= 1.20.1, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.14.0)
|
||||
parser (>= 3.0.1.1)
|
||||
rubocop-minitest (0.17.0)
|
||||
rubocop-ast (1.21.0)
|
||||
parser (>= 3.1.1.0)
|
||||
rubocop-minitest (0.22.0)
|
||||
rubocop (>= 0.90, < 2.0)
|
||||
rubocop-performance (1.12.0)
|
||||
rubocop-performance (1.14.3)
|
||||
rubocop (>= 1.7.0, < 2.0)
|
||||
rubocop-ast (>= 0.4.0)
|
||||
rubocop-rails (2.12.4)
|
||||
rubocop-rails (2.16.0)
|
||||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.7.0, < 2.0)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
rubocop-rake (0.6.0)
|
||||
rubocop (~> 1.0)
|
||||
ruby-openid (2.9.2)
|
||||
|
@ -455,47 +459,55 @@ GEM
|
|||
sprockets (> 3.0)
|
||||
sprockets-rails
|
||||
tilt
|
||||
secure_headers (6.3.3)
|
||||
selenium-webdriver (3.142.7)
|
||||
childprocess (>= 0.5, < 4.0)
|
||||
rubyzip (>= 1.2.2)
|
||||
secure_headers (6.4.0)
|
||||
selenium-webdriver (4.4.0)
|
||||
childprocess (>= 0.5, < 5.0)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 3.0)
|
||||
websocket (~> 1.0)
|
||||
simplecov (0.21.2)
|
||||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.12.3)
|
||||
simplecov-lcov (0.8.0)
|
||||
simplecov_json_formatter (0.1.3)
|
||||
smart_properties (1.16.3)
|
||||
sprockets (4.0.2)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
smart_properties (1.17.0)
|
||||
sprockets (4.1.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.4.1)
|
||||
sprockets-exporters_pack (0.1.2)
|
||||
brotli (>= 0.2.0)
|
||||
sprockets (>= 4.0.0.beta3)
|
||||
sprockets-rails (3.4.2)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
sprockets (>= 3.0.0)
|
||||
strong_migrations (0.7.8)
|
||||
activerecord (>= 5)
|
||||
terser (1.1.8)
|
||||
strong_migrations (1.3.0)
|
||||
activerecord (>= 5.2)
|
||||
strscan (3.0.4)
|
||||
terser (1.1.12)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
thor (1.1.0)
|
||||
tilt (2.0.10)
|
||||
tzinfo (2.0.4)
|
||||
thor (1.2.1)
|
||||
tilt (2.0.11)
|
||||
timeout (0.3.0)
|
||||
tzinfo (2.0.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
unicode-display_width (2.1.0)
|
||||
validates_email_format_of (1.6.3)
|
||||
unicode-display_width (2.2.0)
|
||||
validates_email_format_of (1.7.2)
|
||||
i18n
|
||||
vendorer (0.2.0)
|
||||
webmock (3.14.0)
|
||||
webmock (3.18.1)
|
||||
addressable (>= 2.8.0)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
websocket (1.2.9)
|
||||
websocket-driver (0.7.5)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.5.1)
|
||||
zeitwerk (2.6.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
@ -512,21 +524,21 @@ DEPENDENCIES
|
|||
better_errors
|
||||
binding_of_caller
|
||||
bootsnap (>= 1.4.2)
|
||||
bootstrap (~> 4.5.0)
|
||||
bootstrap_form (~> 4.0)
|
||||
bootstrap (~> 5.1.0)
|
||||
bootstrap_form (~> 5.0)
|
||||
brakeman
|
||||
browser
|
||||
bzip2-ffi
|
||||
cancancan
|
||||
canonical-rails
|
||||
capybara (>= 2.15)
|
||||
composite_primary_keys (~> 13.0.0, != 13.0.1)
|
||||
composite_primary_keys (~> 14.0.0)
|
||||
config
|
||||
connection_pool
|
||||
dalli
|
||||
debug_inspector
|
||||
delayed_job_active_record
|
||||
doorkeeper
|
||||
doorkeeper (~> 5.5.4)
|
||||
doorkeeper-i18n
|
||||
erb_lint
|
||||
factory_bot_rails
|
||||
|
@ -536,7 +548,7 @@ DEPENDENCIES
|
|||
gd2-ffij (>= 0.4.0)
|
||||
htmlentities
|
||||
http_accept_language (~> 2.1.1)
|
||||
i18n-js (>= 3.0.0)
|
||||
i18n-js (~> 3.9.2)
|
||||
image_optim_rails
|
||||
image_processing
|
||||
jbuilder (~> 2.7)
|
||||
|
@ -561,14 +573,14 @@ DEPENDENCIES
|
|||
omniauth-windowslive
|
||||
openstreetmap-deadlock_retry (>= 1.3.1)
|
||||
pg
|
||||
puma (~> 5.3)
|
||||
puma (~> 5.6)
|
||||
quad_tile (~> 1.0.1)
|
||||
r2 (~> 0.2.7)
|
||||
rack-cors
|
||||
rack-uri_sanitizer
|
||||
rails (= 6.1.4.1)
|
||||
rails (= 7.0.4)
|
||||
rails-controller-testing
|
||||
rails-i18n (~> 6.0.0)
|
||||
rails-i18n (~> 7.0.0)
|
||||
rinku (>= 2.0.6)
|
||||
rotp
|
||||
rubocop
|
||||
|
@ -579,9 +591,10 @@ DEPENDENCIES
|
|||
sanitize
|
||||
sassc-rails
|
||||
secure_headers
|
||||
selenium-webdriver (~> 3.142.7)
|
||||
selenium-webdriver
|
||||
simplecov
|
||||
simplecov-lcov
|
||||
sprockets-exporters_pack
|
||||
strong_migrations
|
||||
terser
|
||||
validates_email_format_of (>= 1.5.1)
|
||||
|
@ -589,4 +602,4 @@ DEPENDENCIES
|
|||
webmock
|
||||
|
||||
BUNDLED WITH
|
||||
2.2.19
|
||||
2.3.7
|
||||
|
|
14
INSTALL.md
14
INSTALL.md
|
@ -24,7 +24,6 @@ of packages required before you can get the various gems installed.
|
|||
|
||||
* Ruby 2.7+
|
||||
* PostgreSQL 9.1+
|
||||
* ImageMagick
|
||||
* Bundler (see note below about [developer Ruby setup](#rbenv))
|
||||
* Javascript Runtime
|
||||
|
||||
|
@ -33,10 +32,10 @@ These can be installed on Ubuntu 20.04 or later with:
|
|||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install ruby2.7 libruby2.7 ruby2.7-dev \
|
||||
libmagickwand-dev libxml2-dev libxslt1-dev nodejs \
|
||||
libvips-dev libxml2-dev libxslt1-dev nodejs \
|
||||
apache2 apache2-dev build-essential git-core firefox-geckodriver \
|
||||
postgresql postgresql-contrib libpq-dev libsasl2-dev \
|
||||
imagemagick libffi-dev libgd-dev libarchive-dev libbz2-dev yarnpkg
|
||||
libffi-dev libgd-dev libarchive-dev libbz2-dev yarnpkg
|
||||
sudo gem2.7 install bundler
|
||||
```
|
||||
|
||||
|
@ -51,8 +50,8 @@ sudo dnf install ruby ruby-devel rubygem-rdoc rubygem-bundler rubygems \
|
|||
libxml2-devel nodejs \
|
||||
gcc gcc-c++ git \
|
||||
postgresql postgresql-server postgresql-contrib libpq-devel \
|
||||
perl-podlators ImageMagick libffi-devel gd-devel libarchive-devel \
|
||||
bzip2-devel nodejs-yarn
|
||||
perl-podlators libffi-devel gd-devel libarchive-devel \
|
||||
bzip2-devel nodejs-yarn vips-devel
|
||||
```
|
||||
|
||||
If you didn't already have PostgreSQL installed then create a PostgreSQL instance and start the server:
|
||||
|
@ -90,7 +89,7 @@ Installing other dependencies:
|
|||
|
||||
* Install Homebrew from https://brew.sh/
|
||||
* Install the latest version of Ruby: `brew install ruby`
|
||||
* Install other dependencies: `brew install imagemagick libxml2 gd yarn pngcrush optipng pngquant jhead jpegoptim gifsicle svgo`
|
||||
* Install other dependencies: `brew install libxml2 gd yarn pngcrush optipng pngquant jhead jpegoptim gifsicle svgo advancecomp vips`
|
||||
* Install Bundler: `gem install bundler` (you might need to `sudo gem install bundler` if you get an error about permissions - or see note below about [developer Ruby setup](#rbenv))
|
||||
|
||||
You will need to tell `bundler` that `libxml2` is installed in a Homebrew location. If it uses the system-installed one then you will get errors installing the `libxml-ruby` gem later on<a name="macosx-bundle-config"></a>.
|
||||
|
@ -102,8 +101,7 @@ bundle config build.libxml-ruby --with-xml2-config=/usr/local/opt/libxml2/bin/xm
|
|||
If you want to run the tests, you need `geckodriver` as well:
|
||||
|
||||
```
|
||||
brew tap homebrew/cask
|
||||
brew cask install geckodriver
|
||||
brew install geckodriver
|
||||
```
|
||||
|
||||
Note that OS X does not have a /home directory by default, so if you are using the GPX functions, you will need to change the directories specified in config/application.yml.
|
||||
|
|
9
SECURITY.md
Normal file
9
SECURITY.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
We welcome any reports of security vulnerabilities, and we will respond to you quickly to acknowledge receipt.
|
||||
|
||||
To report a vulnerability please email [the maintainers using this link](mailto:tom@compton.nu;openstreetmap-website@gravitystorm.co.uk;security@openstreetmap.org). This will also notify the security team for the main deployment of this software.
|
||||
|
||||
Please note that we do not offer any bug bounties and we do not participate in any bug programs. If your security report is validated by us, then we are happy to credit you publicly in our issue tracker, on request.
|
12
Vendorfile
12
Vendorfile
|
@ -4,28 +4,28 @@ folder 'vendor/assets' do
|
|||
end
|
||||
|
||||
folder 'leaflet' do
|
||||
from 'git://github.com/aratcliffe/Leaflet.contextmenu.git', :tag => 'v1.5.1' do
|
||||
from 'https://github.com/aratcliffe/Leaflet.contextmenu.git', :tag => 'v1.5.1' do
|
||||
file 'leaflet.contextmenu.js', 'dist/leaflet.contextmenu.js'
|
||||
file 'leaflet.contextmenu.css', 'dist/leaflet.contextmenu.css'
|
||||
end
|
||||
|
||||
from 'git://github.com/kajic/leaflet-locationfilter.git' do
|
||||
from 'https://github.com/kajic/leaflet-locationfilter.git' do
|
||||
file 'leaflet.locationfilter.css', 'src/locationfilter.css'
|
||||
file 'leaflet.locationfilter.js', 'src/locationfilter.js'
|
||||
folder 'img', 'src/img'
|
||||
end
|
||||
|
||||
from 'git://github.com/jfirebaugh/leaflet-osm.git' do
|
||||
from 'https://github.com/jfirebaugh/leaflet-osm.git' do
|
||||
file 'leaflet.osm.js', 'leaflet-osm.js'
|
||||
end
|
||||
|
||||
from 'git://github.com/jieter/Leaflet.encoded.git', :tag => '0.0.9' do
|
||||
from 'https://github.com/jieter/Leaflet.encoded.git', :tag => '0.0.9' do
|
||||
file 'leaflet.polyline.js', 'Polyline.encoded.js'
|
||||
end
|
||||
end
|
||||
|
||||
folder 'iD' do
|
||||
from 'git://github.com/openstreetmap/iD', :branch => 'release' do
|
||||
from 'https://github.com/openstreetmap/iD', :branch => 'release' do
|
||||
folder 'iD/data', 'dist/data'
|
||||
folder 'iD/img', 'dist/img'
|
||||
folder 'iD/locales', 'dist/locales'
|
||||
|
@ -38,7 +38,7 @@ folder 'vendor/assets' do
|
|||
end
|
||||
end
|
||||
|
||||
file 'iD.js', 'dist/iD.legacy.js'
|
||||
file 'iD.js', 'dist/iD.js'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class Ability
|
|||
can [:index, :show], Redaction
|
||||
can [:new, :create, :destroy], :session
|
||||
can [:index, :show, :data, :georss, :picture, :icon], Trace
|
||||
can [:terms, :new, :create, :save, :show, :auth_success, :auth_failure], User
|
||||
can [:terms, :new, :create, :save, :suspended, :show, :auth_success, :auth_failure], User
|
||||
can [:index, :show, :blocks_on, :blocks_by], UserBlock
|
||||
can [:index, :show], Node
|
||||
can [:index, :show, :full, :ways_for_node], Way
|
||||
|
@ -36,12 +36,14 @@ class Ability
|
|||
if user
|
||||
can :welcome, :site
|
||||
can [:revoke, :authorize], :oauth
|
||||
can [:show], :deletion
|
||||
|
||||
if Settings.status != "database_offline"
|
||||
can [:index, :new, :create, :show, :edit, :update, :destroy], ClientApplication
|
||||
can [:index, :new, :create, :show, :edit, :update, :destroy], :oauth2_application
|
||||
can [:index, :destroy], :oauth2_authorized_application
|
||||
can [:new, :show, :create, :destroy], :oauth2_authorization
|
||||
can [:edit, :update, :destroy], :account
|
||||
can [:show], :dashboard
|
||||
can [:new, :create, :edit, :update, :comment, :subscribe, :unsubscribe], DiaryEntry
|
||||
can [:make_friend, :remove_friend], Friendship
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><defs><style>.a{fill:#231f20;}.b{fill:#fff;}</style></defs><rect class="a" width="36" height="36"/><path class="b" d="M19.15,19.33a1.73,1.73,0,1,0,1.72-1.83,1.76,1.76,0,0,0-1.72,1.83Zm9,3.64H26V13.33h2.18Zm3.44-11.45.73-2.32L27.7,7.75,24.5,17.94a4.25,4.25,0,0,1,.25,1.39,3.77,3.77,0,0,1-3.88,3.84,3.79,3.79,0,0,1-2.43-.8l-.62,2.69L22,26l-.78,2.47,4.61,1.45,1.44-4.6,4.09.49.37-3.13a1.46,1.46,0,0,1-2.39-1.11,1.45,1.45,0,0,1,2.62-.85l1.08-9Zm-20.5,8.1h2l-1-3.36Zm9.79-4.14a3.69,3.69,0,0,1,3.57,2.32l2.22-9.7L22,7l-.41,1.8-.86-.56-5.42,8.3,1.79-5.69L12.44,9.42l-1.23,3.91h1.85L16.82,23h-2.6l-.47-1.4H10.41L9.9,23H7.32l3.21-8.14,2.28-8.65L8.14,5,3,24.46l4.35,1.15-1.26,4,4.61,1.45,1.7-5.39,1.88,1.23,3.44-5.27A4.07,4.07,0,0,1,17,19.33a3.77,3.77,0,0,1,3.87-3.85"/></svg>
|
Before Width: | Height: | Size: 849 B |
Binary file not shown.
Before Width: | Height: | Size: 82 KiB |
BIN
app/assets/images/banners/sotm_2022.png
Normal file
BIN
app/assets/images/banners/sotm_2022.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
|
@ -7,7 +7,7 @@
|
|||
<g id="Layer_1">
|
||||
<g id="query">
|
||||
<text transform="matrix(1, 0, 0, 1, 276.165, 12.5)" id="tspan3023">
|
||||
<tspan x="-3.665" y="6.012" font-family="Helvetica-Bold" font-size="12" fill="#FFFFFF">?</tspan>
|
||||
<tspan x="-3.665" y="6.012" font-family="Helvetica, sans-serif" font-weight="Bold" font-size="12" fill="#FFFFFF">?</tspan>
|
||||
</text>
|
||||
<path d="M263,1 C263,1 272,8 272,8 C270.944,8.587 269.888,9.173 268.832,9.76 L271.863,16.375 C272.209,17.128 271.878,18.018 271.125,18.364 C270.372,18.709 269.482,18.378 269.136,17.625 L266.201,11.221 C265.134,11.814 264.067,12.407 263,13 L263,1 z" fill="#FFFFFF"/>
|
||||
</g>
|
||||
|
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><defs><style>.a{fill:#32373c;}.b{fill:#fff;}</style></defs><rect class="a" width="36" height="36"/><path class="b" d="M6,18a12,12,0,0,0,6.76,10.8L7,13.12A11.89,11.89,0,0,0,6,18Zm20.09-.6a6.38,6.38,0,0,0-1-3.32,5.48,5.48,0,0,1-1.21-2.8,2.08,2.08,0,0,1,2-2.13h.16A12,12,0,0,0,9.16,9.9,12.18,12.18,0,0,0,8,11.41h.76c1.26,0,3.2-.16,3.2-.16a.49.49,0,0,1,.39.59.48.48,0,0,1-.32.37s-.65.08-1.37.12l4.37,13,2.63-7.88-1.88-5.11a7.37,7.37,0,0,1-1.25-.12.5.5,0,0,1-.3-.64.52.52,0,0,1,.38-.32s2,.16,3.15.16,3.2-.13,3.2-.13a.5.5,0,0,1,.39.59.48.48,0,0,1-.32.37s-.64.08-1.37.12L24,25.26l1.23-3.93A14,14,0,0,0,26.1,17.4Zm-7.89,1.65-3.6,10.47a12,12,0,0,0,7.37-.2l-.09-.16Zm10.34-6.81a10.32,10.32,0,0,1,.08,1.24,11.35,11.35,0,0,1-.91,4.3L24.05,28.34A12,12,0,0,0,28.55,12.24Z"/><path class="b" d="M32.49,18A14.49,14.49,0,1,1,18,3.51,14.49,14.49,0,0,1,32.49,18ZM18,4.38A13.62,13.62,0,1,0,31.62,18h0A13.62,13.62,0,0,0,18,4.38Z"/></svg>
|
Before Width: | Height: | Size: 998 B |
|
@ -13,7 +13,7 @@
|
|||
//= require leaflet.locationfilter
|
||||
//= require i18n
|
||||
//= require oauth
|
||||
//= require piwik
|
||||
//= require matomo
|
||||
//= require richtext
|
||||
//= require qs/dist/qs
|
||||
//= require bs-custom-file-input
|
||||
|
@ -59,11 +59,13 @@ window.updateLinks = function (loc, zoom, layers, object) {
|
|||
var editDisabled = zoom < 13;
|
||||
$("#edit_tab")
|
||||
.tooltip({ placement: "bottom" })
|
||||
.off("click.minzoom")
|
||||
.on("click.minzoom", function () { return !editDisabled; })
|
||||
.attr("data-bs-original-title", editDisabled ?
|
||||
I18n.t("javascripts.site.edit_disabled_tooltip") : "")
|
||||
// Disable the button group and also the buttons to avoid
|
||||
// inconsistent behaviour when zooming
|
||||
.toggleClass("disabled", editDisabled)
|
||||
.attr("data-original-title", editDisabled ?
|
||||
I18n.t("javascripts.site.edit_disabled_tooltip") : "");
|
||||
.find("a")
|
||||
.toggleClass("disabled", editDisabled);
|
||||
};
|
||||
|
||||
window.maximiseMap = function () {
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
$(document).ready(function () {
|
||||
var id = $("#id-embed");
|
||||
|
||||
if (id.data("key")) {
|
||||
var hashParams = OSM.params(location.hash.substring(1));
|
||||
if (id.data("configured") === true) {
|
||||
var hash = location.hash.substring(1);
|
||||
var hashParams = hash ? OSM.params(hash) : {};
|
||||
var mapParams = OSM.mapParams();
|
||||
var params = {};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ window.onload = function () {
|
|||
I18n.locale = navigator.language;
|
||||
}
|
||||
|
||||
var query = (window.location.search || '?').substr(1),
|
||||
var query = (window.location.search || '?').slice(1),
|
||||
args = {};
|
||||
|
||||
var pairs = query.split('&');
|
||||
|
|
|
@ -7,7 +7,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
|
||||
if (typeof iD === "undefined" || !iD.utilDetect().support) {
|
||||
container.innerHTML = "This editor is supported " +
|
||||
"in Firefox, Chrome, Safari, Opera, Edge, and Internet Explorer 11. " +
|
||||
"in Firefox, Chrome, Safari, Opera and Edge. " +
|
||||
"Please upgrade your browser or use JOSM to edit the map.";
|
||||
container.className = "unsupported";
|
||||
} else {
|
||||
|
@ -17,11 +17,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
.assetMap(JSON.parse(container.dataset.assetMap))
|
||||
.locale(container.dataset.locale)
|
||||
.preauth({
|
||||
urlroot: location.protocol + "//" + location.host,
|
||||
oauth_consumer_key: container.dataset.consumerKey,
|
||||
oauth_secret: container.dataset.consumerSecret,
|
||||
oauth_token: container.dataset.token,
|
||||
oauth_token_secret: container.dataset.tokenSecret
|
||||
url: location.protocol + "//" + location.host,
|
||||
access_token: container.dataset.token
|
||||
})
|
||||
.containerNode(container)
|
||||
.init();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//= require_self
|
||||
//= require leaflet.sidebar
|
||||
//= require leaflet.sidebar-pane
|
||||
//= require leaflet.locatecontrol/src/L.Control.Locate
|
||||
//= require leaflet.layers
|
||||
//= require leaflet.key
|
||||
|
@ -195,7 +196,7 @@ $(document).ready(function () {
|
|||
$(".welcome").addClass("visible");
|
||||
}
|
||||
|
||||
$(".welcome .close").on("click", function () {
|
||||
$(".welcome .btn-close").on("click", function () {
|
||||
$(".welcome").removeClass("visible");
|
||||
Cookies.set("_osm_welcome", "hide", { secure: true, expires: expiry, path: "/", samesite: "lax" });
|
||||
});
|
||||
|
@ -203,7 +204,7 @@ $(document).ready(function () {
|
|||
var bannerExpiry = new Date();
|
||||
bannerExpiry.setYear(bannerExpiry.getFullYear() + 1);
|
||||
|
||||
$("#banner .close-wrap").on("click", function (e) {
|
||||
$("#banner .btn-close").on("click", function (e) {
|
||||
var cookieId = e.target.id;
|
||||
$("#banner").hide();
|
||||
e.preventDefault();
|
||||
|
@ -212,13 +213,13 @@ $(document).ready(function () {
|
|||
}
|
||||
});
|
||||
|
||||
if (OSM.PIWIK) {
|
||||
if (OSM.MATOMO) {
|
||||
map.on("layeradd", function (e) {
|
||||
if (e.layer.options) {
|
||||
var goal = OSM.PIWIK.goals[e.layer.options.keyid];
|
||||
var goal = OSM.MATOMO.goals[e.layer.options.keyid];
|
||||
|
||||
if (goal) {
|
||||
$("body").trigger("piwikgoal", goal);
|
||||
$("body").trigger("matomogoal", goal);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
OSM.initializeBrowse = function (map) {
|
||||
var browseBounds;
|
||||
var selectedLayer;
|
||||
var dataLayer = map.dataLayer;
|
||||
|
||||
dataLayer.setStyle({
|
||||
|
@ -49,20 +48,20 @@ OSM.initializeBrowse = function (map) {
|
|||
|
||||
function displayFeatureWarning(count, limit, add, cancel) {
|
||||
$("#browse_status").html(
|
||||
$("<div>")
|
||||
.append(
|
||||
$("<h2>")
|
||||
.text(I18n.t("browse.start_rjs.load_data"))
|
||||
.prepend($("<span class='icon close'></span>").click(cancel)))
|
||||
.append(
|
||||
$("<div>")
|
||||
.append(
|
||||
$("<p class='alert alert-warning clearfix'></p>")
|
||||
.text(I18n.t("browse.start_rjs.feature_warning", { num_features: count, max_features: limit })))
|
||||
.append(
|
||||
$("<input type='submit' class='btn btn-primary'>")
|
||||
.val(I18n.t("browse.start_rjs.load_data"))
|
||||
.click(add))));
|
||||
$("<div>").append(
|
||||
$("<div class='d-flex'>").append(
|
||||
$("<div class='flex-grow-1 text-break'>").append(
|
||||
$("<h2>")
|
||||
.text(I18n.t("browse.start_rjs.load_data"))),
|
||||
$("<div>").append(
|
||||
$("<button type='button' class='btn-close mt-1'>")
|
||||
.click(cancel))),
|
||||
$("<div>").append(
|
||||
$("<p class='alert alert-warning'></p>")
|
||||
.text(I18n.t("browse.start_rjs.feature_warning", { num_features: count, max_features: limit })),
|
||||
$("<input type='submit' class='btn btn-primary'>")
|
||||
.val(I18n.t("browse.start_rjs.load_data"))
|
||||
.click(add))));
|
||||
}
|
||||
|
||||
var dataLoader;
|
||||
|
@ -92,7 +91,6 @@ OSM.initializeBrowse = function (map) {
|
|||
url: url,
|
||||
success: function (xml) {
|
||||
dataLayer.clearLayers();
|
||||
selectedLayer = null;
|
||||
|
||||
var features = dataLayer.buildFeatures(xml);
|
||||
|
||||
|
@ -112,24 +110,16 @@ OSM.initializeBrowse = function (map) {
|
|||
displayFeatureWarning(features.length, maxFeatures, addFeatures, cancelAddFeatures);
|
||||
}
|
||||
|
||||
if (map._objectLayer) {
|
||||
map._objectLayer.bringToFront();
|
||||
}
|
||||
|
||||
dataLoader = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onSelect(layer) {
|
||||
// Unselect previously selected feature
|
||||
if (selectedLayer) {
|
||||
selectedLayer.setStyle(selectedLayer.originalStyle);
|
||||
}
|
||||
|
||||
// Redraw in selected style
|
||||
layer.originalStyle = layer.options;
|
||||
layer.setStyle({ color: "#0000ff", weight: 8 });
|
||||
|
||||
OSM.router.route("/" + layer.feature.type + "/" + layer.feature.id);
|
||||
|
||||
// Stash the currently drawn feature
|
||||
selectedLayer = layer;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -157,7 +157,7 @@ OSM.Directions = function (map) {
|
|||
}));
|
||||
});
|
||||
|
||||
$(".directions_form .close").on("click", function (e) {
|
||||
$(".directions_form .btn-close").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
var route_from = endpoints[0].value;
|
||||
if (route_from) {
|
||||
|
@ -254,20 +254,30 @@ OSM.Directions = function (map) {
|
|||
map.fitBounds(polyline.getBounds().pad(0.05));
|
||||
}
|
||||
|
||||
var html = "<h2><a class=\"geolink\" href=\"#\">" +
|
||||
"<span class=\"icon close\"></span></a>" + I18n.t("javascripts.directions.directions") +
|
||||
"</h2><p>" +
|
||||
var distanceText = $("<p>").append(
|
||||
I18n.t("javascripts.directions.distance") + ": " + formatDistance(route.distance) + ". " +
|
||||
I18n.t("javascripts.directions.time") + ": " + formatTime(route.time) + ".";
|
||||
I18n.t("javascripts.directions.time") + ": " + formatTime(route.time) + ".");
|
||||
if (typeof route.ascend !== "undefined" && typeof route.descend !== "undefined") {
|
||||
html += "<br />" +
|
||||
distanceText.append(
|
||||
$("<br>"),
|
||||
I18n.t("javascripts.directions.ascend") + ": " + Math.round(route.ascend) + "m. " +
|
||||
I18n.t("javascripts.directions.descend") + ": " + Math.round(route.descend) + "m.";
|
||||
I18n.t("javascripts.directions.descend") + ": " + Math.round(route.descend) + "m.");
|
||||
}
|
||||
html += "</p><table id=\"turnbyturn\" class=\"mb-3\"/>";
|
||||
|
||||
var turnByTurnTable = $("<table class='mb-3'>");
|
||||
var directionsCloseButton = $("<button type='button' class='btn-close mt-1'>");
|
||||
|
||||
$("#sidebar_content")
|
||||
.html(html);
|
||||
.empty()
|
||||
.append(
|
||||
$("<div class='d-flex'>").append(
|
||||
$("<div class='flex-grow-1 text-break'>").append(
|
||||
$("<h2>")
|
||||
.text(I18n.t("javascripts.directions.directions"))),
|
||||
$("<div>").append(directionsCloseButton)),
|
||||
distanceText,
|
||||
turnByTurnTable
|
||||
);
|
||||
|
||||
// Add each row
|
||||
route.steps.forEach(function (step) {
|
||||
|
@ -309,15 +319,14 @@ OSM.Directions = function (map) {
|
|||
map.removeLayer(highlight);
|
||||
});
|
||||
|
||||
$("#turnbyturn").append(row);
|
||||
turnByTurnTable.append(row);
|
||||
});
|
||||
|
||||
$("#sidebar_content").append("<p class=\"text-center\">" +
|
||||
I18n.t("javascripts.directions.instructions.courtesy", { link: chosenEngine.creditline }) +
|
||||
"</p>");
|
||||
|
||||
$("#sidebar_content a.geolink").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
directionsCloseButton.on("click", function () {
|
||||
map.removeLayer(polyline);
|
||||
$("#sidebar_content").html("");
|
||||
map.setSidebarOverlaid(true);
|
||||
|
|
|
@ -14,7 +14,7 @@ function GraphHopperEngine(id, vehicleType) {
|
|||
|
||||
return {
|
||||
id: id,
|
||||
creditline: "<a href=\"https://www.graphhopper.com/\" target=\"_blank\">Graphhopper</a>",
|
||||
creditline: "<a href=\"https://www.graphhopper.com/\" target=\"_blank\">GraphHopper</a>",
|
||||
draggable: false,
|
||||
|
||||
getRoute: function (points, callback) {
|
||||
|
|
|
@ -10,18 +10,6 @@ OSM.History = function (map) {
|
|||
})
|
||||
.on("mouseout", "[data-changeset]", function () {
|
||||
unHighlightChangeset($(this).data("changeset").id);
|
||||
})
|
||||
.on("mousedown", "[data-changeset]", function () {
|
||||
var moved = false;
|
||||
$(this)
|
||||
.one("click", function (e) {
|
||||
if (!moved && !$(e.target).is("a")) {
|
||||
clickChangeset($(this).data("changeset").id, e);
|
||||
}
|
||||
})
|
||||
.one("mousemove", function () {
|
||||
moved = true;
|
||||
});
|
||||
});
|
||||
|
||||
var group = L.featureGroup()
|
||||
|
|
|
@ -85,10 +85,12 @@ OSM.NewNote = function (map) {
|
|||
};
|
||||
|
||||
function newHalo(loc, a) {
|
||||
if (a === "dragstart" && map.hasLayer(halo)) {
|
||||
var hasHalo = halo && map.hasLayer(halo);
|
||||
|
||||
if (a === "dragstart" && hasHalo) {
|
||||
map.removeLayer(halo);
|
||||
} else {
|
||||
if (map.hasLayer(halo)) map.removeLayer(halo);
|
||||
if (hasHalo) map.removeLayer(halo);
|
||||
|
||||
halo = L.circleMarker(loc, {
|
||||
weight: 2.5,
|
||||
|
@ -160,8 +162,8 @@ OSM.NewNote = function (map) {
|
|||
};
|
||||
|
||||
page.unload = function () {
|
||||
noteLayer.removeLayer(newNote);
|
||||
map.removeLayer(halo);
|
||||
if (newNote) noteLayer.removeLayer(newNote);
|
||||
if (halo) map.removeLayer(halo);
|
||||
addNoteButton.removeClass("active");
|
||||
};
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ OSM.Note = function (map) {
|
|||
var data = $(".details").data(),
|
||||
latLng = L.latLng(data.coordinates.split(","));
|
||||
|
||||
if (!map.hasLayer(halo)) {
|
||||
if (!halo || !map.hasLayer(halo)) {
|
||||
halo = L.circleMarker(latLng, {
|
||||
weight: 2.5,
|
||||
radius: 20,
|
||||
|
@ -83,7 +83,8 @@ OSM.Note = function (map) {
|
|||
map.addLayer(halo);
|
||||
}
|
||||
|
||||
if (map.hasLayer(currentNote)) map.removeLayer(currentNote);
|
||||
if (currentNote && map.hasLayer(currentNote)) map.removeLayer(currentNote);
|
||||
|
||||
currentNote = L.marker(latLng, {
|
||||
icon: noteIcons[data.status],
|
||||
opacity: 1,
|
||||
|
|
|
@ -103,8 +103,8 @@ OSM.Query = function (map) {
|
|||
value = tags[key];
|
||||
|
||||
if (prefixes[key]) {
|
||||
var first = value.substr(0, 1).toUpperCase(),
|
||||
rest = value.substr(1).replace(/_/g, " ");
|
||||
var first = value.slice(0, 1).toUpperCase(),
|
||||
rest = value.slice(1).replace(/_/g, " ");
|
||||
|
||||
return first + rest;
|
||||
}
|
||||
|
|
|
@ -1,38 +1,11 @@
|
|||
L.OSM.key = function (options) {
|
||||
var control = L.control(options);
|
||||
|
||||
control.onAdd = function (map) {
|
||||
var $container = $("<div>")
|
||||
.attr("class", "control-key");
|
||||
|
||||
var button = $("<a>")
|
||||
.attr("class", "control-button")
|
||||
.attr("href", "#")
|
||||
.html("<span class=\"icon key\"></span>")
|
||||
.on("click", toggle)
|
||||
.appendTo($container);
|
||||
|
||||
var $ui = $("<div>")
|
||||
.attr("class", "key-ui");
|
||||
|
||||
$("<div>")
|
||||
.attr("class", "sidebar_heading")
|
||||
.appendTo($ui)
|
||||
.append(
|
||||
$("<span>")
|
||||
.text(I18n.t("javascripts.close"))
|
||||
.attr("class", "icon close")
|
||||
.bind("click", toggle))
|
||||
.append(
|
||||
$("<h4>")
|
||||
.text(I18n.t("javascripts.key.title")));
|
||||
var control = L.OSM.sidebarPane(options, "key", null, "javascripts.key.title");
|
||||
|
||||
control.onAddPane = function (map, button, $ui) {
|
||||
var $section = $("<div>")
|
||||
.attr("class", "section")
|
||||
.appendTo($ui);
|
||||
|
||||
options.sidebar.addPane($ui);
|
||||
|
||||
$ui
|
||||
.on("show", shown)
|
||||
.on("hide", hidden);
|
||||
|
@ -50,20 +23,11 @@ L.OSM.key = function (options) {
|
|||
map.off("zoomend baselayerchange", update);
|
||||
}
|
||||
|
||||
function toggle(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (!button.hasClass("disabled")) {
|
||||
options.sidebar.togglePane($ui, button);
|
||||
}
|
||||
$(".leaflet-control .control-button").tooltip("hide");
|
||||
}
|
||||
|
||||
function updateButton() {
|
||||
var disabled = ["mapnik", "cyclemap"].indexOf(map.getMapBaseLayerId()) === -1;
|
||||
button
|
||||
.toggleClass("disabled", disabled)
|
||||
.attr("data-original-title",
|
||||
.attr("data-bs-original-title",
|
||||
I18n.t(disabled ?
|
||||
"javascripts.key.tooltip_disabled" :
|
||||
"javascripts.key.tooltip"));
|
||||
|
@ -82,8 +46,6 @@ L.OSM.key = function (options) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $container[0];
|
||||
};
|
||||
|
||||
return control;
|
||||
|
|
|
@ -1,35 +1,9 @@
|
|||
L.OSM.layers = function (options) {
|
||||
var control = L.control(options);
|
||||
var control = L.OSM.sidebarPane(options, "layers", "javascripts.map.layers.title", "javascripts.map.layers.header");
|
||||
|
||||
control.onAdd = function (map) {
|
||||
control.onAddPane = function (map, button, $ui, toggle) {
|
||||
var layers = options.layers;
|
||||
|
||||
var $container = $("<div>")
|
||||
.attr("class", "control-layers");
|
||||
|
||||
var button = $("<a>")
|
||||
.attr("class", "control-button")
|
||||
.attr("href", "#")
|
||||
.attr("title", I18n.t("javascripts.map.layers.title"))
|
||||
.html("<span class=\"icon layers\"></span>")
|
||||
.on("click", toggle)
|
||||
.appendTo($container);
|
||||
|
||||
var $ui = $("<div>")
|
||||
.attr("class", "layers-ui");
|
||||
|
||||
$("<div>")
|
||||
.attr("class", "sidebar_heading")
|
||||
.appendTo($ui)
|
||||
.append(
|
||||
$("<span>")
|
||||
.text(I18n.t("javascripts.close"))
|
||||
.attr("class", "icon close")
|
||||
.bind("click", toggle))
|
||||
.append(
|
||||
$("<h4>")
|
||||
.text(I18n.t("javascripts.map.layers.header")));
|
||||
|
||||
var baseSection = $("<div>")
|
||||
.attr("class", "section base-layers")
|
||||
.appendTo($ui);
|
||||
|
@ -171,7 +145,7 @@ L.OSM.layers = function (options) {
|
|||
}
|
||||
|
||||
$(item).attr("class", disabled ? "disabled" : "");
|
||||
item.attr("data-original-title", disabled ?
|
||||
item.attr("data-bs-original-title", disabled ?
|
||||
I18n.t("javascripts.site.map_" + name + "_zoom_in_tooltip") : "");
|
||||
});
|
||||
};
|
||||
|
@ -180,17 +154,6 @@ L.OSM.layers = function (options) {
|
|||
addOverlay(map.dataLayer, "data", OSM.MAX_REQUEST_AREA);
|
||||
addOverlay(map.gpsLayer, "gps", Number.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
options.sidebar.addPane($ui);
|
||||
|
||||
function toggle(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
options.sidebar.togglePane($ui, button);
|
||||
$(".leaflet-control .control-button").tooltip("hide");
|
||||
}
|
||||
|
||||
return $container[0];
|
||||
};
|
||||
|
||||
return control;
|
||||
|
|
|
@ -17,7 +17,7 @@ L.OSM.note = function (options) {
|
|||
var disabled = OSM.STATUS === "database_offline" || map.getZoom() < 12;
|
||||
link
|
||||
.toggleClass("disabled", disabled)
|
||||
.attr("data-original-title", I18n.t(disabled ?
|
||||
.attr("data-bs-original-title", I18n.t(disabled ?
|
||||
"javascripts.site.createnote_disabled_tooltip" :
|
||||
"javascripts.site.createnote_tooltip"));
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ L.OSM.query = function (options) {
|
|||
isDisabled = map.getZoom() < 14;
|
||||
link
|
||||
.toggleClass("disabled", isDisabled)
|
||||
.attr("data-original-title", I18n.t(isDisabled ?
|
||||
.attr("data-bs-original-title", I18n.t(isDisabled ?
|
||||
"javascripts.site.queryfeature_disabled_tooltip" :
|
||||
"javascripts.site.queryfeature_tooltip"));
|
||||
|
||||
|
|
|
@ -1,38 +1,12 @@
|
|||
L.OSM.share = function (options) {
|
||||
var control = L.control(options),
|
||||
var control = L.OSM.sidebarPane(options, "share", "javascripts.share.title", "javascripts.share.title"),
|
||||
marker = L.marker([0, 0], { draggable: true }),
|
||||
locationFilter = new L.LocationFilter({
|
||||
enableButton: false,
|
||||
adjustButton: false
|
||||
});
|
||||
|
||||
control.onAdd = function (map) {
|
||||
var $container = $("<div>")
|
||||
.attr("class", "control-share");
|
||||
|
||||
var button = $("<a>")
|
||||
.attr("class", "control-button")
|
||||
.attr("href", "#")
|
||||
.attr("title", I18n.t("javascripts.share.title"))
|
||||
.html("<span class=\"icon share\"></span>")
|
||||
.on("click", toggle)
|
||||
.appendTo($container);
|
||||
|
||||
var $ui = $("<div>")
|
||||
.attr("class", "share-ui");
|
||||
|
||||
$("<div>")
|
||||
.attr("class", "sidebar_heading")
|
||||
.appendTo($ui)
|
||||
.append(
|
||||
$("<span>")
|
||||
.text(I18n.t("javascripts.close"))
|
||||
.attr("class", "icon close")
|
||||
.bind("click", toggle))
|
||||
.append(
|
||||
$("<h4>")
|
||||
.text(I18n.t("javascripts.share.title")));
|
||||
|
||||
control.onAddPane = function (map, button, $ui) {
|
||||
// Link / Embed
|
||||
|
||||
var $linkSection = $("<div>")
|
||||
|
@ -47,7 +21,7 @@ L.OSM.share = function (options) {
|
|||
.appendTo($linkSection);
|
||||
|
||||
$("<div>")
|
||||
.attr("class", "form-check form-group")
|
||||
.attr("class", "form-check mb-3")
|
||||
.appendTo($form)
|
||||
.append(
|
||||
$("<label>")
|
||||
|
@ -159,7 +133,7 @@ L.OSM.share = function (options) {
|
|||
.appendTo($imageSection);
|
||||
|
||||
$("<div>")
|
||||
.attr("class", "form-group form-check")
|
||||
.attr("class", "mb-3 form-check")
|
||||
.appendTo($form)
|
||||
.append(
|
||||
$("<label>")
|
||||
|
@ -246,11 +220,15 @@ L.OSM.share = function (options) {
|
|||
map.on("move", movedMap);
|
||||
map.on("moveend layeradd layerremove", update);
|
||||
|
||||
options.sidebar.addPane($ui);
|
||||
|
||||
$ui
|
||||
.on("show", shown)
|
||||
.on("hide", hidden);
|
||||
|
||||
function shown() {
|
||||
$("#mapnik_scale").val(getScale());
|
||||
update();
|
||||
}
|
||||
|
||||
function hidden() {
|
||||
map.removeLayer(marker);
|
||||
map.options.scrollWheelZoom = map.options.doubleClickZoom = true;
|
||||
|
@ -258,18 +236,6 @@ L.OSM.share = function (options) {
|
|||
update();
|
||||
}
|
||||
|
||||
function toggle(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
$("#mapnik_scale").val(getScale());
|
||||
marker.setLatLng(map.getCenter());
|
||||
|
||||
update();
|
||||
options.sidebar.togglePane($ui, button);
|
||||
$(".leaflet-control .control-button").tooltip("hide");
|
||||
}
|
||||
|
||||
function toggleMarker() {
|
||||
if ($(this).is(":checked")) {
|
||||
marker.setLatLng(map.getCenter());
|
||||
|
@ -414,8 +380,6 @@ L.OSM.share = function (options) {
|
|||
var precision = 5 * Math.pow(10, Math.floor(Math.LOG10E * Math.log(scale)) - 2);
|
||||
return precision * Math.ceil(scale / precision);
|
||||
}
|
||||
|
||||
return $container[0];
|
||||
};
|
||||
|
||||
return control;
|
||||
|
|
53
app/assets/javascripts/leaflet.sidebar-pane.js
Normal file
53
app/assets/javascripts/leaflet.sidebar-pane.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
L.OSM.sidebarPane = function (options, uiClass, buttonTitle, paneTitle) {
|
||||
var control = L.control(options);
|
||||
|
||||
control.onAdd = function (map) {
|
||||
var $container = $("<div>")
|
||||
.attr("class", "control-" + uiClass);
|
||||
|
||||
var button = $("<a>")
|
||||
.attr("class", "control-button")
|
||||
.attr("href", "#")
|
||||
.html("<span class=\"icon " + uiClass + "\"></span>")
|
||||
.on("click", toggle);
|
||||
|
||||
if (buttonTitle) {
|
||||
button.attr("title", I18n.t(buttonTitle));
|
||||
}
|
||||
|
||||
button.appendTo($container);
|
||||
|
||||
var $ui = $("<div>")
|
||||
.attr("class", uiClass + "-ui");
|
||||
|
||||
$("<div class='sidebar_heading d-flex'>")
|
||||
.appendTo($ui)
|
||||
.append($("<div class='flex-grow-1 text-break'>")
|
||||
.append($("<h4>")
|
||||
.text(I18n.t(paneTitle))))
|
||||
.append($("<div>")
|
||||
.append($("<button type='button' class='btn-close mt-1'>")
|
||||
.attr("aria-label", I18n.t("javascripts.close"))
|
||||
.bind("click", toggle)));
|
||||
|
||||
options.sidebar.addPane($ui);
|
||||
|
||||
this.onAddPane(map, button, $ui, toggle);
|
||||
|
||||
function toggle(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (!button.hasClass("disabled")) {
|
||||
options.sidebar.togglePane($ui, button);
|
||||
}
|
||||
$(".leaflet-control .control-button").tooltip("hide");
|
||||
}
|
||||
|
||||
return $container[0];
|
||||
};
|
||||
|
||||
// control.onAddPane = function (map, button, $ui, toggle) {
|
||||
// }
|
||||
|
||||
return control;
|
||||
};
|
32
app/assets/javascripts/matomo.js
Normal file
32
app/assets/javascripts/matomo.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
if (OSM.MATOMO) {
|
||||
$(document).ready(function () {
|
||||
var base = document.location.protocol + "//" + OSM.MATOMO.location + "/";
|
||||
var matomoTracker;
|
||||
|
||||
var matomoLoader = $.ajax({
|
||||
url: base + "matomo.js",
|
||||
dataType: "script",
|
||||
cache: true,
|
||||
success: function () {
|
||||
matomoTracker = Matomo.getTracker(base + "matomo.php", OSM.MATOMO.site);
|
||||
|
||||
if (OSM.user) {
|
||||
matomoTracker.setUserId(OSM.user.toString());
|
||||
}
|
||||
|
||||
matomoTracker.trackPageView();
|
||||
matomoTracker.enableLinkTracking();
|
||||
|
||||
$("meta[name=matomo-goal]").each(function () {
|
||||
matomoTracker.trackGoal($(this).attr("content"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("body").on("matomogoal", function (e, goal) {
|
||||
matomoLoader.done(function () {
|
||||
matomoTracker.trackGoal(goal);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
//= require qs/dist/qs
|
||||
|
||||
OSM = {
|
||||
<% if defined?(PIWIK) %>
|
||||
PIWIK: <%= PIWIK.to_json %>,
|
||||
<% if defined?(Settings.matomo) %>
|
||||
MATOMO: <%= Settings.matomo.to_json %>,
|
||||
<% end %>
|
||||
|
||||
MAX_REQUEST_AREA: <%= Settings.max_request_area.to_json %>,
|
||||
|
@ -146,7 +146,7 @@ OSM = {
|
|||
return args;
|
||||
}
|
||||
|
||||
hash = Qs.parse(hash.substr(i + 1));
|
||||
hash = Qs.parse(hash.slice(i + 1));
|
||||
|
||||
var map = (hash.map || '').split('/'),
|
||||
zoom = parseInt(map[0], 10),
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
if (OSM.PIWIK) {
|
||||
$(document).ready(function () {
|
||||
var base = document.location.protocol + "//" + OSM.PIWIK.location + "/";
|
||||
var piwikTracker;
|
||||
|
||||
var piwikLoader = $.ajax({
|
||||
url: base + "piwik.js",
|
||||
dataType: "script",
|
||||
cache: true,
|
||||
success: function () {
|
||||
piwikTracker = Piwik.getTracker(base + "piwik.php", OSM.PIWIK.site);
|
||||
|
||||
if (OSM.user) {
|
||||
piwikTracker.setUserId(OSM.user.toString());
|
||||
}
|
||||
|
||||
piwikTracker.trackPageView();
|
||||
piwikTracker.enableLinkTracking();
|
||||
|
||||
$("meta[name=piwik-goal]").each(function () {
|
||||
piwikTracker.trackGoal($(this).attr("content"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("body").on("piwikgoal", function (e, goal) {
|
||||
piwikLoader.done(function () {
|
||||
piwikTracker.trackGoal(goal);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -3,15 +3,14 @@
|
|||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>OpenStreetMap</ShortName>
|
||||
<LongName>OpenStreetMap Search</LongName>
|
||||
<Description>Search for a place in OpenStreetMap, the Wiki World Map</Description>
|
||||
<Description>Search for a place in OpenStreetMap</Description>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<OutputEncoding>UTF-8</OutputEncoding>
|
||||
<Image width="16" height="16">data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%08%06%00%00%00%1F%F3%FFa%00%00%00%19tEXtSoftware%00www.inkscape.org%9B%EE%3C%1A%00%00%01'IDATx%9C%9D%93%B1q%C30%0CE%1F%5Dd%80l%90I%C4*%A7%22%95%CF%85J%97%AE%B2%82%3DC%CE%03%A0%B3%9B%B8f%95%A3%17H%93%05%5C%A7%C8%0A%3F%05E%8A%92l%E7.%D0%E9N%02%81%07%E0Cr%FCaf%A6%FC%BC%5E%AF%DD%F4%3C%3Bt%C5%87%99)%84P%0E%DA%B6%BD%0AI%00%A1%A8%A8%1E%263S%D7u%C9'F%FE%9B%80%0C%C9%C9%22%BD'%B0%0A%AC%86%2CJ%DB%0E%22%11%8F%2F%D4%B3%22%8D%F34%CE%13u%06R%0C%40%D7u%AA%01%C5r%40%0Dq%88%C6%F9i%E8%7C%8CX%5D%A9M%95%D6%A3%A2Ti%C3Xx%CA%9C%F5mf3h%11%B6%07%B8%0APh%97%DD%1E%9E%5E%08!%D0%B6m%F1%87%108%1E%8EY5%007%03%5Cv%7B%00%3E%BF%3E%F8~x%1E%CD%B89l%00%F0I%0FWw%00%20%DB%AEJr%B6%E5%FB%09%80%C6y%CE%7D%91%1AP%B6p%2B%D9%BB%06%18V%3A%B5E%9F%AC%5B%95%AFY%3F%EE%20%A2mW%AA%93%DFN%3F%A0%E1%9B%F0u%E5%BC%BC%89%88%BC.%1F%D5'%DF%FD%C1%EE%F8%FFg%BFp%96%DF%E2%DCw%25%2B%00%00%00%00IEND%AEB%60%82</Image>
|
||||
<Image width="32" height="32">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAHXRFWHRUaXRsZQBPcGVuU3RyZWV0TWFwIGxvZ28gMjAxMbBaqq0AAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAACXBIWXMAAAIJAAACCQGIszliAAADAFBMVEVHcEzJ66zM7KnL5Kap3Y3U7LfR7rLd9KrS8K+99bLG6J/P7a3Z8r7O7KrC6aSswcPT77PW78HH46jJ6KfO7K7X8Lqy4ZXK7KrN66vY87vN7Kuu3ZEkMTHC35/W7byswcGzz67O7azA5aHP67mt35G245na88DB5KC41cXN2KLC4KwvLzbA0M7G5b2brJPT5eKarap6iooxPT3D3K6kurlcUz4tLSPwxTSElXs3NSL14qHL06ra8sFpaVaFl4VUXF6UpqWvxLnE2pvb88LN7avE56S546Da88HM6onM6MrM7KrL6qik24m337na8r/V8LfT8LTU5PLZ7trW8bnJ56fQ77Di8uSg1oXQ7LHO6czU7bjI4dPF46LA2Oze8eDS69PP7K3n8+rH5aTJzJzC56LA56vY8bzj8+bQ6s++1era7d7G4sc4Nzq95qjI6KS24KG846fc6fTX5vLG2+jS77LR4vHU5tei2IjV6d8xMTPW2K7N6qzN5M/R5NW60ueIn4Kox4+31b/T0qs8Oz+nvb1AP0JIRUnC5MPM3qXd7eGuz7PK5cqSv4DIxZnQ7bU7PTG60aK/1+W7456915y+2aPK4qvB3aefuo1TWVCSqZus3JFbY1ZygWfQ6r1BQ0fG487N6dHK3u7X7dfK16Gf04O24Jjo7ua13LjB2tGy0rssLC4xMC/OxqCbzoI1NTWtxrzi8OXF56660Mm0yMPB3p6x3pq+1uCFmHfL577I2dV3h2vM56jAvZS/3ce92L3I4M680t3M0J7U5+zN4O/Z27Owy7DB4r4mJymQoJOtzpSjtaHS4rC30cnW5bSxxqCmv43J6LKcs4aXrIjD3cOZtoe1z5qtwrLB4bRIUklob16Qp3y2zNhvbk13hoXb88JPV12it9BXYmrG393i8OuswpqUyoCx2LWeuYe1uo+TxHyXln6vqIbP5dvQ5dyt0ZrZ8MaZw5mcsZet1q/CzbqkrIeyrK2dsbRCRTeyxtJ6iZGnk1dhbHF+dmKBkJ+ppJCUo7fdGvRRAAAASHRSTlMAi9Bd/klPCBAEJb2KHzftZ6ky+aTOt3OfPvPeCtz2/f2XZ+vqk+V7z3DzJvVs4PbJsD9I4uPTtR2HrvHA88Z91PqX+Kn06tFpmiUEAAADw0lEQVQ4y2NQdGEU4GKAAA5GN2kxJXYIh5NV0B1EC3h5eXkzabJzsPHYOOcWlIezuCryMfAKCCqn3bsnCdIlBVJxUCrNzy/tQkHBrFneMRc/Om6+NnN6QZQfD8gIEaB8R4e3f3BfQX5uwdZJl9a/3bBhQ1bFzpaPfqIgBWxe3t7J3iEJ/sEb8wvyt9ZHV9TWlpXV1tRGnzkhB3IPh7e398HkxTEJEREbgfJvOsuyshYF1dbU7G88c4IVZASTt3dITPLihJKAgKlA/Z1ZYUGL4uMzamq6Vp6xAzsioTokJqQ3yduretr6srJFQVlxcWFxcfHd+7oa5WWACtT8/IL9oqoivJO2bN9bFhcWlJ6eGJYVtsB3edfRTfYMDJJ+aWlRaVFHEmJmLZkZnZWeFfa4qLDoUEW7L1BFowMDA08aUIG//5GQpT5rW4oDiwIDA0uBeOE2oIpnK/kZGESDg4MjIoKbtrD4fJCfCJQrBKKihbF184FGABWwB/j7+0dEVE318fmk0LKt9PChQ4dLD8fGxtZl+/r6NvIzsAYAQXXT6SSfWRunfKtbeDgoqKI4MzY2E2SF714TBuYQ79DQ0DXVeSnXU/J/TswsXhSfsWBiJtCG7mPt8VmGDBzCIUkhCR3JeQk7JjX+/ZE50dPTMzLyUXG0p2dGXLq+EQMDNygg1yRVB8/N3/d/3u26bk9PsJqMRWGJiQbAcBIHRnfvbu/d/vtT9z64/7AuGqzAMz4obNkyHW2gAiFgdG9J9oqZe2D/gQcP235viwQrCFq2LH2FHjhpCefleXUkT8suiZh6t611xv2WBUAl8enLsjafUuAEqZCNyYvZkvy5ac/Nf39ab8yZc7dl04ro6J2bZ7ZcfSIEUsDtHZN0fe/iybPntf26s+vW9lsN51/VX3p+8uq5a1NA6YFdbm53dp8XSH5e852Z0642TL8y/XVDT0/PyaNaoBTF9j6yL7hkyuzWttac7/Vfm5qipk6b8KKh5+XTtZM0QDYIRqbmRk2Z3dzauq5/zpd9t/2bqvpOr5m8NhwI1EEKlFNTL0yY0dzcXNl/80pv9YHLAWerzkYtLV8SXu7DB/JlburcCTNymnMq++dc3BNzuSR7f4B/cEr5Eh8fHxZwqi8oODdjXc66Vf27nu/pPQaMuB0r/P0nAbX7+KiAFDDmvrtRua4SKH9+8m5rCaYEoIrsgJRwoLyPGEgBn7iTbeXq46u3N8hKMAN9xSvOHZodGrOURVoVlqc5rUyPm1kYw7jArKTLyMzLgATYzS1lGHABANfVkEkFerrFAAAAAElFTkSuQmCC</Image>
|
||||
<Url type="text/html" method="get" template="https://www.openstreetmap.org/search">
|
||||
<Param name="query" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<Query role="example" searchTerms="Reigate" />
|
||||
<Developer>Jonathan Bennett</Developer>
|
||||
<AdultContent>false</AdultContent>
|
||||
<Attribution>Data &copy; OpenStreetMap contributors, Some Rights Reserved. CC by-sa 2.0. Geolocation provided by npemap.org.uk, geocoder.us, geocoder.ca and geonames.org.</Attribution>
|
||||
<Attribution>&copy; OpenStreetMap contributors. ODbL 1.0. Geocoding provided by nominatim.openstreetmap.org.</Attribution>
|
||||
</OpenSearchDescription>
|
||||
|
|
|
@ -55,24 +55,12 @@ small, aside {
|
|||
.icon.clipboard { /* no-r2 */ background-position: -160px 0; }
|
||||
.icon.link { /* no-r2 */ background-position: -180px 0; }
|
||||
.icon.close { /* no-r2 */ background-position: -200px 0; }
|
||||
.close-wrap:hover .icon.close,
|
||||
.icon.close:hover { /* no-r2 */ background-position: -200px -20px; }
|
||||
.icon.check { /* no-r2 */ background-position: -220px 0; }
|
||||
.icon.note { /* no-r2 */ background-position: -240px 0; }
|
||||
.icon.note.grey { /* no-r2 */ background-position: -240px -20px; }
|
||||
.icon.query { /* no-r2 */ background-position: -260px 0; }
|
||||
|
||||
/* Rules for links */
|
||||
|
||||
a {
|
||||
color: #24d;
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
/* Utility for de-emphasizing content */
|
||||
|
||||
.text-muted a {
|
||||
|
@ -157,7 +145,7 @@ header {
|
|||
|
||||
nav.primary {
|
||||
.btn-outline-primary {
|
||||
@include button-outline-variant($green, $white);
|
||||
@include button-outline-variant($green, $color-hover: $white, $active-color: $white);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
|
@ -202,27 +190,17 @@ nav.secondary {
|
|||
|
||||
.login-menu {
|
||||
.btn-outline-secondary {
|
||||
@include button-outline-variant($darkgrey);
|
||||
@include button-outline-variant($darkgrey, $color-hover: $white, $active-color: $white);
|
||||
}
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
.btn-outline-secondary {
|
||||
@include button-outline-variant($darkgrey, $darkgrey, white, $darkgrey);
|
||||
@include button-outline-variant($darkgrey, $color-hover: $darkgrey, $active-background: white, $active-border: $darkgrey);
|
||||
border-color: $grey;
|
||||
&:hover {
|
||||
border-color: $grey;
|
||||
}
|
||||
&:focus {
|
||||
background-color: white;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
&.show .btn-outline-secondary {
|
||||
background-color: white;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +273,8 @@ body.compact-nav {
|
|||
margin-bottom: 10px;
|
||||
outline: none;
|
||||
|
||||
&:hover {
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
|
@ -369,30 +348,6 @@ body.compact-nav {
|
|||
clear: both;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
h3, h4 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.close-wrap {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
|
||||
.icon.close {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-sidebar #sidebar {
|
||||
|
@ -644,11 +599,6 @@ body.compact-nav {
|
|||
padding: $lineheight/2 $lineheight;
|
||||
// background: $offwhite;
|
||||
// border-bottom: 1px solid $grey;
|
||||
> .close {
|
||||
float: right;
|
||||
margin-top: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#browse_status {
|
||||
|
@ -686,6 +636,28 @@ form {
|
|||
}
|
||||
}
|
||||
|
||||
/* Stop bootstrap 5 from floating legends when they don't need to be */
|
||||
legend {
|
||||
float: none;
|
||||
}
|
||||
|
||||
/* Override the text colour for primary and secondary buttons, to match our
|
||||
bootstrap 4 colours. Note this has accessibility issues, which is why
|
||||
bootstrap 5 calculates black as the appropriate colour, and we should
|
||||
reconsider our colours at some point with that in mind. */
|
||||
|
||||
.btn-primary {
|
||||
@include button-variant($primary, $primary, $color: $white, $hover-color: $white, $active-color: $white, $disabled-color: $white);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@include button-variant($secondary, $secondary, $color: $white, $hover-color: $white, $active-color: $white, $disabled-color: $white);
|
||||
}
|
||||
|
||||
.btn-outline-secondary {
|
||||
@include button-outline-variant($secondary, $color-hover: $white, $active-color: $white);
|
||||
}
|
||||
|
||||
/* Rules for the search and direction forms */
|
||||
|
||||
header .search_forms,
|
||||
|
@ -770,10 +742,13 @@ tr.turn:hover {
|
|||
|
||||
#sidebar .changesets {
|
||||
li {
|
||||
cursor: pointer;
|
||||
|
||||
&.selected { background: $list-highlight; }
|
||||
/* color is derived from changeset bbox fillColor in history.js */
|
||||
|
||||
a.stretched-link > span, a:not(.stretched-link), [title] {
|
||||
position: relative;
|
||||
z-index: 2; /* needs to be higher than Bootstrap's stretched link ::after z-index */
|
||||
}
|
||||
}
|
||||
|
||||
.comments {
|
||||
|
@ -1182,8 +1157,9 @@ tr.turn:hover {
|
|||
/* Rules for messages pages */
|
||||
|
||||
.messages {
|
||||
input[type="submit"] {
|
||||
button[type="submit"] {
|
||||
margin: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.inbox-row {
|
||||
|
@ -1306,10 +1282,6 @@ tr.turn:hover {
|
|||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
a.reverse_directions {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
/* Rules for user images */
|
||||
|
@ -1435,13 +1407,6 @@ dl.dl-inline {
|
|||
}
|
||||
}
|
||||
|
||||
/* Customise the background colour of striped tables */
|
||||
|
||||
.table-striped > tbody > tr:nth-child(2n+1) > td,
|
||||
.table-striped > tbody > tr:nth-child(2n+1) > th {
|
||||
background-color: $offwhite;
|
||||
}
|
||||
|
||||
/* Rules for OpenID logo */
|
||||
|
||||
.openid_logo {
|
||||
|
@ -1454,13 +1419,11 @@ dl.dl-inline {
|
|||
.richtext,
|
||||
.prose {
|
||||
code {
|
||||
font-size: 13px;
|
||||
background: $lightgrey;
|
||||
padding: 2px 3px;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 13px;
|
||||
background: $lightgrey;
|
||||
padding: 2px 3px;
|
||||
white-space: pre-wrap;
|
||||
|
@ -1503,19 +1466,10 @@ dl.dl-inline {
|
|||
|
||||
/* Rules for the "Welcome" page */
|
||||
.site-welcome, .site-fixthemap {
|
||||
.center {
|
||||
text-align: center;
|
||||
.sprite {
|
||||
float: none;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.sprite {
|
||||
background-image: image-url("welcome-sprite.png");
|
||||
background-size: 500px 250px;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.icon-list {
|
||||
|
@ -1565,15 +1519,6 @@ dl.dl-inline {
|
|||
/* no-r2 */ background-position: -350px 0;
|
||||
}
|
||||
|
||||
.start-mapping {
|
||||
margin: auto;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
padding: 20px 40px;
|
||||
font-size: 30px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.icon.note {
|
||||
background-color: #333;
|
||||
border-radius: 4px;
|
||||
|
|
|
@ -17,3 +17,12 @@ $sidebarWidth: 350px;
|
|||
$keyline: 1px solid $lightgrey;
|
||||
$list-highlight: #FFFFC0;
|
||||
$border: 1px solid $grey;
|
||||
|
||||
$link-color: #24d;
|
||||
$link-hover-color: #24d;
|
||||
$link-decoration: none;
|
||||
$link-hover-decoration: underline;
|
||||
|
||||
$table-striped-bg: $offwhite;
|
||||
|
||||
$enable-negative-margins: true;
|
||||
|
|
12
app/controllers/account/deletions_controller.rb
Normal file
12
app/controllers/account/deletions_controller.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
module Account
|
||||
class DeletionsController < ApplicationController
|
||||
layout "site"
|
||||
|
||||
before_action :authorize_web
|
||||
before_action :set_locale
|
||||
|
||||
authorize_resource :class => false
|
||||
|
||||
def show; end
|
||||
end
|
||||
end
|
64
app/controllers/accounts_controller.rb
Normal file
64
app/controllers/accounts_controller.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
class AccountsController < ApplicationController
|
||||
include SessionMethods
|
||||
include UserMethods
|
||||
|
||||
layout "site"
|
||||
|
||||
before_action :authorize_web
|
||||
before_action :set_locale
|
||||
|
||||
authorize_resource :class => false
|
||||
|
||||
before_action :check_database_readable
|
||||
before_action :check_database_writable, :only => [:update]
|
||||
before_action :allow_thirdparty_images, :only => [:edit, :update]
|
||||
|
||||
def edit
|
||||
@tokens = current_user.oauth_tokens.authorized
|
||||
|
||||
append_content_security_policy_directives(
|
||||
:form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org]
|
||||
)
|
||||
|
||||
if errors = session.delete(:user_errors)
|
||||
errors.each do |attribute, error|
|
||||
current_user.errors.add(attribute, error)
|
||||
end
|
||||
end
|
||||
@title = t ".title"
|
||||
end
|
||||
|
||||
def update
|
||||
@tokens = current_user.oauth_tokens.authorized
|
||||
|
||||
append_content_security_policy_directives(
|
||||
:form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org]
|
||||
)
|
||||
|
||||
user_params = params.require(:user).permit(:display_name, :new_email, :pass_crypt, :pass_crypt_confirmation, :auth_provider)
|
||||
|
||||
if params[:user][:auth_provider].blank? ||
|
||||
(params[:user][:auth_provider] == current_user.auth_provider &&
|
||||
params[:user][:auth_uid] == current_user.auth_uid)
|
||||
update_user(current_user, user_params)
|
||||
if current_user.errors.count.zero?
|
||||
redirect_to edit_account_path
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
else
|
||||
session[:new_user_settings] = user_params.to_h
|
||||
redirect_to auth_url(params[:user][:auth_provider], params[:user][:auth_uid]), :status => :temporary_redirect
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
current_user.soft_destroy!
|
||||
|
||||
session.delete(:user)
|
||||
session_expires_automatically
|
||||
|
||||
flash[:notice] = t ".success"
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
|
@ -1,12 +1,13 @@
|
|||
module Api
|
||||
class ChangesetCommentsController < ApiController
|
||||
before_action :check_api_writable
|
||||
before_action :check_api_readable, :except => [:create]
|
||||
before_action :authorize
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :require_public_data, :only => [:create]
|
||||
before_action :check_api_writable
|
||||
before_action :check_api_readable, :except => [:create]
|
||||
before_action :set_request_formats
|
||||
around_action :api_call_handle_error
|
||||
around_action :api_call_timeout
|
||||
|
||||
|
@ -23,7 +24,7 @@ module Api
|
|||
|
||||
# Find the changeset and check it is valid
|
||||
changeset = Changeset.find(id)
|
||||
raise OSM::APIChangesetNotYetClosedError, changeset if changeset.is_open?
|
||||
raise OSM::APIChangesetNotYetClosedError, changeset if changeset.open?
|
||||
|
||||
# Add a comment to the changeset
|
||||
comment = changeset.comments.create(:changeset => changeset,
|
||||
|
@ -41,6 +42,11 @@ module Api
|
|||
# Return a copy of the updated changeset
|
||||
@changeset = changeset
|
||||
render "api/changesets/changeset"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -61,6 +67,11 @@ module Api
|
|||
# Return a copy of the updated changeset
|
||||
@changeset = comment.changeset
|
||||
render "api/changesets/changeset"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -81,6 +92,11 @@ module Api
|
|||
# Return a copy of the updated changeset
|
||||
@changeset = comment.changeset
|
||||
render "api/changesets/changeset"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,14 +4,14 @@ module Api
|
|||
class ChangesetsController < ApiController
|
||||
require "xml/libxml"
|
||||
|
||||
before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe]
|
||||
before_action :check_api_readable, :except => [:create, :update, :upload, :download, :query, :subscribe, :unsubscribe]
|
||||
before_action :authorize, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe]
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :require_public_data, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe]
|
||||
before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe]
|
||||
before_action :check_api_readable, :except => [:create, :update, :upload, :download, :query, :subscribe, :unsubscribe]
|
||||
before_action :set_request_formats, :only => [:download]
|
||||
before_action :set_request_formats, :except => [:create, :close, :upload]
|
||||
|
||||
around_action :api_call_handle_error
|
||||
around_action :api_call_timeout, :except => [:upload]
|
||||
|
@ -42,6 +42,11 @@ module Api
|
|||
@changeset = Changeset.find(params[:id])
|
||||
@include_discussion = params[:include_discussion].presence
|
||||
render "changeset"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -171,6 +176,11 @@ module Api
|
|||
# preload users, tags and comments, and render result
|
||||
@changesets = changesets.preload(:user, :changeset_tags, :comments)
|
||||
render "changesets"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -191,6 +201,11 @@ module Api
|
|||
check_changeset_consistency(@changeset, current_user)
|
||||
@changeset.update_from(new_changeset, current_user)
|
||||
render "changeset"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -212,6 +227,11 @@ module Api
|
|||
# Return a copy of the updated changeset
|
||||
@changeset = changeset
|
||||
render "changeset"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -233,6 +253,11 @@ module Api
|
|||
# Return a copy of the updated changeset
|
||||
@changeset = changeset
|
||||
render "changeset"
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -307,11 +332,11 @@ module Api
|
|||
times = time.split(",")
|
||||
raise OSM::APIBadUserInput, "bad time range" if times.size != 2
|
||||
|
||||
from, to = times.collect { |t| Time.parse(t) }
|
||||
from, to = times.collect { |t| Time.parse(t).utc }
|
||||
changesets.where("closed_at >= ? and created_at <= ?", from, to)
|
||||
else
|
||||
# if there is no comma, assume its a lower limit on time
|
||||
changesets.where("closed_at >= ?", Time.parse(time))
|
||||
changesets.where("closed_at >= ?", Time.parse(time).utc)
|
||||
end
|
||||
# stupid Time seems to throw both of these for bad parsing, so
|
||||
# we have to catch both and ensure the correct code path is taken.
|
||||
|
@ -329,7 +354,7 @@ module Api
|
|||
changesets
|
||||
else
|
||||
changesets.where("closed_at >= ? and num_changes <= ?",
|
||||
Time.now.getutc, Changeset::MAX_ELEMENTS)
|
||||
Time.now.utc, Changeset::MAX_ELEMENTS)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -341,7 +366,7 @@ module Api
|
|||
changesets
|
||||
else
|
||||
changesets.where("closed_at < ? or num_changes > ?",
|
||||
Time.now.getutc, Changeset::MAX_ELEMENTS)
|
||||
Time.now.utc, Changeset::MAX_ELEMENTS)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
module Api
|
||||
class MapController < ApiController
|
||||
before_action :check_api_readable
|
||||
|
||||
authorize_resource :class => false
|
||||
|
||||
before_action :check_api_readable
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
|
||||
before_action :set_request_formats
|
||||
|
|
|
@ -4,13 +4,13 @@ module Api
|
|||
class NodesController < ApiController
|
||||
require "xml/libxml"
|
||||
|
||||
before_action :check_api_writable, :only => [:create, :update, :delete]
|
||||
before_action :check_api_readable, :except => [:create, :update, :delete]
|
||||
before_action :authorize, :only => [:create, :update, :delete]
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :require_public_data, :only => [:create, :update, :delete]
|
||||
before_action :check_api_writable, :only => [:create, :update, :delete]
|
||||
before_action :check_api_readable, :except => [:create, :update, :delete]
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
|
||||
before_action :set_request_formats, :except => [:create, :update, :delete]
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
module Api
|
||||
class NotesController < ApiController
|
||||
before_action :check_api_readable
|
||||
before_action :setup_user_auth, :only => [:create, :comment, :show]
|
||||
before_action :check_api_writable, :only => [:create, :comment, :close, :reopen, :destroy]
|
||||
before_action :setup_user_auth, :only => [:create, :show]
|
||||
before_action :authorize, :only => [:close, :reopen, :destroy, :comment]
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :check_api_writable, :only => [:create, :comment, :close, :reopen, :destroy]
|
||||
before_action :set_locale
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
|
||||
|
@ -277,16 +277,16 @@ module Api
|
|||
# Add any date filter
|
||||
if params[:from]
|
||||
begin
|
||||
from = Time.parse(params[:from])
|
||||
from = Time.parse(params[:from]).utc
|
||||
rescue ArgumentError
|
||||
raise OSM::APIBadUserInput, "Date #{params[:from]} is in a wrong format"
|
||||
end
|
||||
|
||||
begin
|
||||
to = if params[:to]
|
||||
Time.parse(params[:to])
|
||||
Time.parse(params[:to]).utc
|
||||
else
|
||||
Time.now
|
||||
Time.now.utc
|
||||
end
|
||||
rescue ArgumentError
|
||||
raise OSM::APIBadUserInput, "Date #{params[:to]} is in a wrong format"
|
||||
|
@ -361,7 +361,7 @@ module Api
|
|||
elsif closed_since.positive?
|
||||
notes.where(:status => "open")
|
||||
.or(notes.where(:status => "closed")
|
||||
.where(notes.arel_table[:closed_at].gt(Time.now - closed_since.days)))
|
||||
.where(notes.arel_table[:closed_at].gt(Time.now.utc - closed_since.days)))
|
||||
else
|
||||
notes.where(:status => "open")
|
||||
end
|
||||
|
|
|
@ -5,13 +5,13 @@ module Api
|
|||
class OldController < ApiController
|
||||
require "xml/libxml"
|
||||
|
||||
before_action :check_api_readable
|
||||
before_action :check_api_writable, :only => [:redact]
|
||||
before_action :setup_user_auth, :only => [:history, :version]
|
||||
before_action :authorize, :only => [:redact]
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :check_api_readable
|
||||
before_action :check_api_writable, :only => [:redact]
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
before_action :lookup_old_element, :except => [:history]
|
||||
before_action :lookup_old_element_versions, :only => [:history]
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
module Api
|
||||
class PermissionsController < ApiController
|
||||
before_action :check_api_readable
|
||||
|
||||
authorize_resource :class => false
|
||||
|
||||
before_action :check_api_readable
|
||||
before_action :setup_user_auth
|
||||
before_action :set_request_formats
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
|
||||
# External apps that use the api are able to query which permissions
|
||||
|
@ -21,6 +23,11 @@ module Api
|
|||
else
|
||||
[]
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.xml
|
||||
format.json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,13 +2,13 @@ module Api
|
|||
class RelationsController < ApiController
|
||||
require "xml/libxml"
|
||||
|
||||
before_action :check_api_writable, :only => [:create, :update, :delete]
|
||||
before_action :check_api_readable, :except => [:create, :update, :delete]
|
||||
before_action :authorize, :only => [:create, :update, :delete]
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :require_public_data, :only => [:create, :update, :delete]
|
||||
before_action :check_api_writable, :only => [:create, :update, :delete]
|
||||
before_action :check_api_readable, :except => [:create, :update, :delete]
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
|
||||
before_action :set_request_formats, :except => [:create, :update, :delete]
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
module Api
|
||||
class TracepointsController < ApiController
|
||||
before_action :check_api_readable
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :check_api_readable
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
|
||||
# Get an XML response containing a list of tracepoints that have been uploaded
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
module Api
|
||||
class TracesController < ApiController
|
||||
before_action :check_database_readable, :except => [:show, :data]
|
||||
before_action :check_database_writable, :only => [:create, :update, :destroy]
|
||||
before_action :authorize_web
|
||||
before_action :set_locale
|
||||
before_action :authorize
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :check_database_readable, :except => [:show, :data]
|
||||
before_action :check_database_writable, :only => [:create, :update, :destroy]
|
||||
before_action :check_api_readable, :only => [:show, :data]
|
||||
before_action :check_api_writable, :only => [:create, :update, :destroy]
|
||||
before_action :offline_error, :only => [:create, :destroy, :data]
|
||||
|
@ -54,6 +54,8 @@ module Api
|
|||
send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment")
|
||||
elsif request.format == Mime[:gpx]
|
||||
send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment")
|
||||
elsif trace.file.attached?
|
||||
redirect_to rails_blob_path(trace.file, :disposition => "attachment")
|
||||
else
|
||||
send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment")
|
||||
end
|
||||
|
@ -97,12 +99,6 @@ module Api
|
|||
# Sanitise the user's filename
|
||||
name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, "_")
|
||||
|
||||
# Get a temporary filename...
|
||||
filename = "/tmp/#{rand}"
|
||||
|
||||
# ...and save the uploaded file to that location
|
||||
File.open(filename, "wb") { |f| f.write(file.read) }
|
||||
|
||||
# Create the trace object, falsely marked as already
|
||||
# inserted to stop the import daemon trying to load it
|
||||
trace = Trace.new(
|
||||
|
@ -110,40 +106,14 @@ module Api
|
|||
:tagstring => tags,
|
||||
:description => description,
|
||||
:visibility => visibility,
|
||||
:inserted => true,
|
||||
:inserted => false,
|
||||
:user => current_user,
|
||||
:timestamp => Time.now.getutc
|
||||
:timestamp => Time.now.utc,
|
||||
:file => file
|
||||
)
|
||||
|
||||
if trace.valid?
|
||||
Trace.transaction do
|
||||
begin
|
||||
# Save the trace object
|
||||
trace.save!
|
||||
|
||||
# Rename the temporary file to the final name
|
||||
FileUtils.mv(filename, trace.trace_name)
|
||||
rescue StandardError
|
||||
# Remove the file as we have failed to update the database
|
||||
FileUtils.rm_f(filename)
|
||||
|
||||
# Pass the exception on
|
||||
raise
|
||||
end
|
||||
|
||||
begin
|
||||
# Clear the inserted flag to make the import daemon load the trace
|
||||
trace.inserted = false
|
||||
trace.save!
|
||||
rescue StandardError
|
||||
# Remove the file as we have failed to update the database
|
||||
FileUtils.rm_f(trace.trace_name)
|
||||
|
||||
# Pass the exception on
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
# Save the trace object
|
||||
trace.save!
|
||||
|
||||
# Finally save the user's preferred privacy level
|
||||
if pref = current_user.preferences.where(:k => "gps.trace.visibility").first
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
module Api
|
||||
class UsersController < ApiController
|
||||
before_action :check_api_readable
|
||||
before_action :disable_terms_redirect, :only => [:details]
|
||||
before_action :setup_user_auth, :only => [:show, :index]
|
||||
before_action :authorize, :only => [:details, :gpx_files]
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :check_api_readable
|
||||
around_action :api_call_handle_error
|
||||
before_action :lookup_user_by_id, :only => [:show]
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ module Api
|
|||
class WaysController < ApiController
|
||||
require "xml/libxml"
|
||||
|
||||
before_action :check_api_writable, :only => [:create, :update, :delete]
|
||||
before_action :check_api_readable, :except => [:create, :update, :delete]
|
||||
before_action :authorize, :only => [:create, :update, :delete]
|
||||
|
||||
authorize_resource
|
||||
|
||||
before_action :require_public_data, :only => [:create, :update, :delete]
|
||||
before_action :check_api_writable, :only => [:create, :update, :delete]
|
||||
before_action :check_api_readable, :except => [:create, :update, :delete]
|
||||
around_action :api_call_handle_error, :api_call_timeout
|
||||
|
||||
before_action :set_request_formats, :except => [:create, :update, :delete]
|
||||
|
|
|
@ -31,9 +31,8 @@ class ApiController < ApplicationController
|
|||
# as XML for backwards compatibility - all other formats are discarded
|
||||
# which will result in a 406 Not Acceptable response being sent
|
||||
formats = mimetypes.map do |mime|
|
||||
if mime.symbol == :xml then :xml
|
||||
if mime.symbol == :xml || mime == "*/*" then :xml
|
||||
elsif mime.symbol == :json then :json
|
||||
elsif mime == "*/*" then :xml
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -53,8 +52,13 @@ class ApiController < ApplicationController
|
|||
# handle authenticate pass/fail
|
||||
unless current_user
|
||||
# no auth, the user does not exist or the password was wrong
|
||||
response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
|
||||
render :plain => errormessage, :status => :unauthorized
|
||||
if Settings.basic_auth_support
|
||||
response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
|
||||
render :plain => errormessage, :status => :unauthorized
|
||||
else
|
||||
render :plain => errormessage, :status => :forbidden
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
|
@ -76,11 +80,13 @@ class ApiController < ApplicationController
|
|||
report_error t("oauth.permissions.missing"), :forbidden
|
||||
elsif current_user
|
||||
head :forbidden
|
||||
else
|
||||
elsif Settings.basic_auth_support
|
||||
realm = "Web Password"
|
||||
errormessage = "Couldn't authenticate you"
|
||||
response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
|
||||
render :plain => errormessage, :status => :unauthorized
|
||||
else
|
||||
render :plain => errormessage, :status => :forbidden
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -95,13 +101,14 @@ class ApiController < ApplicationController
|
|||
# from the authorize method, but can be called elsewhere if authorisation
|
||||
# is optional.
|
||||
def setup_user_auth
|
||||
logger.info " setup_user_auth"
|
||||
# try and setup using OAuth
|
||||
if doorkeeper_token&.accessible?
|
||||
self.current_user = User.find(doorkeeper_token.resource_owner_id)
|
||||
elsif Authenticator.new(self, [:token]).allow?
|
||||
# self.current_user setup by OAuth
|
||||
else
|
||||
username, passwd = get_auth_data # parse from headers
|
||||
elsif Settings.basic_auth_support
|
||||
username, passwd = auth_data # parse from headers
|
||||
# authenticate per-scheme
|
||||
self.current_user = if username.nil?
|
||||
nil # no authentication provided - perhaps first connect (client should retry after 401)
|
||||
|
@ -110,6 +117,8 @@ class ApiController < ApplicationController
|
|||
else
|
||||
User.authenticate(:username => username, :password => passwd) # basic auth
|
||||
end
|
||||
# log if we have authenticated using basic auth
|
||||
logger.info "Authenticated as user #{current_user.id} using basic authentication" if current_user
|
||||
end
|
||||
|
||||
# have we identified the user?
|
||||
|
|
|
@ -161,7 +161,7 @@ class ApplicationController < ActionController::Base
|
|||
response.headers["Error"] = message
|
||||
|
||||
if request.headers["X-Error-Format"]&.casecmp("xml")&.zero?
|
||||
result = OSM::API.new.get_xml_doc
|
||||
result = OSM::API.new.xml_doc
|
||||
result.root.name = "osmError"
|
||||
result.root << (XML::Node.new("status") << "#{Rack::Utils.status_code(status)} #{Rack::Utils::HTTP_STATUS_CODES[status]}")
|
||||
result.root << (XML::Node.new("message") << message)
|
||||
|
@ -349,7 +349,7 @@ class ApplicationController < ActionController::Base
|
|||
elsif current_user
|
||||
set_locale
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :controller => "errors", :action => "forbidden" }
|
||||
format.html { redirect_to :controller => "/errors", :action => "forbidden" }
|
||||
format.any { report_error t("application.permission_denied"), :forbidden }
|
||||
end
|
||||
elsif request.get?
|
||||
|
@ -363,7 +363,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
# extract authorisation credentials from headers, returns user = nil if none
|
||||
def get_auth_data
|
||||
def auth_data
|
||||
if request.env.key? "X-HTTP_AUTHORIZATION" # where mod_rewrite might have put it
|
||||
authdata = request.env["X-HTTP_AUTHORIZATION"].to_s.split
|
||||
elsif request.env.key? "REDIRECT_X_HTTP_AUTHORIZATION" # mod_fcgi
|
||||
|
|
|
@ -8,7 +8,7 @@ module SessionMethods
|
|||
def auth_url(provider, uid, referer = nil)
|
||||
params = { :provider => provider }
|
||||
|
||||
params[:openid_url] = openid_expand_url(uid) if provider == "openid"
|
||||
params[:openid_url] = uid if provider == "openid"
|
||||
|
||||
if referer.nil?
|
||||
params[:origin] = request.path
|
||||
|
@ -20,23 +20,6 @@ module SessionMethods
|
|||
auth_path(params)
|
||||
end
|
||||
|
||||
##
|
||||
# special case some common OpenID providers by applying heuristics to
|
||||
# try and come up with the correct URL based on what the user entered
|
||||
def openid_expand_url(openid_url)
|
||||
if openid_url.nil?
|
||||
nil
|
||||
elsif openid_url.match(%r{(.*)gmail.com(/?)$}) || openid_url.match(%r{(.*)googlemail.com(/?)$})
|
||||
# Special case gmail.com as it is potentially a popular OpenID
|
||||
# provider and, unlike yahoo.com, where it works automatically, Google
|
||||
# have hidden their OpenID endpoint somewhere obscure this making it
|
||||
# somewhat less user friendly.
|
||||
"https://www.google.com/accounts/o8/id"
|
||||
else
|
||||
openid_url
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# process a successful login
|
||||
def successful_login(user, referer = nil)
|
||||
|
|
47
app/controllers/concerns/user_methods.rb
Normal file
47
app/controllers/concerns/user_methods.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
module UserMethods
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# update a user's details
|
||||
def update_user(user, params)
|
||||
user.display_name = params[:display_name]
|
||||
user.new_email = params[:new_email]
|
||||
|
||||
unless params[:pass_crypt].empty? && params[:pass_crypt_confirmation].empty?
|
||||
user.pass_crypt = params[:pass_crypt]
|
||||
user.pass_crypt_confirmation = params[:pass_crypt_confirmation]
|
||||
end
|
||||
|
||||
if params[:auth_provider].nil? || params[:auth_provider].blank?
|
||||
user.auth_provider = nil
|
||||
user.auth_uid = nil
|
||||
end
|
||||
|
||||
if user.save
|
||||
session[:fingerprint] = user.fingerprint
|
||||
|
||||
if user.new_email.blank? || user.new_email == user.email
|
||||
flash[:notice] = t "accounts.update.success"
|
||||
else
|
||||
user.email = user.new_email
|
||||
|
||||
if user.valid?
|
||||
flash[:notice] = t "accounts.update.success_confirm_needed"
|
||||
|
||||
begin
|
||||
UserMailer.email_confirm(user, user.tokens.create).deliver_later
|
||||
rescue StandardError
|
||||
# Ignore errors sending email
|
||||
end
|
||||
else
|
||||
current_user.errors.add(:new_email, current_user.errors[:email])
|
||||
current_user.errors.add(:email, [])
|
||||
end
|
||||
|
||||
user.restore_email!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,7 +25,7 @@ class ConfirmationsController < ApplicationController
|
|||
render_unknown_user token.user.display_name
|
||||
else
|
||||
user = token.user
|
||||
user.status = "active"
|
||||
user.activate
|
||||
user.email_valid = true
|
||||
flash[:notice] = gravatar_status_message(user) if gravatar_enable(user)
|
||||
user.save!
|
||||
|
@ -93,10 +93,10 @@ class ConfirmationsController < ApplicationController
|
|||
current_user.tokens.delete_all
|
||||
session[:user] = current_user.id
|
||||
session[:fingerprint] = current_user.fingerprint
|
||||
redirect_to user_account_path(current_user)
|
||||
redirect_to edit_account_path
|
||||
elsif token
|
||||
flash[:error] = t "confirmations.confirm_email.failure"
|
||||
redirect_to user_account_path(token.user)
|
||||
redirect_to edit_account_path
|
||||
else
|
||||
flash[:error] = t "confirmations.confirm_email.unknown_token"
|
||||
end
|
||||
|
|
|
@ -60,9 +60,8 @@ class DiaryEntriesController < ApplicationController
|
|||
@title = t "diary_entries.edit.title"
|
||||
@diary_entry = DiaryEntry.find(params[:id])
|
||||
|
||||
if current_user != @diary_entry.user
|
||||
redirect_to diary_entry_path(@diary_entry.user, @diary_entry)
|
||||
elsif params[:diary_entry] && @diary_entry.update(entry_params)
|
||||
if current_user != @diary_entry.user ||
|
||||
(params[:diary_entry] && @diary_entry.update(entry_params))
|
||||
redirect_to diary_entry_path(@diary_entry.user, @diary_entry)
|
||||
else
|
||||
set_map_location
|
||||
|
|
|
@ -21,7 +21,7 @@ class ExportController < ApplicationController
|
|||
format = params[:mapnik_format]
|
||||
scale = params[:mapnik_scale]
|
||||
|
||||
redirect_to "https://render.openstreetmap.org/cgi-bin/export?bbox=#{bbox}&scale=#{scale}&format=#{format}"
|
||||
redirect_to "https://render.openstreetmap.org/cgi-bin/export?bbox=#{bbox}&scale=#{scale}&format=#{format}", :allow_other_host => true
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@ class FriendshipsController < ApplicationController
|
|||
friendship = Friendship.new
|
||||
friendship.befriender = current_user
|
||||
friendship.befriendee = @new_friend
|
||||
if current_user.is_friends_with?(@new_friend)
|
||||
if current_user.friends_with?(@new_friend)
|
||||
flash[:warning] = t "friendships.make_friend.already_a_friend", :name => @new_friend.display_name
|
||||
elsif current_user.friendships.where("created_at >= ?", Time.now.getutc - 1.hour).count >= current_user.max_friends_per_hour
|
||||
elsif current_user.friendships.where("created_at >= ?", Time.now.utc - 1.hour).count >= current_user.max_friends_per_hour
|
||||
flash.now[:error] = t "friendships.make_friend.limit_exceeded"
|
||||
elsif friendship.save
|
||||
flash[:notice] = t "friendships.make_friend.success", :name => @new_friend.display_name
|
||||
|
@ -42,7 +42,7 @@ class FriendshipsController < ApplicationController
|
|||
|
||||
if @friend
|
||||
if request.post?
|
||||
if current_user.is_friends_with?(@friend)
|
||||
if current_user.friends_with?(@friend)
|
||||
Friendship.where(:befriender => current_user, :befriendee => @friend).delete_all
|
||||
flash[:notice] = t "friendships.remove_friend.success", :name => @friend.display_name
|
||||
else
|
||||
|
|
|
@ -18,9 +18,8 @@ class GeocoderController < ApplicationController
|
|||
@sources.push "geonames_reverse" if Settings.key?(:geonames_username)
|
||||
elsif @params[:query]
|
||||
case @params[:query]
|
||||
when /^\d{5}(-\d{4})?$/
|
||||
@sources.push "osm_nominatim"
|
||||
when /^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s*[0-9][ABD-HJLNP-UW-Z]{2})$/i
|
||||
when /^\d{5}(-\d{4})?$/,
|
||||
/^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s*[0-9][ABD-HJLNP-UW-Z]{2})$/i
|
||||
@sources.push "osm_nominatim"
|
||||
when /^[A-Z]\d[A-Z]\s*\d[A-Z]\d$/i
|
||||
@sources.push "ca_postcode"
|
||||
|
@ -168,7 +167,8 @@ class GeocoderController < ApplicationController
|
|||
|
||||
render :action => "results"
|
||||
rescue StandardError => e
|
||||
@error = "Error contacting nominatim.openstreetmap.org: #{e}"
|
||||
host = URI(Settings.nominatim_url).host
|
||||
@error = "Error contacting #{host}: #{e}"
|
||||
render :action => "error"
|
||||
end
|
||||
|
||||
|
@ -232,7 +232,8 @@ class GeocoderController < ApplicationController
|
|||
|
||||
render :action => "results"
|
||||
rescue StandardError => e
|
||||
@error = "Error contacting nominatim.openstreetmap.org: #{e}"
|
||||
host = URI(Settings.nominatim_url).host
|
||||
@error = "Error contacting #{host}: #{e}"
|
||||
render :action => "error"
|
||||
end
|
||||
|
||||
|
@ -291,22 +292,19 @@ class GeocoderController < ApplicationController
|
|||
if query = params[:query]
|
||||
query.strip!
|
||||
|
||||
if latlon = query.match(/^([NS])\s*(\d{1,3}(\.\d*)?)\W*([EW])\s*(\d{1,3}(\.\d*)?)$/).try(:captures) # [NSEW] decimal degrees
|
||||
params.merge!(nsew_to_decdeg(latlon)).delete(:query)
|
||||
elsif latlon = query.match(/^(\d{1,3}(\.\d*)?)\s*([NS])\W*(\d{1,3}(\.\d*)?)\s*([EW])$/).try(:captures) # decimal degrees [NSEW]
|
||||
if latlon = query.match(/^([NS])\s*(\d{1,3}(\.\d*)?)\W*([EW])\s*(\d{1,3}(\.\d*)?)$/).try(:captures) || # [NSEW] decimal degrees
|
||||
query.match(/^(\d{1,3}(\.\d*)?)\s*([NS])\W*(\d{1,3}(\.\d*)?)\s*([EW])$/).try(:captures) # decimal degrees [NSEW]
|
||||
params.merge!(nsew_to_decdeg(latlon)).delete(:query)
|
||||
|
||||
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?['′]?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?['′]?$/).try(:captures) # [NSEW] degrees, decimal minutes
|
||||
params.merge!(ddm_to_decdeg(latlon)).delete(:query)
|
||||
elsif latlon = query.match(/^(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?['′]?\s*([NS])\W*(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?['′]?\s*([EW])$/).try(:captures) # degrees, decimal minutes [NSEW]
|
||||
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?['′]?)?\W*([EW])\s*(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?['′]?)?$/).try(:captures) || # [NSEW] degrees, decimal minutes
|
||||
query.match(/^(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?['′]?)?\s*([NS])\W*(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?['′]?)?\s*([EW])$/).try(:captures) # degrees, decimal minutes [NSEW]
|
||||
params.merge!(ddm_to_decdeg(latlon)).delete(:query)
|
||||
|
||||
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?\s*(\d{1,2})['′]?\s*(\d{1,3}(\.\d*)?)?["″]?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,2})['′]?\s*(\d{1,3}(\.\d*)?)?["″]?$/).try(:captures) # [NSEW] degrees, minutes, decimal seconds
|
||||
params.merge!(dms_to_decdeg(latlon)).delete(:query)
|
||||
elsif latlon = query.match(/^(\d{1,3})°?\s*(\d{1,2})['′]?\s*(\d{1,3}(\.\d*)?)?["″]\s*([NS])\W*(\d{1,3})°?\s*(\d{1,2})['′]?\s*(\d{1,3}(\.\d*)?)?["″]?\s*([EW])$/).try(:captures) # degrees, minutes, decimal seconds [NSEW]
|
||||
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?\s*(\d{1,2})['′]?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,2})['′]?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?$/).try(:captures) || # [NSEW] degrees, minutes, decimal seconds
|
||||
query.match(/^(\d{1,3})°?\s*(\d{1,2})['′]?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?\s*([NS])\W*(\d{1,3})°?\s*(\d{1,2})['′]?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?\s*([EW])$/).try(:captures) # degrees, minutes, decimal seconds [NSEW]
|
||||
params.merge!(dms_to_decdeg(latlon)).delete(:query)
|
||||
|
||||
elsif latlon = query.match(/^\s*([+-]?\d+(\.\d*)?)\s*[\s,]\s*([+-]?\d+(\.\d*)?)\s*$/)
|
||||
elsif latlon = query.match(/^([+-]?\d+(\.\d*)?)(?:\s+|\s*,\s*)([+-]?\d+(\.\d*)?)$/)
|
||||
params.merge!(:lat => latlon[1].to_f, :lon => latlon[3].to_f).delete(:query)
|
||||
|
||||
params[:latlon_digits] = true unless params[:whereami]
|
||||
|
@ -331,11 +329,11 @@ class GeocoderController < ApplicationController
|
|||
def ddm_to_decdeg(captures)
|
||||
begin
|
||||
Float(captures[0])
|
||||
lat = captures[3].casecmp("s").zero? ? -(captures[0].to_f + captures[1].to_f / 60) : captures[0].to_f + captures[1].to_f / 60
|
||||
lon = captures[7].casecmp("w").zero? ? -(captures[4].to_f + captures[5].to_f / 60) : captures[4].to_f + captures[5].to_f / 60
|
||||
lat = captures[3].casecmp("s").zero? ? -(captures[0].to_f + (captures[1].to_f / 60)) : captures[0].to_f + (captures[1].to_f / 60)
|
||||
lon = captures[7].casecmp("w").zero? ? -(captures[4].to_f + (captures[5].to_f / 60)) : captures[4].to_f + (captures[5].to_f / 60)
|
||||
rescue StandardError
|
||||
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + captures[2].to_f / 60) : captures[1].to_f + captures[2].to_f / 60
|
||||
lon = captures[4].casecmp("w").zero? ? -(captures[5].to_f + captures[6].to_f / 60) : captures[5].to_f + captures[6].to_f / 60
|
||||
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + (captures[2].to_f / 60)) : captures[1].to_f + (captures[2].to_f / 60)
|
||||
lon = captures[4].casecmp("w").zero? ? -(captures[5].to_f + (captures[6].to_f / 60)) : captures[5].to_f + (captures[6].to_f / 60)
|
||||
end
|
||||
{ :lat => lat, :lon => lon }
|
||||
end
|
||||
|
@ -343,11 +341,11 @@ class GeocoderController < ApplicationController
|
|||
def dms_to_decdeg(captures)
|
||||
begin
|
||||
Float(captures[0])
|
||||
lat = captures[4].casecmp("s").zero? ? -(captures[0].to_f + (captures[1].to_f + captures[2].to_f / 60) / 60) : captures[0].to_f + (captures[1].to_f + captures[2].to_f / 60) / 60
|
||||
lon = captures[9].casecmp("w").zero? ? -(captures[5].to_f + (captures[6].to_f + captures[7].to_f / 60) / 60) : captures[5].to_f + (captures[6].to_f + captures[7].to_f / 60) / 60
|
||||
lat = captures[4].casecmp("s").zero? ? -(captures[0].to_f + ((captures[1].to_f + (captures[2].to_f / 60)) / 60)) : captures[0].to_f + ((captures[1].to_f + (captures[2].to_f / 60)) / 60)
|
||||
lon = captures[9].casecmp("w").zero? ? -(captures[5].to_f + ((captures[6].to_f + (captures[7].to_f / 60)) / 60)) : captures[5].to_f + ((captures[6].to_f + (captures[7].to_f / 60)) / 60)
|
||||
rescue StandardError
|
||||
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + (captures[2].to_f + captures[3].to_f / 60) / 60) : captures[1].to_f + (captures[2].to_f + captures[3].to_f / 60) / 60
|
||||
lon = captures[5].casecmp("w").zero? ? -(captures[6].to_f + (captures[7].to_f + captures[8].to_f / 60) / 60) : captures[6].to_f + (captures[7].to_f + captures[8].to_f / 60) / 60
|
||||
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + ((captures[2].to_f + (captures[3].to_f / 60)) / 60)) : captures[1].to_f + ((captures[2].to_f + (captures[3].to_f / 60)) / 60)
|
||||
lon = captures[5].casecmp("w").zero? ? -(captures[6].to_f + ((captures[7].to_f + (captures[8].to_f / 60)) / 60)) : captures[6].to_f + ((captures[7].to_f + (captures[8].to_f / 60)) / 60)
|
||||
end
|
||||
{ :lat => lat, :lon => lon }
|
||||
end
|
||||
|
|
|
@ -11,9 +11,20 @@ class IssueCommentsController < ApplicationController
|
|||
comment = @issue.comments.build(issue_comment_params)
|
||||
comment.user = current_user
|
||||
comment.save!
|
||||
notice = t(".comment_created")
|
||||
reassign_issue(@issue) if params[:reassign]
|
||||
redirect_to @issue, :notice => notice
|
||||
|
||||
if params[:reassign]
|
||||
reassign_issue(@issue)
|
||||
flash[:notice] = t ".issue_reassigned"
|
||||
|
||||
if current_user.has_role? @issue.assigned_role
|
||||
redirect_to @issue
|
||||
else
|
||||
redirect_to issues_path(:status => "open")
|
||||
end
|
||||
else
|
||||
flash[:notice] = t(".comment_created")
|
||||
redirect_to @issue
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -24,9 +24,9 @@ class MessagesController < ApplicationController
|
|||
@message = Message.new(message_params)
|
||||
@message.recipient = @user
|
||||
@message.sender = current_user
|
||||
@message.sent_on = Time.now.getutc
|
||||
@message.sent_on = Time.now.utc
|
||||
|
||||
if current_user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= current_user.max_messages_per_hour
|
||||
if current_user.sent_messages.where("sent_on >= ?", Time.now.utc - 1.hour).count >= current_user.max_messages_per_hour
|
||||
flash.now[:error] = t ".limit_exceeded"
|
||||
render :action => "new"
|
||||
elsif @message.save
|
||||
|
@ -121,11 +121,7 @@ class MessagesController < ApplicationController
|
|||
|
||||
referer = safe_referer(params[:referer]) if params[:referer]
|
||||
|
||||
if referer
|
||||
redirect_to referer
|
||||
else
|
||||
redirect_to :action => :inbox
|
||||
end
|
||||
redirect_to referer || { :action => :inbox }
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
@title = t "messages.no_such_message.title"
|
||||
|
|
|
@ -3,12 +3,13 @@ class Oauth2AuthorizationsController < Doorkeeper::AuthorizationsController
|
|||
|
||||
prepend_before_action :authorize_web
|
||||
before_action :set_locale
|
||||
before_action :allow_all_form_action, :only => [:new]
|
||||
|
||||
authorize_resource :class => false
|
||||
|
||||
def new
|
||||
override_content_security_policy_directives(:form_action => []) if Settings.csp_enforce || Settings.key?(:csp_report_url)
|
||||
private
|
||||
|
||||
super
|
||||
def allow_all_form_action
|
||||
override_content_security_policy_directives(:form_action => []) if Settings.csp_enforce || Settings.key?(:csp_report_url)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,7 +66,7 @@ class OauthController < ApplicationController
|
|||
|
||||
@redirect_url.query += "&oauth_verifier=#{@token.verifier}" unless @token.oauth10?
|
||||
|
||||
redirect_to @redirect_url.to_s
|
||||
redirect_to @redirect_url.to_s, :allow_other_host => true
|
||||
end
|
||||
else
|
||||
@token.invalidate!
|
||||
|
|
|
@ -46,7 +46,7 @@ class PasswordsController < ApplicationController
|
|||
if params[:user]
|
||||
current_user.pass_crypt = params[:user][:pass_crypt]
|
||||
current_user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
|
||||
current_user.status = "active" if current_user.status == "pending"
|
||||
current_user.activate if current_user.may_activate?
|
||||
current_user.email_valid = true
|
||||
|
||||
if current_user.save
|
||||
|
|
|
@ -26,7 +26,7 @@ class PreferencesController < ApplicationController
|
|||
flash[:notice] = { :partial => "preferences/update_success_flash" }
|
||||
redirect_to preferences_path
|
||||
else
|
||||
flash[:error] = t ".failure"
|
||||
flash.now[:error] = t ".failure"
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,7 +36,7 @@ class ProfilesController < ApplicationController
|
|||
flash[:notice] = t ".success"
|
||||
redirect_to user_path(current_user)
|
||||
else
|
||||
flash[:error] = t ".failure"
|
||||
flash.now[:error] = t ".failure"
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,7 +28,8 @@ class ReportsController < ApplicationController
|
|||
|
||||
redirect_to helpers.reportable_url(@report.issue.reportable), :notice => t(".successful_report")
|
||||
else
|
||||
redirect_to new_report_path(:reportable_type => @report.issue.reportable_type, :reportable_id => @report.issue.reportable_id), :notice => t(".provide_details")
|
||||
flash.now[:notice] = t(".provide_details")
|
||||
render :action => "new"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -12,9 +12,7 @@ class SessionsController < ApplicationController
|
|||
authorize_resource :class => false
|
||||
|
||||
def new
|
||||
append_content_security_policy_directives(
|
||||
:form_action => %w[*]
|
||||
)
|
||||
override_content_security_policy_directives(:form_action => []) if Settings.csp_enforce || Settings.key?(:csp_report_url)
|
||||
|
||||
session[:referer] = safe_referer(params[:referer]) if params[:referer]
|
||||
end
|
||||
|
@ -40,11 +38,7 @@ class SessionsController < ApplicationController
|
|||
|
||||
referer = safe_referer(params[:referer]) if params[:referer]
|
||||
|
||||
if referer
|
||||
redirect_to referer
|
||||
else
|
||||
redirect_to :controller => "site", :action => "index"
|
||||
end
|
||||
redirect_to referer || { :controller => "site", :action => "index" }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ class SiteController < ApplicationController
|
|||
before_action :redirect_browse_params, :only => :index
|
||||
before_action :redirect_map_params, :only => [:index, :edit, :export]
|
||||
before_action :require_oauth, :only => [:index]
|
||||
before_action :require_user, :only => [:id]
|
||||
before_action :update_totp, :only => [:index]
|
||||
|
||||
authorize_resource :class => false
|
||||
|
|
|
@ -28,7 +28,7 @@ class TracesController < ApplicationController
|
|||
@title = if target_user.nil?
|
||||
t ".public_traces"
|
||||
elsif current_user && current_user == target_user
|
||||
t ".my_traces"
|
||||
t ".my_gps_traces"
|
||||
else
|
||||
t ".public_traces_from", :user => target_user.display_name
|
||||
end
|
||||
|
@ -99,12 +99,8 @@ class TracesController < ApplicationController
|
|||
logger.info(params[:trace][:gpx_file].class.name)
|
||||
|
||||
if params[:trace][:gpx_file].respond_to?(:read)
|
||||
begin
|
||||
@trace = do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
|
||||
params[:trace][:description], params[:trace][:visibility])
|
||||
rescue StandardError => e
|
||||
logger.debug e
|
||||
end
|
||||
@trace = do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
|
||||
params[:trace][:description], params[:trace][:visibility])
|
||||
|
||||
if @trace.id
|
||||
flash[:notice] = t ".trace_uploaded"
|
||||
|
@ -123,7 +119,7 @@ class TracesController < ApplicationController
|
|||
:description => params[:trace][:description],
|
||||
:visibility => params[:trace][:visibility],
|
||||
:inserted => false, :user => current_user,
|
||||
:timestamp => Time.now.getutc)
|
||||
:timestamp => Time.now.utc)
|
||||
@trace.valid?
|
||||
@trace.errors.add(:gpx_file, "can't be blank")
|
||||
|
||||
|
@ -141,6 +137,8 @@ class TracesController < ApplicationController
|
|||
send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment")
|
||||
elsif request.format == Mime[:gpx]
|
||||
send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment")
|
||||
elsif trace.file.attached?
|
||||
redirect_to rails_blob_path(trace.file, :disposition => "attachment")
|
||||
else
|
||||
send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment")
|
||||
end
|
||||
|
@ -217,8 +215,12 @@ class TracesController < ApplicationController
|
|||
|
||||
if trace.visible? && trace.inserted?
|
||||
if trace.public? || (current_user && current_user == trace.user)
|
||||
expires_in 7.days, :private => !trace.public?, :public => trace.public?
|
||||
send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => "image/gif", :disposition => "inline")
|
||||
if trace.icon.attached?
|
||||
redirect_to rails_blob_path(trace.image, :disposition => "inline")
|
||||
else
|
||||
expires_in 7.days, :private => !trace.public?, :public => trace.public?
|
||||
send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => "image/gif", :disposition => "inline")
|
||||
end
|
||||
else
|
||||
head :forbidden
|
||||
end
|
||||
|
@ -234,8 +236,12 @@ class TracesController < ApplicationController
|
|||
|
||||
if trace.visible? && trace.inserted?
|
||||
if trace.public? || (current_user && current_user == trace.user)
|
||||
expires_in 7.days, :private => !trace.public?, :public => trace.public?
|
||||
send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => "image/gif", :disposition => "inline")
|
||||
if trace.icon.attached?
|
||||
redirect_to rails_blob_path(trace.icon, :disposition => "inline")
|
||||
else
|
||||
expires_in 7.days, :private => !trace.public?, :public => trace.public?
|
||||
send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => "image/gif", :disposition => "inline")
|
||||
end
|
||||
else
|
||||
head :forbidden
|
||||
end
|
||||
|
@ -252,62 +258,29 @@ class TracesController < ApplicationController
|
|||
# Sanitise the user's filename
|
||||
name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, "_")
|
||||
|
||||
# Get a temporary filename...
|
||||
filename = "/tmp/#{rand}"
|
||||
|
||||
# ...and save the uploaded file to that location
|
||||
File.open(filename, "wb") { |f| f.write(file.read) }
|
||||
|
||||
# Create the trace object, falsely marked as already
|
||||
# inserted to stop the import daemon trying to load it
|
||||
# Create the trace object
|
||||
trace = Trace.new(
|
||||
:name => name,
|
||||
:tagstring => tags,
|
||||
:description => description,
|
||||
:visibility => visibility,
|
||||
:inserted => true,
|
||||
:inserted => false,
|
||||
:user => current_user,
|
||||
:timestamp => Time.now.getutc
|
||||
:timestamp => Time.now.utc,
|
||||
:file => file
|
||||
)
|
||||
|
||||
if trace.valid?
|
||||
Trace.transaction do
|
||||
begin
|
||||
# Save the trace object
|
||||
trace.save!
|
||||
|
||||
# Rename the temporary file to the final name
|
||||
FileUtils.mv(filename, trace.trace_name)
|
||||
rescue StandardError
|
||||
# Remove the file as we have failed to update the database
|
||||
FileUtils.rm_f(filename)
|
||||
|
||||
# Pass the exception on
|
||||
raise
|
||||
end
|
||||
|
||||
begin
|
||||
# Clear the inserted flag to make the import daemon load the trace
|
||||
trace.inserted = false
|
||||
trace.save!
|
||||
rescue StandardError
|
||||
# Remove the file as we have failed to update the database
|
||||
FileUtils.rm_f(trace.trace_name)
|
||||
|
||||
# Pass the exception on
|
||||
raise
|
||||
end
|
||||
# Save the trace object
|
||||
if trace.save
|
||||
# Finally save the user's preferred privacy level
|
||||
if pref = current_user.preferences.where(:k => "gps.trace.visibility").first
|
||||
pref.v = visibility
|
||||
pref.save
|
||||
else
|
||||
current_user.preferences.create(:k => "gps.trace.visibility", :v => visibility)
|
||||
end
|
||||
end
|
||||
|
||||
# Finally save the user's preferred privacy level
|
||||
if pref = current_user.preferences.where(:k => "gps.trace.visibility").first
|
||||
pref.v = visibility
|
||||
pref.save
|
||||
else
|
||||
current_user.preferences.create(:k => "gps.trace.visibility", :v => visibility)
|
||||
end
|
||||
|
||||
trace
|
||||
end
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ class UserBlocksController < ApplicationController
|
|||
end
|
||||
|
||||
def edit
|
||||
params[:user_block_period] = ((@user_block.ends_at - Time.now.getutc) / 1.hour).ceil.to_s
|
||||
params[:user_block_period] = ((@user_block.ends_at - Time.now.utc) / 1.hour).ceil.to_s
|
||||
end
|
||||
|
||||
def create
|
||||
|
@ -41,7 +41,7 @@ class UserBlocksController < ApplicationController
|
|||
:user => @user,
|
||||
:creator => current_user,
|
||||
:reason => params[:user_block][:reason],
|
||||
:ends_at => Time.now.getutc + @block_period.hours,
|
||||
:ends_at => Time.now.utc + @block_period.hours,
|
||||
:needs_view => params[:user_block][:needs_view]
|
||||
)
|
||||
|
||||
|
@ -62,7 +62,7 @@ class UserBlocksController < ApplicationController
|
|||
flash[:error] = t(".only_creator_can_edit")
|
||||
redirect_to :action => "edit"
|
||||
elsif @user_block.update(
|
||||
:ends_at => Time.now.getutc + @block_period.hours,
|
||||
:ends_at => Time.now.utc + @block_period.hours,
|
||||
:reason => params[:user_block][:reason],
|
||||
:needs_view => params[:user_block][:needs_view]
|
||||
)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class UsersController < ApplicationController
|
||||
include SessionMethods
|
||||
include UserMethods
|
||||
|
||||
layout "site"
|
||||
|
||||
|
@ -11,11 +12,10 @@ class UsersController < ApplicationController
|
|||
|
||||
authorize_resource
|
||||
|
||||
before_action :require_self, :only => [:account]
|
||||
before_action :check_database_writable, :only => [:new, :account, :go_public]
|
||||
before_action :check_database_writable, :only => [:new, :go_public]
|
||||
before_action :require_cookies, :only => [:new]
|
||||
before_action :lookup_user_by_name, :only => [:set_status, :destroy]
|
||||
before_action :allow_thirdparty_images, :only => [:show, :account]
|
||||
before_action :allow_thirdparty_images, :only => [:show]
|
||||
|
||||
def terms
|
||||
@legale = params[:legale] || OSM.ip_to_country(request.remote_ip) || Settings.default_legale
|
||||
|
@ -28,7 +28,7 @@ class UsersController < ApplicationController
|
|||
|
||||
if current_user&.terms_agreed?
|
||||
# Already agreed to terms, so just show settings
|
||||
redirect_to user_account_path(current_user)
|
||||
redirect_to edit_account_path
|
||||
elsif current_user.nil? && session[:new_user].nil?
|
||||
redirect_to login_path(:referer => request.fullpath)
|
||||
end
|
||||
|
@ -46,7 +46,7 @@ class UsersController < ApplicationController
|
|||
|
||||
referer = safe_referer(params[:referer]) if params[:referer]
|
||||
|
||||
redirect_to referer || user_account_path(current_user)
|
||||
redirect_to referer || edit_account_path
|
||||
elsif params[:decline]
|
||||
redirect_to t("users.terms.declined")
|
||||
else
|
||||
|
@ -55,8 +55,8 @@ class UsersController < ApplicationController
|
|||
elsif current_user
|
||||
unless current_user.terms_agreed?
|
||||
current_user.consider_pd = params[:user][:consider_pd]
|
||||
current_user.tou_agreed = Time.now.getutc
|
||||
current_user.terms_agreed = Time.now.getutc
|
||||
current_user.tou_agreed = Time.now.utc
|
||||
current_user.terms_agreed = Time.now.utc
|
||||
current_user.terms_seen = true
|
||||
|
||||
flash[:notice] = t "users.new.terms accepted" if current_user.save
|
||||
|
@ -64,7 +64,7 @@ class UsersController < ApplicationController
|
|||
|
||||
referer = safe_referer(params[:referer]) if params[:referer]
|
||||
|
||||
redirect_to referer || user_account_path(current_user)
|
||||
redirect_to referer || edit_account_path
|
||||
else
|
||||
self.current_user = session.delete(:new_user)
|
||||
|
||||
|
@ -73,8 +73,8 @@ class UsersController < ApplicationController
|
|||
current_user.description = "" if current_user.description.nil?
|
||||
current_user.creation_ip = request.remote_ip
|
||||
current_user.languages = http_accept_language.user_preferred_languages
|
||||
current_user.terms_agreed = Time.now.getutc
|
||||
current_user.tou_agreed = Time.now.getutc
|
||||
current_user.terms_agreed = Time.now.utc
|
||||
current_user.tou_agreed = Time.now.utc
|
||||
current_user.terms_seen = true
|
||||
|
||||
if current_user.auth_uid.blank?
|
||||
|
@ -83,7 +83,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
if current_user.save
|
||||
flash[:piwik_goal] = PIWIK["goals"]["signup"] if defined?(PIWIK)
|
||||
flash[:matomo_goal] = Settings.matomo["goals"]["signup"] if defined?(Settings.matomo)
|
||||
|
||||
referer = welcome_path
|
||||
|
||||
|
@ -114,36 +114,11 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def account
|
||||
@tokens = current_user.oauth_tokens.authorized
|
||||
|
||||
append_content_security_policy_directives(
|
||||
:form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org]
|
||||
)
|
||||
|
||||
if request.post?
|
||||
if params[:user][:auth_provider].blank? ||
|
||||
(params[:user][:auth_provider] == current_user.auth_provider &&
|
||||
params[:user][:auth_uid] == current_user.auth_uid)
|
||||
update_user(current_user, params)
|
||||
redirect_to user_account_url(current_user) if current_user.errors.count.zero?
|
||||
else
|
||||
session[:new_user_settings] = params
|
||||
redirect_to auth_url(params[:user][:auth_provider], params[:user][:auth_uid]), :status => :temporary_redirect
|
||||
end
|
||||
elsif errors = session.delete(:user_errors)
|
||||
errors.each do |attribute, error|
|
||||
current_user.errors.add(attribute, error)
|
||||
end
|
||||
end
|
||||
@title = t "users.account.title"
|
||||
end
|
||||
|
||||
def go_public
|
||||
current_user.data_public = true
|
||||
current_user.save
|
||||
flash[:notice] = t "users.go_public.flash success"
|
||||
redirect_to user_account_path(current_user)
|
||||
redirect_to edit_account_path
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -161,11 +136,7 @@ class UsersController < ApplicationController
|
|||
if current_user
|
||||
# The user is logged in already, so don't show them the signup
|
||||
# page, instead send them to the home page
|
||||
if @referer
|
||||
redirect_to @referer
|
||||
else
|
||||
redirect_to :controller => "site", :action => "index"
|
||||
end
|
||||
redirect_to @referer || { :controller => "site", :action => "index" }
|
||||
elsif params.key?(:auth_provider) && params.key?(:auth_uid)
|
||||
self.current_user = User.new(:email => params[:email],
|
||||
:email_confirmation => params[:email],
|
||||
|
@ -189,8 +160,6 @@ class UsersController < ApplicationController
|
|||
|
||||
Rails.logger.info "create: #{session[:referer]}"
|
||||
|
||||
current_user.status = "pending"
|
||||
|
||||
if current_user.auth_provider.present? && current_user.pass_crypt.empty?
|
||||
# We are creating an account with external authentication and
|
||||
# no password was specified so create a random one
|
||||
|
@ -227,15 +196,19 @@ class UsersController < ApplicationController
|
|||
##
|
||||
# sets a user's status
|
||||
def set_status
|
||||
@user.status = params[:status]
|
||||
@user.save
|
||||
@user.activate! if params[:event] == "activate"
|
||||
@user.confirm! if params[:event] == "confirm"
|
||||
@user.unconfirm! if params[:event] == "unconfirm"
|
||||
@user.hide! if params[:event] == "hide"
|
||||
@user.unhide! if params[:event] == "unhide"
|
||||
@user.unsuspend! if params[:event] == "unsuspend"
|
||||
redirect_to user_path(:display_name => params[:display_name])
|
||||
end
|
||||
|
||||
##
|
||||
# delete a user, marking them as deleted and removing personal data
|
||||
# destroy a user, marking them as deleted and removing personal data
|
||||
def destroy
|
||||
@user.delete
|
||||
@user.soft_destroy!
|
||||
redirect_to user_path(:display_name => params[:display_name])
|
||||
end
|
||||
|
||||
|
@ -293,12 +266,12 @@ class UsersController < ApplicationController
|
|||
|
||||
session[:user_errors] = current_user.errors.as_json
|
||||
|
||||
redirect_to user_account_path(current_user)
|
||||
redirect_to edit_account_path
|
||||
elsif session[:new_user]
|
||||
session[:new_user].auth_provider = provider
|
||||
session[:new_user].auth_uid = uid
|
||||
|
||||
session[:new_user].status = "active" if email_verified && email == session[:new_user].email
|
||||
session[:new_user].activate if email_verified && email == session[:new_user].email
|
||||
|
||||
redirect_to :action => "terms"
|
||||
else
|
||||
|
@ -340,54 +313,6 @@ class UsersController < ApplicationController
|
|||
|
||||
private
|
||||
|
||||
##
|
||||
# update a user's details
|
||||
def update_user(user, params)
|
||||
user.display_name = params[:user][:display_name]
|
||||
user.new_email = params[:user][:new_email]
|
||||
|
||||
unless params[:user][:pass_crypt].empty? && params[:user][:pass_crypt_confirmation].empty?
|
||||
user.pass_crypt = params[:user][:pass_crypt]
|
||||
user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
|
||||
end
|
||||
|
||||
if params[:user][:auth_provider].nil? || params[:user][:auth_provider].blank?
|
||||
user.auth_provider = nil
|
||||
user.auth_uid = nil
|
||||
end
|
||||
|
||||
if user.save
|
||||
session[:fingerprint] = user.fingerprint
|
||||
|
||||
if user.new_email.blank? || user.new_email == user.email
|
||||
flash[:notice] = t "users.account.flash update success"
|
||||
else
|
||||
user.email = user.new_email
|
||||
|
||||
if user.valid?
|
||||
flash[:notice] = t "users.account.flash update success confirm needed"
|
||||
|
||||
begin
|
||||
UserMailer.email_confirm(user, user.tokens.create).deliver_later
|
||||
rescue StandardError
|
||||
# Ignore errors sending email
|
||||
end
|
||||
else
|
||||
current_user.errors.add(:new_email, current_user.errors[:email])
|
||||
current_user.errors.add(:email, [])
|
||||
end
|
||||
|
||||
user.restore_email!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# require that the user in the URL is the logged in user
|
||||
def require_self
|
||||
head :forbidden if params[:display_name] != current_user.display_name
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "user" instance variable
|
||||
def lookup_user_by_name
|
||||
|
|
|
@ -47,11 +47,10 @@ module BrowseTagsHelper
|
|||
# the correct page.
|
||||
lookup_us = lookup.tr(" ", "_")
|
||||
|
||||
if page = WIKI_PAGES.dig(locale, type, lookup_us)
|
||||
url = "https://wiki.openstreetmap.org/wiki/#{page}?uselang=#{locale}"
|
||||
elsif page = WIKI_PAGES.dig("en", type, lookup_us)
|
||||
url = "https://wiki.openstreetmap.org/wiki/#{page}?uselang=#{locale}"
|
||||
end
|
||||
page = WIKI_PAGES.dig(locale, type, lookup_us) ||
|
||||
WIKI_PAGES.dig("en", type, lookup_us)
|
||||
|
||||
url = "https://wiki.openstreetmap.org/wiki/#{page}?uselang=#{locale}" if page
|
||||
|
||||
url
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ module ChangesetsHelper
|
|||
end
|
||||
|
||||
def changeset_details(changeset)
|
||||
if changeset.closed_at > Time.now
|
||||
if changeset.closed_at > Time.now.utc
|
||||
action = :created
|
||||
time = time_ago_in_words(changeset.created_at, :scope => :"datetime.distance_in_words_ago")
|
||||
title = l(changeset.created_at)
|
||||
|
|
|
@ -8,7 +8,7 @@ module UserBlocksHelper
|
|||
if block.active?
|
||||
# if the block hasn't expired yet show the date, if the user just needs to login show that
|
||||
if block.needs_view?
|
||||
if block.ends_at > Time.now.getutc
|
||||
if block.ends_at > Time.now.utc
|
||||
t("user_blocks.helper.time_future_and_until_login_html", :time => friendly_date(block.ends_at))
|
||||
else
|
||||
t("user_blocks.helper.until_login")
|
||||
|
|
|
@ -58,7 +58,7 @@ module UserHelper
|
|||
|
||||
def auth_button(name, provider, options = {})
|
||||
link_to(
|
||||
image_tag("#{name}.svg", :alt => t("sessions.new.auth_providers.#{name}.alt"), :class => "rounded-lg"),
|
||||
image_tag("#{name}.svg", :alt => t("sessions.new.auth_providers.#{name}.alt"), :class => "rounded-3"),
|
||||
auth_path(options.merge(:provider => provider)),
|
||||
:method => :post,
|
||||
:class => "auth_button",
|
||||
|
|
|
@ -183,7 +183,7 @@ class UserMailer < ApplicationMailer
|
|||
end
|
||||
|
||||
def attach_project_logo
|
||||
attachments.inline["logo.png"] = File.read(Rails.root.join("app/assets/images/osm_logo_30.png"))
|
||||
attachments.inline["logo.png"] = Rails.root.join("app/assets/images/osm_logo_30.png").read
|
||||
end
|
||||
|
||||
def attach_user_avatar(user)
|
||||
|
@ -199,7 +199,7 @@ class UserMailer < ApplicationMailer
|
|||
avatar.blob.download
|
||||
end
|
||||
else
|
||||
File.read(Rails.root.join("app/assets/images/avatar_small.png"))
|
||||
Rails.root.join("app/assets/images/avatar_small.png").read
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
#
|
||||
|
||||
class AccessToken < OauthToken
|
||||
belongs_to :user
|
||||
belongs_to :client_application
|
||||
belongs_to :user, :optional => true
|
||||
belongs_to :client_application, :optional => true
|
||||
|
||||
scope :valid, -> { where(:invalidated_at => nil) }
|
||||
|
||||
|
@ -52,6 +52,6 @@ class AccessToken < OauthToken
|
|||
protected
|
||||
|
||||
def set_authorized_at
|
||||
self.authorized_at = Time.now
|
||||
self.authorized_at = Time.now.utc
|
||||
end
|
||||
end
|
||||
|
|
|
@ -44,8 +44,6 @@ class Changeset < ApplicationRecord
|
|||
|
||||
validates :id, :uniqueness => true, :presence => { :on => :update },
|
||||
:numericality => { :on => :update, :only_integer => true }
|
||||
validates :user_id, :presence => true,
|
||||
:numericality => { :only_integer => true }
|
||||
validates :num_changes, :presence => true,
|
||||
:numericality => { :only_integer => true,
|
||||
:greater_than_or_equal_to => 0 }
|
||||
|
@ -67,17 +65,17 @@ class Changeset < ApplicationRecord
|
|||
# Use a method like this, so that we can easily change how we
|
||||
# determine whether a changeset is open, without breaking code in at
|
||||
# least 6 controllers
|
||||
def is_open?
|
||||
def open?
|
||||
# a changeset is open (that is, it will accept further changes) when
|
||||
# it has not yet run out of time and its capacity is small enough.
|
||||
# note that this may not be a hard limit - due to timing changes and
|
||||
# concurrency it is possible that some changesets may be slightly
|
||||
# longer than strictly allowed or have slightly more changes in them.
|
||||
((closed_at > Time.now.getutc) && (num_changes <= MAX_ELEMENTS))
|
||||
((closed_at > Time.now.utc) && (num_changes <= MAX_ELEMENTS))
|
||||
end
|
||||
|
||||
def set_closed_time_now
|
||||
self.closed_at = Time.now.getutc if is_open?
|
||||
self.closed_at = Time.now.utc if open?
|
||||
end
|
||||
|
||||
def self.from_xml(xml, create: false)
|
||||
|
@ -97,7 +95,7 @@ class Changeset < ApplicationRecord
|
|||
def self.from_xml_node(pt, create: false)
|
||||
cs = Changeset.new
|
||||
if create
|
||||
cs.created_at = Time.now.getutc
|
||||
cs.created_at = Time.now.utc
|
||||
# initial close time is 1h ahead, but will be increased on each
|
||||
# modification.
|
||||
cs.closed_at = cs.created_at + IDLE_TIMEOUT
|
||||
|
@ -122,7 +120,7 @@ class Changeset < ApplicationRecord
|
|||
@bbox ||= BoundingBox.new(min_lon, min_lat, max_lon, max_lat)
|
||||
end
|
||||
|
||||
def has_valid_bbox?
|
||||
def bbox_valid?
|
||||
bbox.complete?
|
||||
end
|
||||
|
||||
|
@ -189,11 +187,11 @@ class Changeset < ApplicationRecord
|
|||
# that would make it more than 24h long, in which case clip to
|
||||
# 24h, as this has been decided is a reasonable time limit.
|
||||
def update_closed_at
|
||||
if is_open?
|
||||
if open?
|
||||
self.closed_at = if (closed_at - created_at) > (MAX_TIME_OPEN - IDLE_TIMEOUT)
|
||||
created_at + MAX_TIME_OPEN
|
||||
else
|
||||
Time.now.getutc + IDLE_TIMEOUT
|
||||
Time.now.utc + IDLE_TIMEOUT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -207,7 +205,7 @@ class Changeset < ApplicationRecord
|
|||
raise OSM::APIUserChangesetMismatchError unless user.id == user_id
|
||||
|
||||
# can't change a closed changeset
|
||||
raise OSM::APIChangesetAlreadyClosedError, self unless is_open?
|
||||
raise OSM::APIChangesetAlreadyClosedError, self unless open?
|
||||
|
||||
# copy the other's tags
|
||||
self.tags = other.tags
|
||||
|
|
|
@ -25,8 +25,8 @@ class ChangesetComment < ApplicationRecord
|
|||
|
||||
validates :id, :uniqueness => true, :presence => { :on => :update },
|
||||
:numericality => { :on => :update, :only_integer => true }
|
||||
validates :changeset, :presence => true, :associated => true
|
||||
validates :author, :presence => true, :associated => true
|
||||
validates :changeset, :associated => true
|
||||
validates :author, :associated => true
|
||||
validates :visible, :inclusion => [true, false]
|
||||
validates :body, :characters => true
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ class ChangesetTag < ApplicationRecord
|
|||
|
||||
belongs_to :changeset
|
||||
|
||||
validates :changeset, :presence => true, :associated => true
|
||||
validates :changeset, :associated => true
|
||||
validates :k, :v, :allow_blank => true, :length => { :maximum => 255 }, :characters => true
|
||||
validates :k, :uniqueness => { :scope => :changeset_id }
|
||||
end
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#
|
||||
|
||||
class ClientApplication < ApplicationRecord
|
||||
belongs_to :user
|
||||
belongs_to :user, :optional => true
|
||||
has_many :tokens, :class_name => "OauthToken", :dependent => :delete_all
|
||||
has_many :access_tokens
|
||||
has_many :oauth2_verifiers
|
||||
|
|
|
@ -16,7 +16,7 @@ module ConsistencyValidations
|
|||
raise OSM::APIChangesetMissingError
|
||||
elsif new.changeset.user_id != user.id
|
||||
raise OSM::APIUserChangesetMismatchError
|
||||
elsif !new.changeset.is_open?
|
||||
elsif !new.changeset.open?
|
||||
raise OSM::APIChangesetAlreadyClosedError, new.changeset
|
||||
end
|
||||
end
|
||||
|
@ -27,7 +27,7 @@ module ConsistencyValidations
|
|||
raise OSM::APIChangesetMissingError
|
||||
elsif new.changeset.user_id != user.id
|
||||
raise OSM::APIUserChangesetMismatchError
|
||||
elsif !new.changeset.is_open?
|
||||
elsif !new.changeset.open?
|
||||
raise OSM::APIChangesetAlreadyClosedError, new.changeset
|
||||
end
|
||||
end
|
||||
|
@ -42,7 +42,7 @@ module ConsistencyValidations
|
|||
raise OSM::APIChangesetMissingError
|
||||
elsif user.id != changeset.user_id
|
||||
raise OSM::APIUserChangesetMismatchError
|
||||
elsif !changeset.is_open?
|
||||
elsif !changeset.open?
|
||||
raise OSM::APIChangesetAlreadyClosedError, changeset
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ module Redactable
|
|||
|
||||
def redact!(redaction)
|
||||
# check that this version isn't the current version
|
||||
raise OSM::APICannotRedactError if is_latest_version?
|
||||
raise OSM::APICannotRedactError if latest_version?
|
||||
|
||||
# make the change
|
||||
self.redaction = redaction
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
|
||||
class DiaryEntry < ApplicationRecord
|
||||
belongs_to :user, :counter_cache => true
|
||||
belongs_to :language, :foreign_key => "language_code"
|
||||
belongs_to :language, :foreign_key => "language_code", :inverse_of => :diary_entries
|
||||
|
||||
has_many :comments, -> { order(:id).preload(:user) }, :class_name => "DiaryComment"
|
||||
has_many :comments, -> { order(:id).preload(:user) }, :class_name => "DiaryComment", :inverse_of => :diary_entry
|
||||
has_many :visible_comments, -> { joins(:user).where(:visible => true, :users => { :status => %w[active confirmed] }).order(:id) }, :class_name => "DiaryComment"
|
||||
has_many :subscriptions, :class_name => "DiaryEntrySubscription"
|
||||
has_many :subscribers, :through => :subscriptions, :source => :user
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
|
||||
class Issue < ApplicationRecord
|
||||
belongs_to :reportable, :polymorphic => true
|
||||
belongs_to :reported_user, :class_name => "User"
|
||||
belongs_to :user_resolved, :class_name => "User", :foreign_key => :resolved_by
|
||||
belongs_to :user_updated, :class_name => "User", :foreign_key => :updated_by
|
||||
belongs_to :reported_user, :class_name => "User", :optional => true
|
||||
belongs_to :user_resolved, :class_name => "User", :foreign_key => :resolved_by, :optional => true
|
||||
belongs_to :user_updated, :class_name => "User", :foreign_key => :updated_by, :optional => true
|
||||
|
||||
has_many :reports, :dependent => :destroy
|
||||
has_many :comments, :class_name => "IssueComment", :dependent => :destroy
|
||||
|
@ -70,7 +70,7 @@ class Issue < ApplicationRecord
|
|||
event :resolve do
|
||||
transitions :from => :open, :to => :resolved
|
||||
after do
|
||||
self.resolved_at = Time.now.getutc
|
||||
self.resolved_at = Time.now.utc
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ class IssueComment < ApplicationRecord
|
|||
belongs_to :user
|
||||
|
||||
validates :body, :presence => true, :characters => true
|
||||
validates :user, :presence => true
|
||||
validates :issue, :presence => true
|
||||
|
||||
def body
|
||||
RichText.new("markdown", self[:body])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
class Language < ApplicationRecord
|
||||
self.primary_key = "code"
|
||||
|
||||
has_many :diary_entries, :foreign_key => "language"
|
||||
has_many :diary_entries, :foreign_key => "language", :inverse_of => :language
|
||||
|
||||
def self.load(file)
|
||||
Language.transaction do
|
||||
|
|
|
@ -29,7 +29,7 @@ class Message < ApplicationRecord
|
|||
belongs_to :recipient, :class_name => "User", :foreign_key => :to_user_id
|
||||
|
||||
validates :title, :presence => true, :utf8 => true, :length => 1..255
|
||||
validates :body, :sent_on, :sender, :recipient, :presence => true
|
||||
validates :body, :sent_on, :presence => true
|
||||
validates :title, :body, :characters => true
|
||||
|
||||
def self.from_mail(mail, from, to)
|
||||
|
|
|
@ -32,7 +32,7 @@ class Node < ApplicationRecord
|
|||
|
||||
belongs_to :changeset
|
||||
|
||||
has_many :old_nodes, -> { order(:version) }
|
||||
has_many :old_nodes, -> { order(:version) }, :inverse_of => :current_node
|
||||
|
||||
has_many :way_nodes
|
||||
has_many :ways, :through => :way_nodes
|
||||
|
@ -49,8 +49,6 @@ class Node < ApplicationRecord
|
|||
:numericality => { :on => :update, :only_integer => true }
|
||||
validates :version, :presence => true,
|
||||
:numericality => { :only_integer => true }
|
||||
validates :changeset_id, :presence => true,
|
||||
:numericality => { :only_integer => true }
|
||||
validates :latitude, :presence => true,
|
||||
:numericality => { :only_integer => true }
|
||||
validates :longitude, :presence => true,
|
||||
|
@ -206,7 +204,7 @@ class Node < ApplicationRecord
|
|||
end
|
||||
|
||||
def tags
|
||||
@tags ||= node_tags.collect { |t| [t.k, t.v] }.to_h
|
||||
@tags ||= node_tags.to_h { |t| [t.k, t.v] }
|
||||
end
|
||||
|
||||
attr_writer :tags
|
||||
|
@ -238,7 +236,7 @@ class Node < ApplicationRecord
|
|||
private
|
||||
|
||||
def save_with_history!
|
||||
t = Time.now.getutc
|
||||
t = Time.now.utc
|
||||
|
||||
self.version += 1
|
||||
self.timestamp = t
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue