diff --git a/.arcconfig b/.arcconfig deleted file mode 100644 index 4025878e91..0000000000 --- a/.arcconfig +++ /dev/null @@ -1,6 +0,0 @@ -{ - "phabricator.uri" : "https://phabricator.ushahidi.com/", - "repository.callsign" : "USH", - "unit.engine": "PhpunitTestEngine", - "unit.phpunit.binary": "bin/phpunit" -} diff --git a/.arclint b/.arclint deleted file mode 100644 index 9852814d0b..0000000000 --- a/.arclint +++ /dev/null @@ -1,51 +0,0 @@ -{ - "linters" : { - "jshint" : { - "type" : "jshint", - "include" : "(\\.js$)", - "exclude" : "@/libs/.*\\.js$@", - "jshint.jshintrc" : ".jshintrc", - "jshint.jshintignore" : ".jshintignore" - }, - "phpcs" : { - "type" : "phpcs", - "include" : "(\\.php$)", - "exclude" : "@^(application|modules|plugins|web|httpdocs|spec|migrations)/.*@", - "severity.rules" : { - "(^PHPCS\\.E\\.)" : "warning", - "(^PHPCS\\.W\\.)" : "advice" - }, - "bin" : ["/usr/local/bin/phpcs", "bin/phpcs"], - "flags" : [ - "--standard=PSR2", - "--tab-width=4" - ] - }, - "phpcs-spec" : { - "type" : "phpcs", - "include" : "(spec/.*\\.php$)", - "severity.rules" : { - "(^PHPCS\\.E\\.)" : "warning", - "(^PHPCS\\.W\\.)" : "advice" - }, - "bin" : ["/usr/local/bin/phpcs", "bin/phpcs"], - "flags" : [ - "--standard=spec/ruleset.xml", - "--tab-width=4" - ] - }, - "phpcs-migrations" : { - "type" : "phpcs", - "include" : "(migrations/.*\\.php$)", - "severity.rules" : { - "(^PHPCS\\.E\\.)" : "warning", - "(^PHPCS\\.W\\.)" : "advice" - }, - "bin" : ["/usr/local/bin/phpcs", "bin/phpcs"], - "flags" : [ - "--standard=migrations/ruleset.xml", - "--tab-width=4" - ] - } - } -} diff --git a/.coveralls.yml b/.coveralls.yml deleted file mode 100644 index 819212a26b..0000000000 --- a/.coveralls.yml +++ /dev/null @@ -1,2 +0,0 @@ -coverage_clover: coverage/* -json_path: coverage/coveralls.json diff --git a/.dockerignore b/.dockerignore index 56ebbca56e..9ed274f033 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,4 @@ Makefile -codeship-*.yml -deployment.env -deployment.env.encrypted storage/app/public/** storage/app/temp/** storage/framework/cache/** @@ -10,8 +7,11 @@ storage/framework/views/** storage/logs/** storage/passport/** -# garden.io -.garden -garden_modules -garden.yaml +# Leftover deployment secrets. The tooling that produced these is gone, but old +# working copies may still have them -- never let them into the build context. +*.aes +deployment.env +docker.env +vault.txt + error.log diff --git a/.editorconfig b/.editorconfig index ae4d693849..8f960391f6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ root = true [*] -indent_style = spaces +indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 diff --git a/.env.travis b/.env.travis deleted file mode 100644 index 0338a30797..0000000000 --- a/.env.travis +++ /dev/null @@ -1,19 +0,0 @@ -## Laravel -APP_ENV=local -APP_DEBUG=true -APP_KEY=SomeRandomKey!!!SomeRandomKey!!! -APP_TIMEZONE=UTC - -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_HOST_REPLICA=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=ushahidi -DB_USERNAME=travis -DB_PASSWORD=password - -CACHE_DRIVER=array -QUEUE_DRIVER=sync - -MEDIA_MAX_UPLOAD=1048576 - diff --git a/.gitignore b/.gitignore index c577d31101..d9a7adfe2d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,57 +9,34 @@ vendor/* bin/* !bin/tests .vagrant/* -.floo -.flooignore -.sublime-project build/* -puppet/modules -Puppetfile.lock .tmp/* +tmp/ *.vscode .env +bootstrap/gwcheck.enabled + +# Local configs generated from the tracked .dist templates (see docker/utils.sh) phpunit.xml phpspec.yml -phinx.yml -bootstrap/gwcheck.enabled +behat.yml + # Homestead / Laravel files Homestead.json Homestead.yaml -# Kohana deployment specifics -application/logs/* -application/cache/* -application/config/environments/development/*.php - -# Kohana tests -behat.yml -application/tests/behat.yml - -# Kohana app uploads -application/media/uploads/* - -# Kohana modules installed composer -system -modules/cache -modules/image -modules/unittest -modules/minion -modules/orm - -# Docker Deployment Specifics +# Leftover deployment secrets. The tooling that produced these is gone, but the +# files may still exist in old working copies -- keep ignoring them so they can +# never be committed by accident. Delete your local copies. *.aes deployment.env docker.env vault.txt -# garden.io -.garden -error.log -# Snowboard +# Snowboard (composer snowboard-v3-serve / snowboard-v5-serve) dist/* -# Garden -.garden +error.log # Test Coverage coverage diff --git a/.librarian/puppet/config b/.librarian/puppet/config deleted file mode 100644 index 3049ac6c68..0000000000 --- a/.librarian/puppet/config +++ /dev/null @@ -1,4 +0,0 @@ ---- -LIBRARIAN_PUPPET_DESTRUCTIVE: 'false' -LIBRARIAN_PUPPET_USE_V1_API: '1' -LIBRARIAN_PUPPET_PATH: puppet/modules/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 60c845439c..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,61 +0,0 @@ -#notifications: -# slack: -# secure: NxhzhKGYnZYZiWVZM4w1PlZpTy9bbmNlvbqjL+9d4PvK4hFzPwQU12CchhBPeXNGLWBHg/ti6Scn/t5XIS3YJrkk4ydWmJBht5UId8uFZ1A7GCUnNNPTt2RG55lbJJdZSj01rOGZjEQbE5RyckEjgRzhZjdZ+HsjoPaRzWIBrvE= -language: php -php: -- '7.2' -- '7.3' -env: -- coverage="--coverage" -- coverage="" -matrix: - exclude: - - php: '7.3' - env: coverage="--coverage" - fast_finish: true -cache: - directories: - - "$HOME/.composer/cache" -services: -- mysql -before_install: -- mysql -e 'CREATE DATABASE ushahidi;' -- mysql -e "SET PASSWORD FOR travis@localhost = PASSWORD('password')"; -- mysql -e "select version();" -- mysql -e "SET GLOBAL sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'" -- cp .env.travis .env -install: -- composer install --no-interaction -before_script: -- composer pre-test -- mysql -e 'SET @@GLOBAL.wait_timeout=1800' -- if [ "${coverage}" == "" ]; then (cd httpdocs/; php -S localhost:8000 -t . index.php &) fi -# Coverage -- if [ "${coverage}" != "" ]; then curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter; fi -- if [ "${coverage}" != "" ]; then chmod +x ./cc-test-reporter; fi -- if [ "${coverage}" != "" ]; then ./cc-test-reporter before-build; fi -#- if [ "${coverage}" != "" ]; then (cd httpdocs/; php -S localhost:8000 -t . coverage.php &) fi -script: -- if [ "${coverage}" == "" ]; then composer test; fi -- if [ "${coverage}" != "" ]; then composer run coverage --timeout=0; fi -- composer lint -after_success: -- if [ "${coverage}" != "" ]; then travis_retry bin/php-coveralls -v; fi -- if [ "${coverage}" != "" ]; then travis_retry ./cc-test-reporter format-coverage -t clover coverage/phpunit.xml; fi -- if [ "${coverage}" != "" ]; then travis_retry ./cc-test-reporter upload-coverage; fi - -### Deploy files now generated by Codeship -# before_deploy: -# - bin/release ${TRAVIS_TAG:-$TRAVIS_COMMIT} -# deploy: -# - provider: releases -# api_key: -# secure: C9dRB0X6/QWeKMIdDnuItGzzcJITf5oeGSd/Ry85//DawkC1nZn7yhjOFJuzOT1W8+lrmYgOtqVWaZdKuw36CEa4iooXCwDqn+6SWL1N/Q0JkJZH/pXkjSjtkfRV9iNlSRw3DF1yAcout1piqbD4BKDcAtrIf5apGQnXGzKjn/Q= -# file: build/* -# file_glob: true -# skip_cleanup: true -# on: -# repo: ushahidi/platform -# php: 5.5 -# tags: true -# all_branches: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e88b89225a..152d569e52 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,5 @@ ## Getting Involved -There are many ways to get involved with Ushahidi projects, and some of them are great even for first time contributors. If you never contributed to Open Source Software before, or need more guidance doing it, please jump in our [gitter](https://gitter.im/ushahidi/Community) channel with a clear description of what you are trying to do, and someone in there will try to help you. +There are many ways to get involved with Ushahidi projects, and some of them are great even for first time contributors. If you never contributed to Open Source Software before, or need more guidance doing it, please [open an issue](https://github.com/ushahidi/platform/issues) with a clear description of what you are trying to do, and someone will try to help you. ### You can contribute to Ushahidi projects in these areas: @@ -7,6 +7,6 @@ There are many ways to get involved with Ushahidi projects, and some of them are - **Report a bug**: If you found an issue/bug, please report it [here](https://github.com/ushahidi/platform/issues). Someone on the team will jump in to check it, try to help, and prioritize it for future development depending on the issue type. Please follow the bug report template to allow others to reproduce it easily. - **Fix a bug**: If you want to contribute a fix for a bug you or someone else found, we will be happy to review your PR and provide support. Tasks that are suggested for the community can be found by searching for the https://github.com/ushahidi/platform/labels/Community%20Task tag. Please add a comment notifying others that you will be working on a task before you start. - **Helping other users in the community**: you are welcome and encouraged to jump in and help other members of the community, either by responding to issues in github or jumping into our community channels to answer questions. -- **New features**: our features are generally driven by our product and engineering team members, but if you have a great idea, or found a user need that we have not covered, you are more than welcome to make a suggestion in the form of a github issue [here](https://github.com/ushahidi/platform/issues), or reach out to Ushahidi staff in [gitter](https://gitter.im/ushahidi/Community) +- **New features**: our features are generally driven by our product and engineering team members, but if you have a great idea, or found a user need that we have not covered, you are more than welcome to make a suggestion in the form of a github issue [here](https://github.com/ushahidi/platform/issues), or reach out to Ushahidi staff through [support](https://www.ushahidi.com/support) - **Security issues**: if you think you have found a security issue, please follow [this link where we explain our disclosure and reporting policies](https://www.ushahidi.com/security) diff --git a/Dockerfile b/Dockerfile index ef1c1f86fe..03c5574eb7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,9 @@ COPY docker-php-ext-xdebug.ini /etc/php/${PHP_MAJOR_VERSION}/fpm/conf.d WORKDIR /var/www COPY composer.json ./ COPY composer.lock ./ +# symm/gisconverter is a path-repository package (its upstream was deleted); its +# source must be in the build context before composer install can resolve it. +COPY packages ./packages RUN composer self-update --2 RUN composer install --no-autoloader --no-scripts diff --git a/Procfile b/Procfile deleted file mode 100644 index c395ac0397..0000000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: bin/heroku-php-apache2 -C apache_heroku.conf httpdocs/ diff --git a/Vagrantfile b/Vagrantfile index fd422311ef..d304fad0fd 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -7,8 +7,12 @@ require 'yaml' VAGRANTFILE_API_VERSION ||= "2" confDir = $confDir ||= File.expand_path("vendor/laravel/homestead", File.dirname(__FILE__)) +# Homestead.yml is the settings file that ships with the repo. Homestead.yaml / +# Homestead.json are gitignored, so a developer can drop one in to override it +# locally; those take precedence. homesteadYamlPath = File.expand_path("Homestead.yaml", File.dirname(__FILE__)) homesteadJsonPath = File.expand_path("Homestead.json", File.dirname(__FILE__)) +homesteadYmlPath = File.expand_path("Homestead.yml", File.dirname(__FILE__)) afterScriptPath = "after.sh" aliasesPath = "aliases" @@ -28,8 +32,10 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| settings = YAML::load(File.read(homesteadYamlPath)) elsif File.exist? homesteadJsonPath then settings = JSON.parse(File.read(homesteadJsonPath)) + elsif File.exist? homesteadYmlPath then + settings = YAML::load(File.read(homesteadYmlPath)) else - abort "Homestead settings file not found in #{confDir}" + abort "Homestead settings file not found in #{File.dirname(__FILE__)}" end # Patch around the pitfalls of the imho dreadful composer update script in Homestead diff --git a/apache_heroku.conf b/apache_heroku.conf deleted file mode 100644 index 5872a47ac9..0000000000 --- a/apache_heroku.conf +++ /dev/null @@ -1,13 +0,0 @@ -# Turn on URL rewriting -RewriteEngine On - -RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ -RewriteRule ^(.*) - [E=BASE:%1] - -RewriteCond %{ENV:REDIRECT_STATUS} ^$ -RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L] - -RewriteCond %{REQUEST_FILENAME} -f -RewriteRule .? - [L] - -RewriteRule .? %{ENV:BASE}/index.php [L] diff --git a/apiary.apib b/apiary.apib deleted file mode 100644 index 5c0da9b158..0000000000 --- a/apiary.apib +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app.json b/app.json deleted file mode 100644 index f4129abda9..0000000000 --- a/app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "Ushahidi Platform API", - "description": "The API for the Ushahidi Platform.", - "keywords": [ - "ushahidi", - "crowdmap" - ], - "website": "http://ushahidi.com", - "repository": "https://github.com/ushahidi/platform", - "logo": "https://www.ushahidi.com/uploads/about-images/ushahidi-stamp.png", - "success_url": "/", - "addons": [ - "cleardb", - "scheduler" - ] -} diff --git a/behat.yml.dist b/behat.yml.dist index d56590d1b2..e3e9e16acf 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -14,19 +14,6 @@ default: baseUrl: http://localhost:8000 # proxyUrl: localhost:8888 - Ushahidi\Tests\Integration\Bootstrap\PHPUnitFixtureContext - extensions: - Behat\MinkExtension: - default_session: laravel - base_url: http://localhost:8000 - laravel: ~ - sessions: - default: - goutte: ~ - goutte: - guzzle_parameters: - curl.options: - 3 : 8000 #CURLOPT_PORT=3 - # 10004: localhost:8888 #CURLOPT_PROXY=10004 ci: suites: default: diff --git a/codeship-services.yml b/codeship-services.yml deleted file mode 100644 index 7b8ec242c0..0000000000 --- a/codeship-services.yml +++ /dev/null @@ -1,112 +0,0 @@ -build: - build: - image: build - dockerfile_path: docker/build.Dockerfile - volumes: - - .:/var/www - - ./tmp/out:/tmp/out - cached: true - default_cache_branch: develop - -dockerimg: - build: - image: ushahidi-platform/dockerimg - dockerfile_path: Dockerfile - cached: true - command: noop - -release: - build: - image: release - dockerfile_path: docker/release.Dockerfile - volumes: - - ./tmp/out:/release - encrypted_env_file: deployment.env.encrypted - cached: true - default_cache_branch: master - -deploy: - image: ushahidi/engineering-deployer:latest - encrypted_env_file: deployment.env.encrypted - add_docker: true - environment: - AWS_REGION: us-east-1 - DEPLOYMENT_RULES_REPO: deployment-rules - DEPLOYMENT_RULES_VERSION: master - DEPLOYMENT_RULES_FILE: platform.yml - - -mysql/base: &_mysql_base - image: mariadb:10.11 - environment: - - MARIADB_DATABASE=ushahidi - - MARIADB_USER=ushahidi - - MARIADB_PASSWORD=ushahidi - - MARIADB_ROOT_PASSWORD=root -mysql-7.2: - <<: *_mysql_base -mysql-7.3: - <<: *_mysql_base - - -test/base: &_test_defaults - build: &_test_build_defaults - dockerfile_path: docker/test.Dockerfile - volumes: - - .:/var/www - environment: &_test_env_defaults - DB_PORT: 3306 - DB_DATABASE: ushahidi - DB_USERNAME: ushahidi - DB_PASSWORD: ushahidi - KOHANA_ENV: testing - extra_hosts: - - "ushahidi.dev:127.0.0.1" - cached: true - default_cache_branch: develop - -test/php-7.2: - <<: *_test_defaults - build: - <<: *_test_build_defaults - image: test-7.2 - args: - PHP_MAJOR_VERSION: "7.2" - environment: - <<: *_test_env_defaults - DB_HOST: mysql-7.2 - depends_on: - - mysql-7.2 - -test/php-7.3: - <<: *_test_defaults - build: - <<: *_test_build_defaults - image: test-7.3 - args: - PHP_MAJOR_VERSION: "7.3" - depends_on: - - mysql-7.3 - environment: - <<: *_test_env_defaults - DB_HOST: mysql-7.3 - - -aglio: - image: humangeo/aglio - volumes: - - .:/var/www - -awscli: - build: - image: awscli - dockerfile_path: docker/awscli.Dockerfile - volumes: - - .:/var/www - encrypted_env_file: deployment.env.encrypted - cached: true - -dockercfggen: - image: codeship/dockercfg-generator - add_docker: true - encrypted_env_file: docker.env.encrypted diff --git a/codeship-steps.yml b/codeship-steps.yml deleted file mode 100644 index af502cac46..0000000000 --- a/codeship-steps.yml +++ /dev/null @@ -1,28 +0,0 @@ -# run 'jet test/php-7.2 test_reporter composer run test --timeout 0' to run tests on php 7.2 -# run 'jet test/php-7.3 test_reporter composer run test --timeout 0' to run tests on php 7.2 - -- type: parallel - steps: - - name: "Bundle" - type: serial - tag: '^v[0-9]\.[0-9]+.[0-9]+(-[a-zA-Z0-9\.]+)?$' - steps: - - service: build - command: build - - service: release - command: release - - - type: serial - tag: develop - steps: - - name: "Docs (develop)" - service: aglio - command: aglio -i /var/www/docs/api/index.apib -o /var/www/docs/api/index.html - - name: "Deploy Docs (develop)" - service: awscli - command: aws s3 sync /var/www/docs/ s3://preview.ushahidi.com/platform/develop --acl public-read - - - name: "Deployment director" - service: deploy - command: CI_NAME=codeship ush-deployment-director.sh - diff --git a/composer.json b/composer.json index 1501217ede..76de729408 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,14 @@ { "type": "vcs", "url": "https://github.com/ushahidi/laravel-ckan-api" + }, + { + "comment": "Upstream symm/gisconverter was deleted from GitHub, so its dist URL 404s and composer install fails. Vendored copy, see packages/gisconverter/README.md", + "type": "path", + "url": "packages/gisconverter", + "options": { + "symlink": false + } } ], "require": { @@ -56,7 +64,6 @@ "laravel/homestead": "^11.0", "mockery/mockery": "^1.4.4", "nunomaduro/collision": "^5.10", - "php-coveralls/php-coveralls": "^2.0@dev", "php-mock/php-mock-mockery": "^1.2", "phpspec/phpspec": "~7.0", "phpunit/phpunit": "^9.0", diff --git a/composer.lock b/composer.lock index 47d3964edf..c92f432418 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "166fd0e81a81080b7acc8556f8b2cdb6", + "content-hash": "1e626a5e0816bfb40c59831f8eb3213f", "packages": [ { "name": "abraham/twitteroauth", @@ -10143,45 +10143,29 @@ }, { "name": "symm/gisconverter", - "version": "v1.0.5", - "source": { - "type": "git", - "url": "https://github.com/symm/gisconverter.git", - "reference": "21ab697b7692b891dac37c64d10c9d83d4433f80" - }, + "version": "1.0.5", "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symm/gisconverter/zipball/21ab697b7692b891dac37c64d10c9d83d4433f80", - "reference": "21ab697b7692b891dac37c64d10c9d83d4433f80", - "shasum": "" + "type": "path", + "url": "packages/gisconverter", + "reference": "c083445ee0094cf9cb2e9993dc530c685139d095" }, "require": { "php": ">=5.3.0" }, - "require-dev": { - "phpunit/phpunit": "3.7.*" - }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-0": { "Symm\\Gisconverter": "src/" } }, - "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "BSD-3-Clause" ], "description": "A php library to convert vector geometries between different formats", - "support": { - "source": "https://github.com/symm/gisconverter/tree/master" - }, - "abandoned": true, - "time": "2014-08-07T13:50:52+00:00" + "transport-options": { + "symlink": false, + "relative": true + } }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -12068,89 +12052,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "php-coveralls/php-coveralls", - "version": "v2.7.0", - "source": { - "type": "git", - "url": "https://github.com/php-coveralls/php-coveralls.git", - "reference": "b36fa4394e519dafaddc04ae03976bc65a25ba15" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/b36fa4394e519dafaddc04ae03976bc65a25ba15", - "reference": "b36fa4394e519dafaddc04ae03976bc65a25ba15", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-simplexml": "*", - "guzzlehttp/guzzle": "^6.0 || ^7.0", - "php": "^7.0 || ^8.0", - "psr/log": "^1.0 || ^2.0", - "symfony/config": "^2.1 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/console": "^2.1 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/yaml": "^2.0.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0 || ^7.0 || >=8.0 <8.5.29 || >=9.0 <9.5.23", - "sanmai/phpunit-legacy-adapter": "^6.1 || ^8.0" - }, - "suggest": { - "symfony/http-kernel": "Allows Symfony integration" - }, - "bin": [ - "bin/php-coveralls" - ], - "type": "library", - "autoload": { - "psr-4": { - "PhpCoveralls\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kitamura Satoshi", - "email": "with.no.parachute@gmail.com", - "homepage": "https://www.facebook.com/satooshi.jp", - "role": "Original creator" - }, - { - "name": "Takashi Matsuo", - "email": "tmatsuo@google.com" - }, - { - "name": "Google Inc" - }, - { - "name": "Dariusz Ruminski", - "email": "dariusz.ruminski@gmail.com", - "homepage": "https://github.com/keradus" - }, - { - "name": "Contributors", - "homepage": "https://github.com/php-coveralls/php-coveralls/graphs/contributors" - } - ], - "description": "PHP client library for Coveralls API", - "homepage": "https://github.com/php-coveralls/php-coveralls", - "keywords": [ - "ci", - "coverage", - "github", - "test" - ], - "support": { - "issues": "https://github.com/php-coveralls/php-coveralls/issues", - "source": "https://github.com/php-coveralls/php-coveralls/tree/v2.7.0" - }, - "time": "2023-11-22T10:21:01+00:00" - }, { "name": "php-mock/php-mock", "version": "2.5.0", @@ -14505,68 +14406,6 @@ ], "time": "2024-05-31T14:33:22+00:00" }, - { - "name": "symfony/stopwatch", - "version": "v5.4.40", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "0e9daf3b7c805c747638b2cc48f1649e594f9625" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/0e9daf3b7c805c747638b2cc48f1649e594f9625", - "reference": "0e9daf3b7c805c747638b2cc48f1649e594f9625", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/service-contracts": "^1|^2|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a way to profile code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.40" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T14:33:22+00:00" - }, { "name": "symfony/thanks", "version": "v1.3.0", @@ -14682,19 +14521,18 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { + "beheh/flaps": 20, "league/csv": 20, + "league/event": 20, "ohanzee/database": 20, "ushahidi/kohana-validation": 20, - "ushahidi/laravel-ckan-api": 20, - "php-coveralls/php-coveralls": 20, - "beheh/flaps": 20, - "league/event": 20 + "ushahidi/laravel-ckan-api": 20 }, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": ">=7.4 <8" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/deployment.env.encrypted b/deployment.env.encrypted deleted file mode 100644 index 623d873f1f..0000000000 --- a/deployment.env.encrypted +++ /dev/null @@ -1,2 +0,0 @@ -codeship:v2 -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 \ No newline at end of file diff --git a/docker/awscli.Dockerfile b/docker/awscli.Dockerfile deleted file mode 100644 index f813e757b5..0000000000 --- a/docker/awscli.Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM alpine:3.4 - -RUN apk add --no-cache python py-pip && \ - pip install awscli diff --git a/docker/build.Dockerfile b/docker/build.Dockerfile deleted file mode 100644 index 4d8ac3cdc0..0000000000 --- a/docker/build.Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ushahidi/php-ci:php-7.2 - -WORKDIR /var/www -COPY composer.json ./ -COPY composer.lock ./ -RUN composer install --no-autoloader --no-scripts - -COPY docker/build.run.sh /build.run.sh - -ENTRYPOINT [ "/bin/bash", "/build.run.sh" ] diff --git a/docker/build.run.sh b/docker/build.run.sh deleted file mode 100644 index 0ad0061530..0000000000 --- a/docker/build.run.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -check_vols_src() { - if [ ! -d /var/www ]; then - echo "No /var/www with code" - exit 1 - fi -} -check_vols_out() { - if [ ! -d /var/out ]; then - echo "No /var/out for output!" - exit 1 - fi -} - -# Bring in source files, taking care not to bring in useless files or overwriting useful ones -function sync { - check_vols_src - { - for f in bin/*; do - echo "- ${f}" - done - for f in modules/*; do - echo "- ${f}" - done - echo "- .git" - echo "- vendor" - echo "- tmp" - } > /tmp/rsync_exclude - rsync -ar --exclude-from=/tmp/rsync_exclude --delete-during /var/www/ ./ -} - -function run_composer_install { - composer install --no-interaction --no-scripts -} - -function bundle { - check_vols_out - local version=${GITHUB_VERSION:-${CI_BRANCH:-v0.0.0}} - DEST_DIR=/var/out ./bin/release $version -} - -sync -run_composer_install -bundle diff --git a/docker/release.Dockerfile b/docker/release.Dockerfile deleted file mode 100644 index 6e38fd8ecf..0000000000 --- a/docker/release.Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM golang:1.14 - -RUN go get github.com/ushahidi/github-release - -COPY docker/release.run.sh /release.run.sh - -ENTRYPOINT [ "/bin/bash", "/release.run.sh" ] diff --git a/docker/release.run.sh b/docker/release.run.sh deleted file mode 100644 index 9be184cae1..0000000000 --- a/docker/release.run.sh +++ /dev/null @@ -1,34 +0,0 @@ -#/bin/sh - -set -ex - -if [ -z "$GITHUB_RELEASE_TOKEN" ]; then - echo "Please provide a GITHUB_RELEASE_TOKEN environment variable!" -fi - -export GITHUB_TOKEN=$GITHUB_RELEASE_TOKEN - -GITHUB_ORG=${GITHUB_ORG:-ushahidi} -GITHUB_REPO_NAME=${GITHUB_REPO_NAME:-$CI_REPO_NAME} -GITHUB_VERSION=${GITHUB_VERSION:-$CI_BRANCH} - -ghr() { - local cmd=$1 - shift 1 - /go/bin/github-release $cmd \ - --user $GITHUB_ORG \ - --repo $GITHUB_REPO_NAME \ - $* -} - -if ghr info --tag $GITHUB_VERSION ; then - # release already exists - echo "Release already exists, leaving it alone" -else - # release has to be created - ghr release --tag $GITHUB_VERSION --name $GITHUB_VERSION -fi - -for f in $(find /release -type f); do - ghr upload --tag $GITHUB_VERSION --name $(basename $f) --file $f -done diff --git a/docker/release.sh b/docker/release.sh index e11ff72085..e8a2822ed9 100755 --- a/docker/release.sh +++ b/docker/release.sh @@ -38,11 +38,9 @@ tar -C $TMP_DIR -cf $TARFILE \ --exclude 'build' \ --exclude 'docs' \ --exclude 'storage/logs/*' \ - --exclude '.travis.yml' \ --exclude '.vagrant' \ --exclude 'tmp' \ --exclude '.env' \ - --exclude '.env.travis' \ --exclude '.git' \ --exclude '.gitbook' \ ushahidi-platform-bundle-${VERSION}/ diff --git a/docker/test.Dockerfile b/docker/test.Dockerfile deleted file mode 100644 index ceb30bc188..0000000000 --- a/docker/test.Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -ARG PHP_MAJOR_VERSION -FROM ushahidi/php-ci:php-${PHP_MAJOR_VERSION} - -WORKDIR /var/www -COPY composer.json ./ -COPY composer.lock ./ -RUN composer install --no-autoloader --no-scripts - -COPY docker/utils.sh /utils.sh -COPY docker/test.run.sh /test.run.sh - -ENTRYPOINT [ "/bin/bash", "/test.run.sh" ] diff --git a/docker/test.run.sh b/docker/test.run.sh deleted file mode 100644 index cc40f78e79..0000000000 --- a/docker/test.run.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -. `dirname $0`/utils.sh - -set -e - -sync -cp .env.testing .env -run_composer_install --no-dev --no-scripts -run_composer dumpautoload -provision_passport_keys -wait_for_mysql -composer pre-test -(cd httpdocs/; php -S localhost:8000 -t . index.php &) - -test_reporter() { - local _ret=0; - "$@" || _ret=$? - if [ $_ret -ne 0 ]; then - echo -e "\n\n* Test run failed, output of logs in application/logs follows:" - echo -e "-------------------- BEGIN LOG OUTPUT --------------------" - cat storage/logs/laravel.log - echo -e "--------------------- END LOG OUTPUT ---------------------" - return 1 - else - echo -e "\n* Successful test run" - return 0 - fi -} - -case "$1" in - test_reporter) - shift - test_reporter "$@" - ;; - *) - exec "$@" - ;; -esac diff --git a/docs/README.md b/docs/README.md index fffdbad42a..d2bb023f40 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,5 @@ # 👋 Welcome | README -[![Build Status](https://travis-ci.org/ushahidi/platform.png)](https://travis-ci.org/ushahidi/platform) [![Coverage Status](https://coveralls.io/repos/github/ushahidi/platform/badge.svg)](https://coveralls.io/github/ushahidi/platform) [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) - ![](<../.gitbook/assets/oss-welcome-banner (1) (1) (2) (2).png>) ## What is Ushahidi? diff --git a/docs/contributing-or-getting-involved/README.md b/docs/contributing-or-getting-involved/README.md index 9fd3f0da19..f0f56bb3d0 100644 --- a/docs/contributing-or-getting-involved/README.md +++ b/docs/contributing-or-getting-involved/README.md @@ -43,7 +43,7 @@ Before you start coding, read through the [Development & Code](../development-an #### 💡A note about n**ew features** -Feature development is generally driven by our product and engineering team members, but if you have a great idea or found a user need that we haven't covered, you are more than welcome to make a suggestion in the form of a GitHub issue [here](https://github.com/ushahidi/platform/issues), or reach out to Ushahidi staff in [Gitter](https://gitter.im/ushahidi/Community). +Feature development is generally driven by our product and engineering team members, but if you have a great idea or found a user need that we haven't covered, you are more than welcome to make a suggestion in the form of a GitHub issue [here](https://github.com/ushahidi/platform/issues), or reach out to Ushahidi staff through [support](https://www.ushahidi.com/support). ### 🎨 I want to contribute to Design diff --git a/docs/contributing-or-getting-involved/workflow-for-adding-code.md b/docs/contributing-or-getting-involved/workflow-for-adding-code.md index e619f0b5a8..a8f26b88e7 100644 --- a/docs/contributing-or-getting-involved/workflow-for-adding-code.md +++ b/docs/contributing-or-getting-involved/workflow-for-adding-code.md @@ -46,7 +46,7 @@ When you clone a repository, the URL you clone is always created as the "origin" ### 5. Find a feature to work on -The best way to pick a feature to work on is to say hi to Ushahidi’s developers in our community-channels in gitter/irc, let them know what you’d like to work on \(front end, back end, etc\), and chat about what could be suitable for you. You can find more info on how to contact us [here](../get-in-touch.md). +The best way to pick a feature to work on is to say hi to Ushahidi’s developers by opening an issue, let them know what you’d like to work on \(front end, back end, etc\), and chat about what could be suitable for you. You can find more info on how to contact us [here](../get-in-touch.md). Ushahidi issues \(bugs, feature requests, etc\) are in Github Issues. Find something that needs doing. diff --git a/docs/contributors-to-ushahidi.md b/docs/contributors-to-ushahidi.md index 31bb7dd124..1d8ee9f66d 100644 --- a/docs/contributors-to-ushahidi.md +++ b/docs/contributors-to-ushahidi.md @@ -10,7 +10,7 @@ _**All contributors to the Ushahidi Platform are valued by Ushahidi. Thank you t ## Note: adding yourself to this list -If you have contributed to Ushahidi Platform V3 or V4 and don't see your name in this list, please reach out to us in [https://gitter.im/ushahidi/Community](https://gitter.im/ushahidi/Community) or use the "all contributors" bot in your contribution \(ie in the ticket\) to ask the bot to add you. +If you have contributed to Ushahidi Platform V3 or V4 and don't see your name in this list, please reach out to us by [opening an issue](https://github.com/ushahidi/platform/issues) or use the "all contributors" bot in your contribution \(ie in the ticket\) to ask the bot to add you. Usage example `@all-contributors add @username for code` Usage example `@all-contributors add @username for design` Usage example `@all-contributors add @username for bug, ideas, design` diff --git a/docs/development-and-code/add-code-to-ushahidi.md b/docs/development-and-code/add-code-to-ushahidi.md index dcb5863c7a..8c6e70844a 100644 --- a/docs/development-and-code/add-code-to-ushahidi.md +++ b/docs/development-and-code/add-code-to-ushahidi.md @@ -46,7 +46,7 @@ When you clone a repository, the URL you clone is always created as the "origin" ### 5. Find a feature to work on -The best way to pick a feature to work on is to say hi to Ushahidi’s developers in our community-channels in gitter/irc, let them know what you’d like to work on \(front end, back end, etc\), and chat about what could be suitable for you. You can find more info on how to contact us [here](../get-in-touch.md). +The best way to pick a feature to work on is to say hi to Ushahidi’s developers by opening an issue, let them know what you’d like to work on \(front end, back end, etc\), and chat about what could be suitable for you. You can find more info on how to contact us [here](../get-in-touch.md). Ushahidi issues \(bugs, feature requests, etc\) are in Github Issues. Find something that needs doing. diff --git a/docs/frequently-asked-questions.md b/docs/frequently-asked-questions.md index c2239d3c31..039e3c076b 100644 --- a/docs/frequently-asked-questions.md +++ b/docs/frequently-asked-questions.md @@ -30,7 +30,7 @@ As with many things, it depends. * if you plan to modify the code in some way, follow the [Installing for production environments setup guide](development-and-code/setup\_alternatives/installing-for-production-environments.md). * If you want to deploy Ushahidi without worrying about upgrading, monitoring services, or hosting it yourself, start a new deployment in [http://ushahidi.io/create](http://ushahidi.io/create) and we will manage all the tech for you. -* If you're looking for something in between, [Contact the Ushahidi team ](http://gitter.im/ushahidi/Community)and we'll figure it out! We're always happy to chat. +* If you're looking for something in between, [contact the Ushahidi team](https://www.ushahidi.com/support) and we'll figure it out! We're always happy to chat. ### How do I install Ushahidi? @@ -73,7 +73,7 @@ First, let's identify your stack. * You have used the wrong url in the BACKEND\_URL key of your platform-client .ENV file. Check that when you access the URL in the browser + /api/v3/config it returns a valid json. It should look like this when you call the /api/v3/config endpoint for your API: [https://qa.api.ushahidi.io/api/v3/config](https://qa.api.ushahidi.io/api/v3/config) * The server is failing for some reason. If the server is failing, it will likely show an error either in the browser when you call the API URL or in the server logs, which you can see in files contained within {the\_platform\_install\_dir}/storage/logs. Check the errors in the log, as often you will see that there is a permissions error somewhere, or a directory is missing, which you can solve yourself. - When reporting issues, please note that we will need as much information as you can provide to be able to help you, so please start by checking all of the above, and then contact us with the information you found through[ the Ushahidi gitter](http://gitter.im/ushahidi/Community) channel. Including details about your development environment, what you have tried doing to solve it, what you were doing when this error occured, and your log files are critical in order for us to help you get set up. + When reporting issues, please note that we will need as much information as you can provide to be able to help you, so please start by checking all of the above, and then contact us with the information you found by [opening an issue](https://github.com/ushahidi/platform/issues). Including details about your development environment, what you have tried doing to solve it, what you were doing when this error occured, and your log files are critical in order for us to help you get set up. * Are you a developer who is only setting up the client and using ushahidi.io for the API? This is most likely an error in your .ENV file, check that your BACKEND\_URL looks like this [http://DEPLOYMENTNAME.api.ushahidi.io](http://test.api.ushahidi.io) (notice the .api after your deployment's name -- it's important!) ### I have configured the datasources but I'm not getting any posts from them. What could be wrong? @@ -98,7 +98,7 @@ If the configuration values are correct, then proceed to check the following in php artisan datasource:incoming ``` -Run the datasource:incoming task manually in the platform API directory (as the example above). It should succeed and not show any errors. If there are errors, check the logs under storage/logs to review what looks wrong. If nothing else, this will help you contact the team through[ the Ushahidi gitter](http://gitter.im/ushahidi/Community) channel with details. +Run the datasource:incoming task manually in the platform API directory (as the example above). It should succeed and not show any errors. If there are errors, check the logs under storage/logs to review what looks wrong. If nothing else, this will help you contact the team by [opening an issue](https://github.com/ushahidi/platform/issues) with details. If the incoming task worked, check if new posts are available. If they are, then this means that the problem is that the datasources work but are not being automatically fetched. Check that you have a crontab running periodically for your datasources and other tasks. @@ -117,7 +117,7 @@ MAILTO=admin@example.com ``` {% endcode %} -If after ensuring the crontab is correct and datasources run, you don't see any new posts, please get in touch through[ the Ushahidi gitter](http://gitter.im/ushahidi/Community) channel with all the details about what you tried and what you have seen, and we'll be happy to help. +If after ensuring the crontab is correct and datasources run, you don't see any new posts, please get in touch by [opening an issue](https://github.com/ushahidi/platform/issues) with all the details about what you tried and what you have seen, and we'll be happy to help. ### I am getting some sort of PHP error. @@ -175,11 +175,8 @@ Connect with the wider Ushahidi community: * Join the discussion on [our forum](http://forums.ushahidi.com/) * Sign up on the [mailing list](http://list.ushahidi.com/) -* Chat with us on: - * IRC at [#ushahidi on Freenode](http://irc/irc.freenode.net/#ushahidi) - * Gitter at [ushahidi/Community](https://gitter.im/ushahidi/community) - * [Skype](https://join.skype.com/S9t68IVKzwo8) -* Messages to any of these channels should show up on all of them! +* Open an [issue on GitHub](https://github.com/ushahidi/platform/issues) +* Reach the team through [Ushahidi support](https://www.ushahidi.com/support) ### How to get help in a different language? diff --git a/docs/get-in-touch.md b/docs/get-in-touch.md index 7e33a483b8..bea137cf09 100644 --- a/docs/get-in-touch.md +++ b/docs/get-in-touch.md @@ -4,6 +4,6 @@ Connect with the wider Ushahidi community: -* Chat with us on Gitter at [ushahidi/Community](https://gitter.im/ushahidi/community) -* Add an [issue in GitHub ](https://github.com/ushahidi/platform) +* Add an [issue in GitHub](https://github.com/ushahidi/platform/issues) +* Reach the team through [Ushahidi support](https://www.ushahidi.com/support) diff --git a/example.env b/example.env deleted file mode 100644 index af728a28cb..0000000000 --- a/example.env +++ /dev/null @@ -1,5 +0,0 @@ -DB_TYPE=MySQLi -DB_HOST=localhost -DB_NAME=database -DB_USER=username -DB_PASS=password diff --git a/garden.yaml b/garden.yaml deleted file mode 100644 index b6b88daf1d..0000000000 --- a/garden.yaml +++ /dev/null @@ -1,136 +0,0 @@ ---- -kind: Project -name: platform -environments: -- name: ush-staging - variables: - ingress-hostname: platform-dev-${local.username}-api.staging.ush.zone - v2_db_host: mysql.v2-sample-db - v2_db_user: ushahidi - v2_db_pass: ushahidi - v2_db_db: ush_v2 - providers: - - name: kubernetes - context: ush-staging-arare - namespace: platform-dev-${local.username} - buildMode: cluster-docker - clusterDocker: - enableBuildKit: true - setupIngressController: false - storage: - builder: - size: 10240 - registry: - size: 5120 - sync: - size: 5120 - nfs: - storageClass: gp2 - - ---- -kind: Module -name: platform -type: container -dockerfile: Dockerfile -exclude: - - public - - httpdocs/storage - - vendor/** - - storage/passport/** - - garden_modules/** - - bin/** - - .garden/** - - garden.yaml -# include: -# - bin/release -# - bin/update -# - bin/ushahidi -hotReload: - sync: - - source: ./app/ - target: /var/www/app/ - - source: ./src/ - target: /var/www/src/ - -services: -- name: api - ports: - - name: http - containerPort: 8080 - command: - - /bin/bash - - /entrypoint.CES.sh - - start - ingresses: - - hostname: ${var.ingress-hostname} - path: / - port: http - env: &api_env - APP_KEY: SomeRandomKey!!!SomeRandomKey!!! - DOCKERIZE_TIMEOUT: 180s - DOCKERIZE_WAIT_FOR_mysql: tcp://mysql:3306 - DOCKERIZE_WAIT_FOR_redis: tcp://redis:6379 - ENABLE_NGINX: "true" - ENABLE_PHPFPM: "true" - ENABLE_PLATFORM_TASKS: "false" - RUN_PLATFORM_MIGRATIONS: "true" - DB_CONNECTION: mysql - DB_DATABASE: ushahidi - DB_HOST: mysql - DB_PORT: 3306 - DB_USERNAME: ushahidi - DB_PASSWORD: ushahidi - REDIS_HOST: redis - REDIS_PORT: 6379 - CACHE_DRIVER: redis - QUEUE_DRIVER: redis - healthCheck: - httpGet: - path: /api/v3/config - port: http - dependencies: - - mysql - - redis - -tasks: -- name: test-integration - # optional variables: - # flags: handy examples -> --stop-on-failure, ... - # spec_filename: spec file to run tests from - artifacts: - - source: /tmp/task-log/* - env: - <<: *api_env - command: - - /bin/bash - - -c - - >- - . docker/utils.sh ; - run_composer_install ; - (cd httpdocs/; php -S localhost:8000 -t . index.php &) ; - ./bin/behat --strict --profile ci ${var.flags || ''} ${var.spec_filename || ''} - -- name: import-v2 - artifacts: - - source: /tmp/task-log/* - command: - - /bin/bash - - -c - - >- - set -x; - set; - composer install; - mkdir -p /tmp/task-log; - { ./artisan import:ushahidiv2 - --host ${local.env.V2_DB_HOST || var.v2_db_host || "mysql"} - --port ${local.env.V2_DB_PORT || var.v2_db_port || "3306"} - --user ${local.env.V2_DB_USER || var.v2_db_user || "ushahidi"} - --password ${local.env.V2_DB_PASS || var.v2_db_pass || "ushahidi"} - ${local.env.V2_DB_DB || var.v2_db_db || "ush_v2"} - 2>&1 | tee /tmp/task-log/import-v2.log ;} - env: - <<: *api_env - ARTISAN_LOG_CONSOLE: 1 - timeout: 7200 - diff --git a/garden_modules/garden.yaml b/garden_modules/garden.yaml deleted file mode 100644 index f5e6c78a7e..0000000000 --- a/garden_modules/garden.yaml +++ /dev/null @@ -1,83 +0,0 @@ ---- -kind: Module -name: mysql -description: mysql container -type: container -image: mysql:5.7 - -services: -- name: mysql - command: - - docker-entrypoint.sh - - --character-set-server=utf8mb4 - - --collation-server=utf8mb4_unicode_ci - - --general-log=1 - - --general-log-file=/tmp/queries.log - ports: - - name: mysql - containerPort: 3306 - env: &mysql_env - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: ushahidi - MYSQL_USER: ushahidi - MYSQL_PASSWORD: ushahidi - -tasks: -- name: db-dump - command: - - /bin/bash - - "-c" - - "export MYSQL_PWD=$MYSQL_PASSWORD ; mysqldump -h mysql --default-character-set=utf8mb4 --no-tablespaces --skip-add-locks -u $MYSQL_USER $MYSQL_DATABASE | gzip -c > /tmp/dump.sql.gz" - artifacts: - - source: /tmp/dump.sql.gz - target: mysql/dump.${local.env.LABEL || "default"} - env: - <<: *mysql_env - -- name: migration-dump - command: - - /bin/bash - - "-c" - - | - export MYSQL_PWD=$MYSQL_PASSWORD ; - tables_to_include() { - echo "SHOW TABLES LIKE \'form%\';" | mysql -N -h mysql -u $MYSQL_USER $MYSQL_DATABASE ; - echo "SHOW TABLES LIKE \'post_%\';" | mysql -N -h mysql -u $MYSQL_USER $MYSQL_DATABASE ; - echo "import_mappings import_source_datas media messages tags users" ; - } - - { - echo "DELETE FROM users;"; - echo "DELETE FROM contacts;"; - echo "DELETE FROM forms;"; - echo "DELETE FROM csv;"; - echo "DELETE FROM media;"; - echo "DELETE FROM messages;"; - echo "DELETE FROM notification_queue;"; - echo "DELETE FROM tags;"; - - tables_to_include | \ - xargs mysqldump -h mysql \ - --default-character-set=utf8mb4 \ - --no-tablespaces \ - --skip-add-locks \ - -u $MYSQL_USER \ - $MYSQL_DATABASE ; - } | gzip -c > /tmp/dump.sql.gz - artifacts: - - source: /tmp/migration-dump.sql.gz - target: mysql/migration-dump.${local.env.LABEL || "default"} - env: - <<: *mysql_env - ---- -kind: Module -name: redis -description: redis container -type: container -image: redis:4-alpine -services: -- name: redis - ports: - - name: redis - containerPort: 6379 diff --git a/mapping.json b/mapping.json deleted file mode 100644 index a5c7da72f2..0000000000 --- a/mapping.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "Unstructured Description", - "title": "Survey", - "Created (UTC)": "Created (UTC)", - "Updated (UTC)": "Updated (UTC)", - "Post Date (UTC)": "Post Date (UTC)", - "Contact": "Contact", - "form_id": "form_id" -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 48e341a095..0000000000 --- a/package-lock.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lockfileVersion": 1 -} diff --git a/packages/gisconverter/LICENSE.txt b/packages/gisconverter/LICENSE.txt new file mode 100644 index 0000000000..d4d62eaaec --- /dev/null +++ b/packages/gisconverter/LICENSE.txt @@ -0,0 +1,36 @@ +gisconvert.php is available under the modified bsd license, and can be used and +redistributed under the conditions of this license. A copy of modified bsd +license is included in this file. + +=============================================================================== + +Software License Agreement (BSD License) + +Copyright (c) 2010-2011, Arnaud Renevier +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Arnaud Renevier nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Parakey Inc. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/gisconverter/README.md b/packages/gisconverter/README.md new file mode 100644 index 0000000000..f78087f8dd --- /dev/null +++ b/packages/gisconverter/README.md @@ -0,0 +1,42 @@ +# symm/gisconverter (vendored) + +This is a vendored copy of [`symm/gisconverter`](https://packagist.org/packages/symm/gisconverter) +v1.0.5, at upstream commit `21ab697b7692b891dac37c64d10c9d83d4433f80`. + +## Why is this here? + +**The upstream repository no longer exists.** `github.com/symm/gisconverter` returns 404, and +the package is marked abandoned on Packagist. Packagist still serves the metadata, but the only +`dist` URL it offers points at the deleted GitHub repo, so `composer install` fails with: + +``` +Failed to download symm/gisconverter from dist: The "https://api.github.com/repos/symm/ +gisconverter/zipball/21ab697b7692b891dac37c64d10c9d83d4433f80" file could not be downloaded +(HTTP/2 404) +``` + +That made the project unbuildable from a clean checkout. There is no surviving fork to point +at, so the source is vendored here and wired up with a Composer `path` repository in the root +`composer.json`. Nothing that imports `Symm\Gisconverter\...` had to change. + +The library is load-bearing: it does the WKT geometry decoding used by `PointRepository`, +`BoundingBox`, `PostPoint`, the V5 geometry query handlers and the Twitter data source. + +## Contents + +`src/` is byte-identical to the v1.0.5 release. The upstream `composer.json` was trimmed to +what we need (dropping `require-dev`, `minimum-stability` and the `dev-master` branch alias) +and pinned with an explicit `version`, which a `path` repository requires. + +Upstream's tests, `example.php` and its (long dead) Travis config were not copied. + +## Licence + +Unchanged: modified BSD (3-clause), Copyright (c) 2010-2011 Arnaud Renevier. See `LICENSE.txt`. +BSD-3-Clause is compatible with this project's AGPL-3.0, and the copyright notice and +disclaimer are retained as that licence requires. + +## If you are replacing this + +Should a maintained fork appear, drop the `path` repository entry from the root `composer.json`, +delete this directory, and point `symm/gisconverter` at the new source. diff --git a/packages/gisconverter/composer.json b/packages/gisconverter/composer.json new file mode 100644 index 0000000000..b87e4e4fe5 --- /dev/null +++ b/packages/gisconverter/composer.json @@ -0,0 +1,14 @@ +{ + "name": "symm/gisconverter", + "description": "A php library to convert vector geometries between different formats", + "version": "1.0.5", + "license": "BSD-3-Clause", + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-0": { + "Symm\\Gisconverter": "src/" + } + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Decoders/Decoder.php b/packages/gisconverter/src/Symm/Gisconverter/Decoders/Decoder.php new file mode 100644 index 0000000000..80ddfbb5e2 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Decoders/Decoder.php @@ -0,0 +1,14 @@ +attributes(); + $lon = (string) $attributes['lon']; + $lat = (string) $attributes['lat']; + + if (!$lon or !$lat) { + throw new InvalidText(__CLASS__); + } + + return array($lon, $lat); + } + + protected static function parseTrkseg($xml) + { + $res = array(); + + foreach ($xml->children() as $elem) { + if (strtolower($elem->getName()) == "trkpt") { + $res[] = new Point(static::extractCoordinates($elem)); + } + } + + return $res; + } + + protected static function parseRte($xml) + { + $res = array(); + + foreach ($xml->children() as $elem) { + if (strtolower($elem->getName()) == "rtept") { + $res[] = new Point(static::extractCoordinates($elem)); + } + } + + return $res; + } + + protected static function parseWpt($xml) + { + return static::extractCoordinates($xml); + } + + protected static function geomFromXML($xml) + { + $nodename = strtolower($xml->getName()); + + if ($nodename == "gpx" or $nodename == "trk") { + return static::childsCollect($xml); + } + + foreach (array("Trkseg", "Rte", "Wpt") as $kml_type) { + if (strtolower($kml_type) == $xml->getName()) { + $type = $kml_type; + break; + } + } + + if (!isset($type)) { + throw new InvalidText(__CLASS__); + } + + try { + $components = call_user_func(array('static', 'parse'.$type), $xml); + } catch (InvalidText $e) { + throw new InvalidText(__CLASS__); + } catch (\Exception $e) { + throw $e; + } + + if ($type == "Trkseg" or $type == "Rte") { + $constructor = 'Symm\\Gisconverter\\Geometry\\' . 'LineString'; + } elseif ($type == "Wpt") { + $constructor = 'Symm\\Gisconverter\\Geometry\\' . 'Point'; + } + + return new $constructor($components); + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Decoders/GeoJSON.php b/packages/gisconverter/src/Symm/Gisconverter/Decoders/GeoJSON.php new file mode 100644 index 0000000000..e324225a09 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Decoders/GeoJSON.php @@ -0,0 +1,193 @@ +geometry)) { + return static::geomFromJson($json->geometry); + } + + if (!property_exists($json, "type") or !is_string($json->type)) { + throw new InvalidText(__CLASS__); + } + + $geometryTypes = array( + "Point", + "Polygon", + "MultiPoint", + "LineString", + "LinearRing", + "MultiPolygon", + "MultiLineString", + "GeometryCollection" + ); + + foreach ($geometryTypes as $json_type) { + if (strtolower($json_type) == $json->type) { + $type = $json_type; + break; + } + } + + if (!isset($type)) { + throw new InvalidText(__CLASS__); + } + + try { + $components = call_user_func(array('static', 'parse'.$type), $json); + } catch (InvalidText $e) { + throw new InvalidText(__CLASS__); + } catch (\Exception $e) { + throw $e; + } + + $constructor = 'Symm\\Gisconverter\\Geometry\\' . $type; + + return new $constructor($components); + } + + protected static function parsePoint($json) + { + if (!property_exists($json, "coordinates") or !is_array($json->coordinates)) { + throw new InvalidText(__CLASS__); + } + + return $json->coordinates; + } + + protected static function parseMultiPoint($json) + { + if (!property_exists($json, "coordinates") or !is_array($json->coordinates)) { + throw new InvalidText(__CLASS__); + } + + return array_map( + function ($coords) { + return new Point($coords); + }, + $json->coordinates + ); + } + + protected static function parseLineString($json) + { + return static::parseMultiPoint($json); + } + + protected static function parseMultiLineString($json) + { + $components = array(); + + if (!property_exists($json, "coordinates") or !is_array($json->coordinates)) { + throw new InvalidText(__CLASS__); + } + + foreach ($json->coordinates as $coordinates) { + $linecomp = array(); + + foreach ($coordinates as $coordinates) { + $linecomp[] = new Point($coordinates); + } + + $components[] = new LineString($linecomp); + } + + return $components; + } + + protected static function parseLinearRing($json) + { + return static::parseMultiPoint($json); + } + + protected static function parsePolygon($json) + { + $components = array(); + + if (!property_exists($json, "coordinates") or !is_array($json->coordinates)) { + throw new InvalidText(__CLASS__); + } + + foreach ($json->coordinates as $coordinates) { + $ringcomp = array(); + + foreach ($coordinates as $coordinates) { + $ringcomp[] = new Point($coordinates); + } + + $components[] = new LinearRing($ringcomp); + } + + return $components; + } + + protected static function parseMultiPolygon($json) + { + $components = array(); + + if (!property_exists($json, "coordinates") or !is_array($json->coordinates)) { + throw new InvalidText(__CLASS__); + } + foreach ($json->coordinates as $coordinates) { + $polycomp = array(); + + foreach ($coordinates as $coordinates) { + $ringcomp = array(); + + foreach ($coordinates as $coordinates) { + $ringcomp[] = new Point($coordinates); + } + + $polycomp[] = new LinearRing($ringcomp); + } + + $components[] = new Polygon($polycomp); + } + + return $components; + } + + protected static function parseGeometryCollection($json) + { + if (!property_exists($json, "geometries") or !is_array($json->geometries)) { + throw new InvalidText(__CLASS__); + } + + $components = array(); + + foreach ($json->geometries as $geometry) { + $components[] = static::geomFromJson($geometry); + } + + return $components; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Decoders/KML.php b/packages/gisconverter/src/Symm/Gisconverter/Decoders/KML.php new file mode 100644 index 0000000000..898f80a4fe --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Decoders/KML.php @@ -0,0 +1,146 @@ +children() as $child) { + $components[] = static::geomFromXML($child); + } + + return $components; + } + + protected static function extractCoordinates($xml) + { + $coordinates = static::childElements($xml, 'coordinates'); + + if (count($coordinates) != 1) { + throw new InvalidText(__CLASS__); + } + + return $coordinates; + } + + protected static function geomFromXML($xml) + { + $nodename = strtolower($xml->getName()); + + if ($nodename == "kml" or $nodename == "document" or $nodename == "placemark") { + return static::childsCollect($xml); + } + + foreach (array("Point", "LineString", "LinearRing", "Polygon", "MultiGeometry") as $kml_type) { + if (strtolower($kml_type) == $nodename) { + $type = $kml_type; + break; + } + } + + if (!isset($type)) { + throw new InvalidText(__CLASS__); + } + + try { + $components = call_user_func(array('static', 'parse'.$type), $xml); + } catch (InvalidText $e) { + throw new InvalidText(__CLASS__); + } catch (\Exception $e) { + throw $e; + } + + if ($type == "MultiGeometry") { + if (count($components)) { + $possibletype = $components[0]::name; + $sametype = true; + + foreach (array_slice($components, 1) as $component) { + if ($component::name != $possibletype) { + $sametype = false; + break; + } + } + + if ($sametype) { + switch ($possibletype) { + case "Point": + return new MultiPoint($components); + case "LineString": + return new MultiLineString($components); + case "Polygon": + return new MultiPolygon($components); + default: + break; + } + } + } + + return new GeometryCollection($components); + } + + $constructor = 'Symm\\Gisconverter\\Geometry\\' . $type; + + return new $constructor($components); + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Decoders/WKT.php b/packages/gisconverter/src/Symm/Gisconverter/Decoders/WKT.php new file mode 100644 index 0000000000..724a11ebec --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Decoders/WKT.php @@ -0,0 +1,122 @@ +children() as $attribute) { + $propvalue =$xmlobj->{$attribute->getName()}; + if ( $propvalue->children()->count()===0 ) { + $PlaceAttributes[strval($attribute->getName())] = strval($propvalue->__toString()); + } + } + + // Parses possible attributes using ExtendedData + if ($xmlobj->ExtendedData) { + foreach ( $xmlobj->ExtendedData->children() as $Element ) { + foreach ( $Element->children() as $attribute ) { + if($attribute->attributes()->name) $PlaceAttributes[strval($attribute->attributes()->name)] =strval($attribute->__toString()); + } + + if ( empty( $Element->displayName ) ) { + if ( $Element->attributes()->name ) $PlaceAttributes[strval($Element->attributes()->name)] =strval($Element->value); + } else { + $PlaceAttributes[strval($Element->displayName)] =strval($Element->value); + } + } + } + + $geom->setAttributes($PlaceAttributes); + + return $geom; + } + + protected static function childElements($xml, $nodename = "") + { + $nodename = strtolower($nodename); + $res = array(); + + foreach ($xml->children() as $child) { + if ($nodename) { + if (strtolower($child->getName()) == $nodename) { + array_push($res, $child); + } + } else { + array_push($res, $child); + } + } + + return $res; + } + + protected static function childsCollect($xml) + { + $components = array(); + + foreach (static::childElements($xml) as $child) { + try { + $geom = static::geomFromXML($child); + $components[] = $geom; + } catch (InvalidText $e) { + + } + } + + $ncomp = count($components); + if ($ncomp == 0) { + throw new InvalidText(__CLASS__); + } elseif ($ncomp == 1) { + return $components[0]; + } else { + return new GeometryCollection($components); + } + } + + protected static function geomFromXML($xml) + { + + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Exceptions/CustomException.php b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/CustomException.php new file mode 100644 index 0000000000..e35c42573e --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/CustomException.php @@ -0,0 +1,13 @@ +message} in {$this->file}({$this->line})\n{$this->getTraceAsString()}"; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Exceptions/InvalidFeature.php b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/InvalidFeature.php new file mode 100644 index 0000000000..055f796d28 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/InvalidFeature.php @@ -0,0 +1,11 @@ +message = "invalid feature for decoder $decoder_name" . ($text ? ": $text" : ""); + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Exceptions/InvalidText.php b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/InvalidText.php new file mode 100644 index 0000000000..b2f7c88c3d --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/InvalidText.php @@ -0,0 +1,11 @@ +message = "invalid text for decoder " . $decoder_name . ($text ? (": " . $text) : ""); + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Exceptions/OutOfRangeCoord.php b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/OutOfRangeCoord.php new file mode 100644 index 0000000000..0b5f4db6f2 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/OutOfRangeCoord.php @@ -0,0 +1,20 @@ +message = "invalid {$this->type}: $coord"; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Exceptions/OutOfRangeLat.php b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/OutOfRangeLat.php new file mode 100644 index 0000000000..2615186e12 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/OutOfRangeLat.php @@ -0,0 +1,8 @@ +message = "unavailable resource: $resource"; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Exceptions/Unimplemented.php b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/Unimplemented.php new file mode 100644 index 0000000000..7c4b61c746 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/Unimplemented.php @@ -0,0 +1,11 @@ +message = "unimplemented $message"; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Exceptions/UnimplementedMethod.php b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/UnimplementedMethod.php new file mode 100644 index 0000000000..d525f647e3 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Exceptions/UnimplementedMethod.php @@ -0,0 +1,11 @@ +message = "method {$this->class}::{$this->method}"; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/Collection.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Collection.php new file mode 100644 index 0000000000..d79beb8d0a --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Collection.php @@ -0,0 +1,64 @@ +components; + } else { + throw new \Exception("Undefined property"); + } + } + + public function toWKT() + { + $recursiveWKT = function ($geom) use (&$recursiveWKT) { + if ($geom instanceof Point) { + return "{$geom->lon} {$geom->lat}"; + } else { + return "(" . implode(',', array_map($recursiveWKT, $geom->components)). ")"; + } + }; + + return strtoupper(static::name) . call_user_func($recursiveWKT, $this); + } + + public function toGeoArray() + { + $recurviseJSON = function ($geom) use (&$recurviseJSON) { + + if ($geom instanceof Point) { + return array($geom->lon, $geom->lat); + } else { + return array_map($recurviseJSON, $geom->components); + } + }; + + return array('type' => static::name, 'coordinates' => call_user_func($recurviseJSON, $this)); + } + + public function toGeoJSON() + { + return json_encode((object) $this->toGeoArray()); + } + + public function toKML() + { + return '' . + implode( + "", + array_map( + function ($comp) { + return $comp->toKML(); + }, + $this->components + ) + ) + . ''; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/Geometry.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Geometry.php new file mode 100644 index 0000000000..cfface46e4 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Geometry.php @@ -0,0 +1,58 @@ +attributes; + } + + public function setAttributes($attributes) + { + $this->attributes = $attributes; + } + + public function toGeoArray() + { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + public function toGeoJSON() + { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + public function toKML() + { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + public function toGPX($mode = null) + { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + public function toWKT() + { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + public function equals(Geometry $geom) + { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + public function __toString() + { + return $this->toWKT(); + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/GeometryCollection.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/GeometryCollection.php new file mode 100644 index 0000000000..78e560c902 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/GeometryCollection.php @@ -0,0 +1,53 @@ +components = $components; + } + + public function toWKT() + { + return strtoupper(static::name) . + "(" . + implode( + ',', + array_map( + function ($comp) { + return $comp->toWKT(); + }, + $this->components + ) + ) . + ')'; + } + + public function toGeoArray() + { + $value = array ( + 'type' => static::name, + 'geometries' => array_map( + function ($comp) { + return $comp->toGeoArray(); + }, + $this->components + ) + ); + return $value; + } + + public function toGeoJSON() + { + return json_encode((object) $this->toGeoArray()); + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/LineString.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/LineString.php new file mode 100644 index 0000000000..9482bbc237 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/LineString.php @@ -0,0 +1,74 @@ +" . + "" . + implode( + " ", + array_map( + function ($comp) { + return "{$comp->lon},{$comp->lat}"; + }, + $this->components + ) + ) . + "" . + ""; + } + + public function toGPX($mode = null) + { + if (!$mode) { + $mode = "trkseg"; + } + + if ($mode != "trkseg" and $mode != "rte") { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + if ($mode == "trkseg") { + return '' . + implode( + "", + array_map( + function ($comp) { + return "lon}\" lat=\"{$comp->lat}\">"; + }, + $this->components + ) + ) . + ""; + } else { + return '' . + implode( + "", + array_map( + function ($comp) { + return "lon}\" lat=\"{$comp->lat}\">"; + }, + $this->components + ) + ). + ""; + } + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/LinearRing.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/LinearRing.php new file mode 100644 index 0000000000..b95517a750 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/LinearRing.php @@ -0,0 +1,104 @@ +equals($last)) { + throw new InvalidFeature(__CLASS__, "LinearRing must be closed"); + } + + parent::__construct($components); + } + public function contains(Geometry $geom) + { + if ($geom instanceof Collection) { + foreach ($geom->components as $point) { + if (!$this->contains($point)) { + return false; + } + } + + return true; + } elseif ($geom instanceof Point) { + return $this->containsPoint($geom); + } else { + throw new Unimplemented(get_class($this) . "::" . __FUNCTION__ . " for " . get_class($geom) . " geometry"); + } + } + + protected function containsPoint(Point $point) + { + /* + *PHP implementation of OpenLayers.Geometry.LinearRing.ContainsPoint algorithm + */ + $px = round($point->lon, 14); + $py = round($point->lat, 14); + + $crosses = 0; + foreach (range(0, count($this->components) - 2) as $i) { + $start = $this->components[$i]; + $x1 = round($start->lon, 14); + $y1 = round($start->lat, 14); + $end = $this->components[$i + 1]; + $x2 = round($end->lon, 14); + $y2 = round($end->lat, 14); + + if ($y1 == $y2) { + // horizontal edge + if ($py == $y1) { + // point on horizontal line + if ($x1 <= $x2 && ($px >= $x1 && $px <= $x2) || // right or vert + $x1 >= $x2 && ($px <= $x1 && $px >= $x2)) { // left or vert + // point on edge + $crosses = -1; + break; + } + } + // ignore other horizontal edges + continue; + } + + $cx = round(((($x1 - $x2) * $py) + (($x2 * $y1) - ($x1 * $y2))) / ($y1 - $y2), 14); + + if ($cx == $px) { + // point on line + if ($y1 < $y2 && ($py >= $y1 && $py <= $y2) || // upward + $y1 > $y2 && ($py <= $y1 && $py >= $y2)) { // downward + // point on edge + $crosses = -1; + break; + } + } + if ($cx <= $px) { + // no crossing to the right + continue; + } + if ($x1 != $x2 && ($cx < min($x1, $x2) || $cx > max($x1, $x2))) { + // no crossing + continue; + } + if ($y1 < $y2 && ($py >= $y1 && $py < $y2) || // upward + $y1 > $y2 && ($py < $y1 && $py >= $y2)) { // downward + $crosses++; + } + } + $contained = ($crosses == -1) ? + // on edge + 1 : + // even (out) or odd (in) + !!($crosses & 1); + + return $contained; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiLineString.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiLineString.php new file mode 100644 index 0000000000..3f2af4556e --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiLineString.php @@ -0,0 +1,19 @@ +components = $components; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiPoint.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiPoint.php new file mode 100644 index 0000000000..2f19031482 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiPoint.php @@ -0,0 +1,40 @@ +components = $components; + } + + public function equals(Geometry $geom) + { + if (get_class($geom) != get_class($this)) { + return false; + } + + if (count($this->components) != count($geom->components)) { + return false; + } + + foreach (range(0, count($this->components) - 1) as $count) { + if (!$this->components[$count]->equals($geom->components[$count])) { + return false; + } + } + + return true; + } + +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiPolygon.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiPolygon.php new file mode 100644 index 0000000000..c7732e469f --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/MultiPolygon.php @@ -0,0 +1,25 @@ +components = $components; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/Point.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Point.php new file mode 100644 index 0000000000..76f2b0173c --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Point.php @@ -0,0 +1,115 @@ +checkLon($lon)) { + throw new OutOfRangeLon($lon); + } + + if (!$this->checkLat($lat)) { + throw new OutOfRangeLat($lat); + } + + $this->lon = (float) $lon; + $this->lat = (float) $lat; + } + + public function __get($property) + { + if ($property == "lon") { + return $this->lon; + } elseif ($property == "lat") { + return $this->lat; + } else { + throw new \Exception("Undefined property"); + } + } + + public function toWKT() + { + return strtoupper(static::name) . "({$this->lon} {$this->lat})"; + } + + public function toKML() + { + return "<" . static::name . ">{$this->lon},{$this->lat}"; + } + + public function toGPX($mode = null) + { + if (!$mode) { + $mode = "wpt"; + } + + if ($mode != "wpt") { + throw new UnimplementedMethod(__FUNCTION__, get_called_class()); + } + + return "lon}\" lat=\"{$this->lat}\">"; + } + + public function toGeoArray() + { + return array ('type' => static::name, 'coordinates' => array($this->lon, $this->lat)); + } + + public function toGeoJSON() + { + return json_encode((object) $this->toGeoArray()); + } + + public function equals(Geometry $geom) + { + if (get_class($geom) != get_class($this)) { + return false; + } + + return $geom->lat == $this->lat && $geom->lon == $this->lon; + } + + private function checkLon($lon) + { + if (!is_numeric($lon)) { + return false; + } + + if ($lon < -180 || $lon > 180) { + return false; + } + + return true; + } + private function checkLat($lat) + { + if (!is_numeric($lat)) { + return false; + } + + if ($lat < -90 || $lat > 90) { + return false; + } + + return true; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Geometry/Polygon.php b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Polygon.php new file mode 100644 index 0000000000..0ff18b8b00 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Geometry/Polygon.php @@ -0,0 +1,50 @@ +contains($inner)) { + throw new InvalidFeature(__CLASS__, "Polygon inner rings must be enclosed in outer ring"); + } + } + + foreach ($components as $comp) { + if (!($comp instanceof LinearRing)) { + throw new InvalidFeature(__CLASS__, "Polygon can only contain LinearRing elements"); + } + } + + $this->components = $components; + } + + public function toKML() + { + $str = '' . + $this->components[0]->toKML() . + ''; + + $str .= implode( + "", + array_map( + function ($comp) { + return '' . $comp->toKML() . ''; + }, + array_slice($this->components, 1) + ) + ); + + return + '<' . static::name . '>' . + $str . + ''; + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Gisconverter.php b/packages/gisconverter/src/Symm/Gisconverter/Gisconverter.php new file mode 100644 index 0000000000..ce4cf14080 --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Gisconverter.php @@ -0,0 +1,107 @@ +geomFromText($text)->toGeoJSON(); + } + + public static function wktToKml($text) + { + $className = __NAMESPACE__ . '\\Decoders\\WKT'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toKML(); + } + + public static function wktToGpx($text) + { + $className = __NAMESPACE__ . '\\Decoders\\WKT'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toGPX(); + } + + public static function geojsonToWkt($text) + { + $className = __NAMESPACE__ . '\\Decoders\\GeoJSON'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toWKT(); + } + + public static function geojsonToKml($text) + { + $className = __NAMESPACE__ . '\\Decoders\\GeoJSON'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toKML(); + } + + public static function geojsonToGpx($text) + { + $className = __NAMESPACE__ . '\\Decoders\\GeoJSON'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toGPX(); + } + + public static function kmlToWkt($text) + { + $className = __NAMESPACE__ . '\\Decoders\\KML'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toWKT(); + } + + public static function kmlToGeojson($text) + { + $className = __NAMESPACE__ . '\\Decoders\\KML'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toGeoJSON(); + } + + public static function kmlToGpx($text) + { + $className = __NAMESPACE__ . '\\Decoders\\KML'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toGPX(); + } + + public static function gpxToWkt($text) + { + $className = __NAMESPACE__ . '\\Decoders\\GPX'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toWKT(); + } + + public static function gpxToGeojson($text) + { + $className = __NAMESPACE__ . '\\Decoders\\GPX'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toGeoJSON(); + } + + public static function gpxToKml($text) + { + $className = __NAMESPACE__ . '\\Decoders\\GPX'; + $decoder = new $className; + + return $decoder->geomFromText($text)->toKML(); + } +} diff --git a/packages/gisconverter/src/Symm/Gisconverter/Interfaces/DecoderInterface.php b/packages/gisconverter/src/Symm/Gisconverter/Interfaces/DecoderInterface.php new file mode 100644 index 0000000000..ea502d00eb --- /dev/null +++ b/packages/gisconverter/src/Symm/Gisconverter/Interfaces/DecoderInterface.php @@ -0,0 +1,12 @@ + - * @package Ushahidi\Application - * @copyright 2014 Ushahidi - * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) - */ - -namespace Ushahidi\Core; - -// put your code here diff --git a/src/ruleset.xml b/src/ruleset.xml index 465f0b3086..039dd2252b 100644 --- a/src/ruleset.xml +++ b/src/ruleset.xml @@ -10,6 +10,8 @@ vendor/* + + packages/* tests/spec/* migrations/* bin/* diff --git a/tests/CaptainHook/PHPCS.php b/tests/CaptainHook/PHPCS.php deleted file mode 100644 index 2f8fb303fd..0000000000 --- a/tests/CaptainHook/PHPCS.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @copyright 2013 Ushahidi - * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) - */ - -namespace Tests\CaptainHook; - -use SebastianFeldmann\CaptainHook\Config; -use SebastianFeldmann\CaptainHook\Console\IO; -use SebastianFeldmann\CaptainHook\Exception\ActionFailed; -use SebastianFeldmann\CaptainHook\Hook\Action; -use SebastianFeldmann\Cli\Processor\ProcOpen as Processor; -use SebastianFeldmann\Git\Repository; - -/** - * Class PHPCS - */ -class PHPCS implements Action -{ - /** - * Executes the action. - * - * @param \SebastianFeldmann\CaptainHook\Config $config - * @param \SebastianFeldmann\CaptainHook\Console\IO $io - * @param \SebastianFeldmann\Git\Repository $repository - * @param \SebastianFeldmann\CaptainHook\Config\Action $action - * @throws \Exception - */ - public function execute(Config $config, IO $io, Repository $repository, Config\Action $action) - { - $options = $action->getOptions()->getAll(); - $changedPHPFiles = $repository->getIndexOperator()->getStagedFilesOfType('php'); - - // If nothing has changed, skip - if (! $changedPHPFiles) { - return; - } - - $io->write('Running PHPCS:', true, IO::VERBOSE); - - $process = new Processor(); - $result = $process->run( - 'bin/phpcs '. - implode(' ', $options). - ' '. - implode(' ', array_map('escapeshellarg', $changedPHPFiles)) - ); - - if (! $result->isSuccessful()) { - throw ActionFailed::withMessage($result->getStdOut().PHP_EOL.$result->getStdErr()); - } - - $io->write($result->getStdOut()); - } -} diff --git a/tests/Feature/V3/ExportJobAPI.php b/tests/Feature/V3/ExportJobAPI.php deleted file mode 100644 index 42abc821ce..0000000000 --- a/tests/Feature/V3/ExportJobAPI.php +++ /dev/null @@ -1,81 +0,0 @@ -withoutMiddleware(); - $this->expectsJobs(\Ushahidi\Modules\V3\Jobs\ExportPostsJob::class); - - $this - ->actingAs(new \Ushahidi\Authzn\GenericUser(['id' => 2])) - ->json('POST', '/api/v3/exports/jobs', [ - 'fields' => 'test', - 'filters' => [ - 'status' => ['published', 'draft'], - ], - 'entity_type' => 'post', - 'send_to_browser' => true, - 'send_to_hdx' => false, - 'hxl_heading_row' => ['something'], - ]); - - $this->seeStatusCode('200') - ->seeJson([ - 'fields' => ['test'], - 'filters' => [ - 'status' => ['published', 'draft'], - ], - 'entity_type' => 'post', - 'send_to_browser' => true, - 'send_to_hdx' => false, - 'hxl_heading_row' => null, - ]); - } - - /** - * Create a job - */ - public function testCreateJobWithRealDispatch() - { - $this->withoutMiddleware(); - - $this - ->actingAs(new \Ushahidi\Modules\Auth\GenericUser(['id' => 2])) - ->json('POST', '/api/v3/exports/jobs', [ - 'fields' => 'test', - 'filters' => [ - 'status' => ['published', 'draft'], - ], - 'entity_type' => 'post', - 'send_to_browser' => true, - 'send_to_hdx' => false, - 'hxl_heading_row' => ['something'], - ]); - - $this->seeStatusCode('200') - ->seeJson([ - 'fields' => ['test'], - 'filters' => [ - 'status' => ['published', 'draft'], - ], - 'entity_type' => 'post', - 'send_to_browser' => true, - 'send_to_hdx' => false, - 'hxl_heading_row' => null, - ]); - } -} diff --git a/tests/Feature/V3/ExportJobAPITest.php b/tests/Feature/V3/ExportJobAPITest.php new file mode 100644 index 0000000000..218fbb806f --- /dev/null +++ b/tests/Feature/V3/ExportJobAPITest.php @@ -0,0 +1,100 @@ + 'test', + 'filters' => [ + 'status' => ['published', 'draft'], + ], + 'entity_type' => 'post', + 'send_to_browser' => true, + 'send_to_hdx' => false, + 'hxl_heading_row' => ['something'], + ]; + + private const EXPECTED = [ + 'fields' => ['test'], + 'filters' => [ + 'status' => ['published', 'draft'], + ], + 'entity_type' => 'post', + 'send_to_browser' => true, + 'send_to_hdx' => false, + 'hxl_heading_row' => null, + ]; + + /** + * Creating an export job requires admin rights. The test owns its admin + * user rather than relying on a fixture: the behat dataset is not loaded + * for phpunit runs, and it rewrites the users table when it is. + */ + protected $adminId; + + public function setUp(): void + { + parent::setUp(); + + $faker = Faker\Factory::create(); + + $this->adminId = service('repository.user')->create(new User([ + 'email' => $faker->unique()->safeEmail, + 'realname' => 'Export Admin', + 'role' => 'admin', + ])); + } + + public function tearDown(): void + { + service('repository.user')->delete(new User(['id' => $this->adminId])); + + parent::tearDown(); + } + + private function postJob() + { + return $this->actingAs(new GenericUser(['id' => $this->adminId])) + ->json('POST', '/api/v3/exports/jobs', self::REQUEST); + } + + /** + * Create a job, asserting the export is queued rather than run inline. + */ + public function testCreateJob() + { + Bus::fake(); + + $this->withoutMiddleware(); + + $this->postJob() + ->assertStatus(200) + ->assertJson(self::EXPECTED); + + Bus::assertDispatched(ExportPostsJob::class); + } + + /** + * Create a job and let the export actually dispatch. + */ + public function testCreateJobWithRealDispatch() + { + $this->withoutMiddleware(); + + $this->postJob() + ->assertStatus(200) + ->assertJson(self::EXPECTED); + } +} diff --git a/tests/Feature/V3/WebhooksPostsUpdateAPI.php b/tests/Feature/V3/WebhooksPostsUpdateAPITest.php similarity index 59% rename from tests/Feature/V3/WebhooksPostsUpdateAPI.php rename to tests/Feature/V3/WebhooksPostsUpdateAPITest.php index d75bdead44..c7e8728706 100644 --- a/tests/Feature/V3/WebhooksPostsUpdateAPI.php +++ b/tests/Feature/V3/WebhooksPostsUpdateAPITest.php @@ -1,26 +1,21 @@ delete(new Post(['id' => $this->postId])); @@ -46,31 +41,27 @@ protected function makeSig($sharedSecret, $url, $payload) return base64_encode(hash_hmac('sha256', $data, $sharedSecret, true)); } - /** - * Get count - */ public function testUpdate() { $this->withoutMiddleware(); + $this->json('PUT', '/api/v3/webhooks/posts/'.$this->postId, [ 'title' => 'Updated', 'content' => 'Also updated', - ]); - - $this->seeStatusCode('200') - ->seeJson([ + ]) + ->assertStatus(200) + ->assertJson([ 'title' => 'Updated', 'content' => 'Also updated', ]); } /** - * Update a job + * Middleware is left enabled here: the point of the test is that a request + * carrying a valid X-Ushahidi-Signature is accepted. */ public function testUpdateWithSignature() { - // Re-enable middleware - $this->app->instance('middleware.disable', false); // Set the shared secret $originalSecret = getenv('PLATFORM_SHARED_SECRET'); putenv('PLATFORM_SHARED_SECRET=asharedsecret'); @@ -80,32 +71,23 @@ public function testUpdateWithSignature() $apiKeyId = $apiKeys->create(new ApiKey([])); $apiKey = $apiKeys->get($apiKeyId); + $url = '/api/v3/webhooks/posts/'.$this->postId.'?api_key='.$apiKey->api_key; + + $payload = [ + 'title' => 'Updated w/sig', + 'content' => 'Also updated', + ]; + // Make a signature $sig = $this->makeSig( 'asharedsecret', - $this->prepareUrlForRequest( - '/api/v3/webhooks/posts/'.$this->postId.'?api_key='.$apiKey->api_key - ), - json_encode([ - 'title' => 'Updated w/sig', - 'content' => 'Also updated', - ]) + $this->prepareUrlForRequest($url), + json_encode($payload) ); - $this->json( - 'PUT', - '/api/v3/webhooks/posts/'.$this->postId.'?api_key='.$apiKey->api_key, - [ - 'title' => 'Updated w/sig', - 'content' => 'Also updated', - ], - [ - 'X-Ushahidi-Signature' => $sig, - ] - ); - - $this->seeStatusCode('200') - ->seeJsonStructure([ + $this->json('PUT', $url, $payload, ['X-Ushahidi-Signature' => $sig]) + ->assertStatus(200) + ->assertJsonStructure([ 'id', 'user_id', 'type', @@ -116,10 +98,7 @@ public function testUpdateWithSignature() 'created', 'updated', ]) - ->seeJson([ - 'title' => 'Updated w/sig', - 'content' => 'Also updated', - ]); + ->assertJson($payload); // Clean up $apiKeys->delete($apiKey);