diff --git a/.gitbook.yaml b/.gitbook.yaml new file mode 100644 index 000000000..16680a37a --- /dev/null +++ b/.gitbook.yaml @@ -0,0 +1,3 @@ +structure: + readme: README.md + summary: SUMMARY.md diff --git a/.gitbook/assets/grafik (1).png b/.gitbook/assets/grafik (1).png new file mode 100644 index 000000000..8fabb8555 Binary files /dev/null and b/.gitbook/assets/grafik (1).png differ diff --git a/.gitbook/assets/grafik-1 (1).png b/.gitbook/assets/grafik-1 (1).png new file mode 100644 index 000000000..cc5dade55 Binary files /dev/null and b/.gitbook/assets/grafik-1 (1).png differ diff --git a/.gitbook/assets/grafik-1.png b/.gitbook/assets/grafik-1.png new file mode 100644 index 000000000..cc5dade55 Binary files /dev/null and b/.gitbook/assets/grafik-1.png differ diff --git a/.gitbook/assets/grafik-4.png b/.gitbook/assets/grafik-4.png new file mode 100644 index 000000000..dab3eef27 Binary files /dev/null and b/.gitbook/assets/grafik-4.png differ diff --git a/.gitbook/assets/grafik.png b/.gitbook/assets/grafik.png new file mode 100644 index 000000000..8fabb8555 Binary files /dev/null and b/.gitbook/assets/grafik.png differ diff --git a/.gitbook/assets/graphql-playground (1).png b/.gitbook/assets/graphql-playground (1).png new file mode 100644 index 000000000..32396a577 Binary files /dev/null and b/.gitbook/assets/graphql-playground (1).png differ diff --git a/.gitbook/assets/graphql-playground.png b/.gitbook/assets/graphql-playground.png new file mode 100644 index 000000000..32396a577 Binary files /dev/null and b/.gitbook/assets/graphql-playground.png differ diff --git a/.gitbook/assets/humanconnection (1).png b/.gitbook/assets/humanconnection (1).png new file mode 100644 index 000000000..f0576413f Binary files /dev/null and b/.gitbook/assets/humanconnection (1).png differ diff --git a/.gitbook/assets/humanconnection.png b/.gitbook/assets/humanconnection.png new file mode 100644 index 000000000..f0576413f Binary files /dev/null and b/.gitbook/assets/humanconnection.png differ diff --git a/lets_get_together_2.png b/.gitbook/assets/lets_get_together.png similarity index 100% rename from lets_get_together_2.png rename to .gitbook/assets/lets_get_together.png diff --git a/.gitbook/assets/screenshot (1).png b/.gitbook/assets/screenshot (1).png new file mode 100644 index 000000000..b4ff4b2f9 Binary files /dev/null and b/.gitbook/assets/screenshot (1).png differ diff --git a/.gitbook/assets/screenshot-neo4j-download-center-current-releases.png b/.gitbook/assets/screenshot-neo4j-download-center-current-releases.png new file mode 100644 index 000000000..8d9033864 Binary files /dev/null and b/.gitbook/assets/screenshot-neo4j-download-center-current-releases.png differ diff --git a/.gitbook/assets/screenshot-styleguide (1).png b/.gitbook/assets/screenshot-styleguide (1).png new file mode 100644 index 000000000..d8e009394 Binary files /dev/null and b/.gitbook/assets/screenshot-styleguide (1).png differ diff --git a/.gitbook/assets/screenshot-styleguide (2).png b/.gitbook/assets/screenshot-styleguide (2).png new file mode 100644 index 000000000..d8e009394 Binary files /dev/null and b/.gitbook/assets/screenshot-styleguide (2).png differ diff --git a/.gitbook/assets/screenshot-styleguide.png b/.gitbook/assets/screenshot-styleguide.png new file mode 100644 index 000000000..d8e009394 Binary files /dev/null and b/.gitbook/assets/screenshot-styleguide.png differ diff --git a/.gitbook/assets/screenshot.png b/.gitbook/assets/screenshot.png new file mode 100644 index 000000000..b4ff4b2f9 Binary files /dev/null and b/.gitbook/assets/screenshot.png differ diff --git a/.travis.yml b/.travis.yml index c858fc186..cd43b771f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ script: - docker-compose exec webapp yarn run lint - docker-compose exec webapp yarn run test --ci --verbose=false - docker-compose exec -d backend yarn run test:before:seeder - - yarn run cypress:run --record --key $CYPRESS_TOKEN + - yarn run cypress:run after_success: - wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 19f3854c1..b331a1736 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -40,7 +40,5 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4/) -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0da2958ea..01c963187 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,40 +1,39 @@ -Thanks so much for thinking of contributing to the Human Connection project, we really appreciate it! :-) +# CONTRIBUTING -### Getting Set Up +Thanks so much for thinking of contributing to the Human Connection project, we really appreciate it! :-\) -Instructions for how to install all the necessary software can be found in our [documentation](https://docs.human-connection.org/nitro/) +## Getting Set Up -We recommend that new folks should ideally work together with an existing developer. Please join our discord instance to chat with developers or just ask them in tickets in [Zenhub](https://app.zenhub.com/workspaces/human-connection-nitro-5c0154ecc699f60fc92cf11f/boards?repos=152252353): +Instructions for how to install all the necessary software can be found in our [documentation](https://docs.human-connection.org/human-connection/) + +We recommend that new folks should ideally work together with an existing developer. Please join our discord instance to chat with developers or just ask them in tickets in [Zenhub](https://app.zenhub.com/workspaces/human-connection-nitro-5c0154ecc699f60fc92cf11f/boards?repos=152252353): ![](https://dl.dropbox.com/s/vbmcihkduy9dhko/Screenshot%202019-01-03%2015.50.11.png?dl=0) Here are some general notes on our development flow: -### Development +## Development * Currently operating in two week sprints * We are using ZenHub to coordinate - - estimating time per issue is the crucial feature of [Zenhub](https://app.zenhub.com/workspaces/human-connection-nitro-5c0154ecc699f60fc92cf11f) that Github does not have - - "up-for-grabs" links to [Github project](https://github.com/orgs/Human-Connection/projects/10?card_filter_query=label%3A%22good+first+issue) - - ordering on ZenHub not necessarily reflected on github projects - + * estimating time per issue is the crucial feature of [Zenhub](https://app.zenhub.com/workspaces/human-connection-nitro-5c0154ecc699f60fc92cf11f) that Github does not have + * "up-for-grabs" links to [Github project](https://github.com/orgs/Human-Connection/projects/10?card_filter_query=label%3A"good+first+issue) + * ordering on ZenHub not necessarily reflected on github projects * AgileVentures run open pairing sessions at 10:30am UTC each week on Tuesdays and Thursdays - * Core team - - all the people who are hired by HC non-profit corporation - - you can Meet-the-team [every two weeks in German](https://human-connection.org/veranstaltungen/) and [every month in English](https://human-connection.org/en/events/). - - 9 people - - 2 core developers (Robert [@roschaefer](https://github.com/roschaefer) and Greg [@appinteractive](https://github.com/appinteractive)) - - 3 marketeers Jasi, Dennis and Sensi - - Hardy doing business development - - Martin head of IT and previously data protection officer - - Victor doing accounting and controlling - - Nicolas is the community manager (reviews content in the network) reflects community opinion back to the core team - + * all the people who are hired by HC non-profit corporation + * you can Meet-the-team [every two weeks in German](https://human-connection.org/veranstaltungen/) and [every month in English](https://human-connection.org/en/events/). + * 9 people + * 2 core developers \(Robert [@roschaefer](https://github.com/roschaefer) and Greg [@appinteractive](https://github.com/appinteractive)\) + * 3 marketeers Jasi, Dennis and Sensi + * Hardy doing business development + * Martin head of IT and previously data protection officer + * Victor doing accounting and controlling + * Nicolas is the community manager \(reviews content in the network\) reflects community opinion back to the core team * when can folks pair with Robert - - 10am UTC until 5pm UTC every working day + * 10am UTC until 5pm UTC every working day -### Philosophy +## Philosophy We practise [collective code ownership](http://www.extremeprogramming.org/rules/collective.html) rather than strong code ownership, which means that: @@ -45,28 +44,25 @@ We practise [collective code ownership](http://www.extremeprogramming.org/rules/ Everyone feel free to request merges or answers to issues from the project managers -But what do we do when waiting for merge into master (wanting to keep PRs small) - --> Robert recommends creating a pull request for each step - - programming is also about thinking about other people - empathy for your co-workers - - but what about when you are waiting for merge? - - solutions - - 1) put 2nd PR into branch that the first PR is hitting - but requires update after merging - - 2) prefer to leave exiting PR until it can be reviewed, and instead go and work on some other part of the codebase that is not impacted by the first PR +But what do we do when waiting for merge into master \(wanting to keep PRs small\) --> Robert recommends creating a pull request for each step -### Notes +* programming is also about thinking about other people - empathy for your co-workers + * but what about when you are waiting for merge? + * solutions + * 1\) put 2nd PR into branch that the first PR is hitting - but requires update after merging + * 2\) prefer to leave exiting PR until it can be reviewed, and instead go and work on some other part of the codebase that is not impacted by the first PR -question: when you want to pick a task - (find out priority) - is it in discord? is it in AV slack? --> Robert says you can always ask in discord - group channels are the best +## Notes -Robert shares: [Zenhub board](https://app.zenhub.com/workspaces/nitro-embed-5c0154ecc699f60fc92cf11f/boards?repos=112590397,152252353,152252578,157710732,163305928) -Robert says the order of tickets are preserved in ZenHub and reflect their priority (most important at the top) and so check out the current milestones +question: when you want to pick a task - \(find out priority\) - is it in discord? is it in AV slack? --> Robert says you can always ask in discord - group channels are the best -Matt - question about who can work on [ticket 100](https://app.zenhub.com/workspaces/nitro-embed-5c0154ecc699f60fc92cf11f/issues/human-connection/human-connection/100) --> Robert - in rare occasions it might be exclusive to someone with admin permissions -Robert: notes greg just pushed this today: https://github.com/Human-Connection/Nitro-Deployment +Robert shares: [Zenhub board](https://app.zenhub.com/workspaces/nitro-embed-5c0154ecc699f60fc92cf11f/boards?repos=112590397,152252353,152252578,157710732,163305928) Robert says the order of tickets are preserved in ZenHub and reflect their priority \(most important at the top\) and so check out the current milestones + +Matt - question about who can work on [ticket 100](https://app.zenhub.com/workspaces/nitro-embed-5c0154ecc699f60fc92cf11f/issues/human-connection/human-connection/100) --> Robert - in rare occasions it might be exclusive to someone with admin permissions Robert: notes greg just pushed this today: [https://github.com/Human-Connection/Nitro-Deployment](https://github.com/Human-Connection/Nitro-Deployment) Matt makes point that new stories will have to be taken off the "New Issues" and Robert says that's fine, if you don't like the first one, then you can take the next one. Volunteeers have no commitment except their own self development and their awesomeness by contributing to free and open-source software projects. Robert notes that everyone is invited to join the kickoff meetings -Robert - difference between "important" (creates a lot of value) and "beginner friendly" (easy to implement) - +Robert - difference between "important" \(creates a lot of value\) and "beginner friendly" \(easy to implement\) diff --git a/LICENSE.md b/LICENSE.md index 9d4508b38..646ae3a6d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,21 +1,12 @@ +# LICENSE + MIT License -Copyright (c) 2018 Human-Connection gGmbH +Copyright \(c\) 2018 Human-Connection gGmbH -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files \(the "Software"\), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 77ac8dd4b..3f92be96d 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,25 @@ -

- Human-Connection -

- # Human-Connection - [![Build Status](https://travis-ci.com/Human-Connection/Human-Connection.svg?branch=master)](https://travis-ci.com/Human-Connection/Human-Connection) +[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/Human-Connection/Nitro-Backend/blob/backend/LICENSE.md) +[![Discord Channel](https://img.shields.io/discord/489522408076738561.svg)](https://discord.gg/6ub73U3) -Human Connection is a free and open-source social network for active citizenship. +Human Connection is a nonprofit social, action and knowledge network that connects information to action and promotes positive local and global change in all areas of life. + +* **Social**: Interact with other people not just by commenting their posts, but by providing **Pro & Contra** arguments, give a **Versus** or ask them by integrated **Chat** or **Let's Talk** +* **Knowledge**: Read articles about interesting topics and find related posts in the **More Info** tab or by **Filtering** based on **Categories** and **Tagging** or by using the **Fulltext Search**. +* **Action**: Don't just read about how to make the world a better place, but come into **Action** by following provided suggestions on the **Action** tab provided by other people or **Organisations**. + + [![Human-Connection](.gitbook/assets/lets_get_together.png)](https://human-connection.org) **Technology Stack** -- [VueJS](https://vuejs.org/) -- [NuxtJS](https://nuxtjs.org/) -- [GraphQL](https://graphql.org/) -- [NodeJS](https://nodejs.org/en/) -- [Neo4J](https://neo4j.com/) + +* [VueJS](https://vuejs.org/) +* [NuxtJS](https://nuxtjs.org/) +* [GraphQL](https://graphql.org/) +* [NodeJS](https://nodejs.org/en/) +* [Neo4J](https://neo4j.com/) + ## Live demo @@ -22,18 +27,31 @@ Try out our deployed [staging environment](https://nitro-staging.human-connectio Logins: -| email | password | role | -| --- | --- | --- | -| `user@example.org` | 1234 | user | -| `moderator@example.org` | 1234 | moderator | -| `admin@example.org` | 1234 | admin | - +| email | password | role | +| :--- | :--- | :--- | +| `user@example.org` | 1234 | user | +| `moderator@example.org` | 1234 | moderator | +| `admin@example.org` | 1234 | admin | ## Documentation -Learn how to set up a local development environment in our [Docs](https://docs.human-connection.org/nitro). + +Learn how to set up a local development environment in our [Docs](https://docs.human-connection.org/human-connection/) :mag_right: ## Translations -Contributre translations on [lokalise.co](https://lokalise.co/public/556252725c18dd752dd546.13222042/). + +You can help translating the interface by joining us on [lokalise.co](https://lokalise.co/public/556252725c18dd752dd546.13222042/). +Thank you lokalise for providing us with a premium account :raised_hands:. ## Developer Chat -Join the open-source community on [Discord](https://discord.gg/6ub73U3). + +Join our friendly open-source community on [Discord](https://discord.gg/6ub73U3) :heart_eyes_cat: +Just introduce yourself at `#user-presentation` and mention `@@Mentor` to get you onboard :neckbeard: +Check out the [contribution guideline](./CONTRIBUTING.md), too! + + +## Attributions + +Locale Icons made by [Freepik](http://www.freepik.com/) from [www.flaticon.com](https://www.flaticon.com/) is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/) + +## License +See the [LICENSE](LICENSE.md) file for license rights and limitations (MIT). diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 000000000..7c1e41d13 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,35 @@ +# Table of contents + +* [Introduction](README.md) +* [Edit this Documentation](edit-this-documentation.md) +* [Installation](installation.md) +* [Backend](backend/README.md) + * [GraphQL](backend/graphql.md) +* [Webapp](webapp/README.md) + * [COMPONENTS](webapp/components.md) + * [PLUGINS](webapp/plugins.md) + * [STORE](webapp/store.md) + * [PAGES](webapp/pages.md) + * [ASSETS](webapp/assets.md) + * [LAYOUTS](webapp/layouts.md) + * [Styleguide](webapp/styleguide.md) + * [STATIC](webapp/static.md) + * [MIDDLEWARE](webapp/middleware.md) +* [Testing Guide](testing.md) + * [End-to-end tests](cypress/README.md) + * [Frontend tests](webapp/testing.md) + * [Backend tests](backend/testing.md) +* [Contributing](CONTRIBUTING.md) +* [Kubernetes Deployment](deployment/README.md) + * [Minikube](deployment/minikube/README.md) + * [Digital Ocean](deployment/digital-ocean/README.md) + * [Kubernetes Dashboard](deployment/digital-ocean/dashboard/README.md) + * [HTTPS](deployment/digital-ocean/https/README.md) + * [Human Connection](deployment/human-connection/README.md) + * [Volumes](deployment/volumes/README.md) + * [Neo4J DB Backup](deployment/backup.md) + * [Legacy Migration](deployment/legacy-migration/README.md) +* [Feature Specification](cypress/features.md) +* [Code of conduct](CODE_OF_CONDUCT.md) +* [License](LICENSE.md) + diff --git a/backend/.dockerignore b/backend/.dockerignore index 31f5b28f3..25a941824 100644 --- a/backend/.dockerignore +++ b/backend/.dockerignore @@ -15,7 +15,7 @@ node_modules/ scripts/ dist/ -db-migration-worker/ +maintenance-worker/ neo4j/ public/uploads/* diff --git a/backend/README.md b/backend/README.md index dd4c040e7..7c4d3a3e9 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,196 +1,152 @@ -

- Human Connection -

+# Backend -# NITRO Backend -[![Build Status](https://img.shields.io/travis/com/Human-Connection/Nitro-Backend/master.svg)](https://travis-ci.com/Human-Connection/Nitro-Backend) -[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/Human-Connection/Nitro-Backend/blob/backend/LICENSE.md) -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Backend.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Backend?ref=badge_shield) -[![Discord Channel](https://img.shields.io/discord/489522408076738561.svg)](https://discord.gg/6ub73U3) +## Installation +{% tabs %} +{% tab title="Docker" %} -> This Prototype tries to resolve the biggest hurdle of connecting -> our services together. This is not possible in a sane way using -> our current approach. -> -> With this Prototype we can explore using the combination of -> GraphQL and the Neo4j Graph Database for achieving the connected -> nature of a social graph with better development experience as we -> do not need to connect data by our own any more through weird table -> structures etc. +Run the following command to install everything through docker. -> -> #### Advantages: -> - easer data structure -> - better connected data -> - easy to achieve "recommendations" based on actions (relations) -> - more performant and better to understand API -> - better API client that uses caching -> -> We still need to evaluate the drawbacks and estimate the development -> cost of such an approach +The installation takes a bit longer on the first pass or on rebuild ... -## How to get in touch -Connect with other developers over [Discord](https://discord.gg/6ub73U3) +```bash +$ docker-compose up -## Quick Start - -### Requirements - -Node >= `v10.12.0` +# rebuild the containers for a cleanup +$ docker-compose up --build ``` - node --version +Open another terminal and create unique indices with: + +```bash +$ docker-compose exec neo4j migrate ``` -### Forking the repository -Before you start, fork the repository using the fork button above, then clone it to your local machine using `git clone https://github.com/your-username/Nitro-Backend.git` +{% endtab %} -### Installation with Docker +{% tab title="Without Docker" %} -Run: -```sh -docker-compose up - -# create indices etc. -docker-compose exec neo4j migrate - -# if you want seed data -# open another terminal and run -docker-compose exec backend yarn run db:seed -``` - -App is [running on port 4000](http://localhost:4000/) - -To wipe out your neo4j database run: -```sh -docker-compose down -v -``` - - -### Installation without Docker - -Install dependencies: +For the local installation you need a recent version of [node](https://nodejs.org/en/) +(>= `v10.12.0`) and [Neo4J](https://neo4j.com/) along with +[Apoc](https://github.com/neo4j-contrib/neo4j-apoc-procedures) plugin installed +on your system. Download [Neo4j Community Edition](https://neo4j.com/download-center/#releases) and unpack the files. Download [Neo4j Apoc](https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases) and drop the file into the `plugins` folder of the just extracted Neo4j-Server +Note that grand-stack-starter does not currently bundle a distribution of Neo4j. You can download [Neo4j Desktop](https://neo4j.com/download/) and run locally for development, spin up a [hosted Neo4j Sandbox instance](https://neo4j.com/download/), run Neo4j in one of the [many cloud options](https://neo4j.com/developer/guide-cloud-deployment/), [spin up Neo4j in a Docker container](https://neo4j.com/developer/docker/) or on Debian-based systems install [Neo4j from the Debian Repository](http://debian.neo4j.org/). Just be sure to update the Neo4j connection string and credentials accordingly in `.env`. +Start Neo4J and confirm the database is running at [http://localhost:7474](http://localhost:7474). -Start Neo4j +Now install node dependencies with [yarn](https://yarnpkg.com/en/): +```bash +$ cd backend +$ yarn install ``` -neo4j\bin\neo4j start -``` -and confirm it's running [here](http://localhost:7474) +Copy Environment Variables: +```bash +# in backend/ +$ cp .env.template .env +``` + +Configure the new files according to your needs and your local setup. + +Create unique indices with: ```bash -yarn install -# -or- -npm install +$ ./neo4j/migrate.sh ``` -Copy: -``` -cp .env.template .env -``` -Configure the file `.env` according to your needs and your local setup. - -Start the GraphQL service: - +Start the backend for development with: ```bash -yarn dev -# -or- -npm dev +$ yarn run dev ``` -And on the production machine run following: - +or start the backend in production environment with: ```bash -yarn start -# -or- -npm start +yarn run start ``` -This will start the GraphQL service (by default on localhost:4000) -where you can issue GraphQL requests or access GraphQL Playground in the browser: +{% endtab %} +{% endtabs %} -![GraphQL Playground](graphql-playground.png) +Your backend is up and running at [http://localhost:4000/](http://localhost:4000/) +This will start the GraphQL service \(by default on localhost:4000\) where you can issue GraphQL requests or access GraphQL Playground in the browser. -## Configure +![GraphQL Playground](../.gitbook/assets/graphql-playground.png) -Set your Neo4j connection string and credentials in `.env`. -For example: +You can access Neo4J through [http://localhost:7474/](http://localhost:7474/) +for an interactive `cypher` shell and a visualization of the graph. -_.env_ -```yaml -NEO4J_URI=bolt://localhost:7687 -NEO4J_USERNAME=neo4j -NEO4J_PASSWORD=letmein -``` +#### Seed Database -> You need to install APOC as a plugin for the graph you create in the neo4j desktop app! +If you want your backend to return anything else than an empty response, you +need to seed your database: -Note that grand-stack-starter does not currently bundle a distribution -of Neo4j. You can download [Neo4j Desktop](https://neo4j.com/download/) -and run locally for development, spin up a [hosted Neo4j Sandbox instance](https://neo4j.com/download/), -run Neo4j in one of the [many cloud options](https://neo4j.com/developer/guide-cloud-deployment/), -[spin up Neo4j in a Docker container](https://neo4j.com/developer/docker/) or on Debian-based systems install [Neo4j from the Debian Repository](http://debian.neo4j.org/). -Just be sure to update the Neo4j connection string and credentials accordingly in `.env`. - -## Mock API Results - -Alternatively you can just mock all responses from the api which let -you build a frontend application without running a neo4j instance. - -Just set `MOCK=true` inside `.env` or pass it on application start. - -## Seed and Reset the Database - -Optionally you can seed the GraphQL service by executing mutations that -will write sample data to the database: +{% tabs %} +{% tab title="Docker" %} +In another terminal run: ```bash -yarn run db:seed -# -or- -npm run db:seed +$ docker-compose exec backend yarn run db:seed ``` -For a reset you can use the reset script: - +To reset the database run: ```bash -yarn db:reset -# -or- -npm run db:reset +$ docker-compose exec backend yarn run db:reset +# you could also wipe out your neo4j database and delete all volumes with: +$ docker-compose down -v +``` +{% endtab %} + +{% tab title="Without Docker" %} +Run: +```bash +$ yarn run db:seed ``` -## Run Tests +To reset the database run: +```bash +$ yarn run db:reset +``` +{% endtab %} +{% endtabs %} + + +# Testing **Beware**: We have no multiple database setup at the moment. We clean the database after each test, running the tests will wipe out all your data! -Run the **_jest_** tests: + +{% tabs %} +{% tab title="Docker" %} + +Run the _**jest**_ tests: + ```bash -yarn run test -# -or- -npm run test -``` -Run the **_cucumber_** features: -```bash -yarn run test:cucumber -# -or- -npm run test:cucumber +$ docker-compose exec backend yarn run test:jest ``` -When some tests fail, try `yarn db:reset` and after that `yarn db:seed`. Then run the tests again -## Todo`s +Run the _**cucumber**_ features: -- [x] add jwt authentication -- [ ] get directives working correctly (@toLower, @auth, @role, etc.) -- [x] check if search is working -- [x] check if sorting is working -- [x] check if pagination is working -- [ ] check if upload is working (using graphql-yoga?) -- [x] evaluate middleware -- [ ] ignore Posts and Comments by blacklisted Users +```bash +$ docker-compose exec backend yarn run test:cucumber +``` +{% endtab %} -## License -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Backend.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Backend?ref=badge_large) +{% tab title="Without Docker" %} + +Run the _**jest**_ tests: + +```bash +$ yarn run test:jest +``` + +Run the _**cucumber**_ features: + +```bash +$ yarn run test:cucumber +``` + +{% endtab %} +{% endtabs %} diff --git a/backend/db-migration-worker/Dockerfile b/backend/db-migration-worker/Dockerfile deleted file mode 100644 index 865a4c330..000000000 --- a/backend/db-migration-worker/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM mongo:4 - -RUN apt-get update && apt-get -y install --no-install-recommends wget apt-transport-https \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* -RUN wget -O - https://debian.neo4j.org/neotechnology.gpg.key | apt-key add - -RUN echo 'deb https://debian.neo4j.org/repo stable/' | tee /etc/apt/sources.list.d/neo4j.list -RUN apt-get update && apt-get -y install --no-install-recommends openjdk-8-jre openssh-client neo4j rsync \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* -COPY migration ./migration -COPY migrate.sh /usr/local/bin/migrate -COPY sync_uploads.sh /usr/local/bin/sync_uploads diff --git a/backend/docker-compose.cypress.yml b/backend/docker-compose.cypress.yml deleted file mode 100644 index 3d577e638..000000000 --- a/backend/docker-compose.cypress.yml +++ /dev/null @@ -1,18 +0,0 @@ -version: "3.7" - -services: - neo4j: - environment: - - NEO4J_AUTH=none - ports: - - 7687:7687 - - 7474:7474 - backend: - ports: - - 4001:4001 - - 4123:4123 - image: humanconnection/nitro-backend:builder - build: - context: . - target: builder - command: yarn run test:cypress diff --git a/backend/docker-compose.db-migration.yml b/backend/docker-compose.db-migration.yml deleted file mode 100644 index 02f054d1b..000000000 --- a/backend/docker-compose.db-migration.yml +++ /dev/null @@ -1,36 +0,0 @@ -version: "3.7" - -services: - backend: - volumes: - - uploads:/nitro-backend/public/uploads - neo4j: - volumes: - - mongo-export:/mongo-export - environment: - - NEO4J_apoc_import_file_enabled=true - db-migration-worker: - build: - context: db-migration-worker - volumes: - - mongo-export:/mongo-export - - uploads:/uploads - - ./db-migration-worker/migration/:/migration - - ./db-migration-worker/.ssh/:/root/.ssh/ - networks: - - hc-network - depends_on: - - backend - environment: - - NEO4J_URI=bolt://neo4j:7687 - - "SSH_USERNAME=${SSH_USERNAME}" - - "SSH_HOST=${SSH_HOST}" - - "MONGODB_USERNAME=${MONGODB_USERNAME}" - - "MONGODB_PASSWORD=${MONGODB_PASSWORD}" - - "MONGODB_AUTH_DB=${MONGODB_AUTH_DB}" - - "MONGODB_DATABASE=${MONGODB_DATABASE}" - - "UPLOADS_DIRECTORY=${UPLOADS_DIRECTORY}" - -volumes: - mongo-export: - uploads: diff --git a/backend/docker-compose.override.yml b/backend/docker-compose.override.yml deleted file mode 100644 index b972c31f6..000000000 --- a/backend/docker-compose.override.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: "3.7" - -services: - backend: - image: humanconnection/nitro-backend:builder - build: - context: . - target: builder - volumes: - - .:/nitro-backend - - /nitro-backend/node_modules - command: yarn run dev - neo4j: - environment: - - NEO4J_AUTH=none - ports: - - 7687:7687 - - 7474:7474 - volumes: - - neo4j-data:/data - -volumes: - neo4j-data: diff --git a/backend/docker-compose.travis.yml b/backend/docker-compose.travis.yml deleted file mode 100644 index e1998f6dd..000000000 --- a/backend/docker-compose.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: "3.7" - -services: - neo4j: - environment: - - NEO4J_AUTH=none - ports: - - 7687:7687 - - 7474:7474 - backend: - image: humanconnection/nitro-backend:builder - build: - context: . - target: builder diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml deleted file mode 100644 index 30d102f96..000000000 --- a/backend/docker-compose.yml +++ /dev/null @@ -1,34 +0,0 @@ -version: "3.7" - -services: - backend: - image: humanconnection/nitro-backend:latest - build: - context: . - target: production - networks: - - hc-network - depends_on: - - neo4j - ports: - - 4000:4000 - environment: - - NEO4J_URI=bolt://neo4j:7687 - - GRAPHQL_PORT=4000 - - GRAPHQL_URI=http://localhost:4000 - - CLIENT_URI=http://localhost:3000 - - JWT_SECRET=b/&&7b78BF&fv/Vd - - MOCK=false - - MAPBOX_TOKEN=pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.KZ8KK9l70omjXbEkkbHGsQ - - PRIVATE_KEY_PASSPHRASE=a7dsf78sadg87ad87sfagsadg78 - - neo4j: - image: humanconnection/neo4j:latest - build: - context: neo4j - networks: - - hc-network - -networks: - hc-network: - name: hc-network diff --git a/backend/graphql.md b/backend/graphql.md new file mode 100644 index 000000000..12cc59e57 --- /dev/null +++ b/backend/graphql.md @@ -0,0 +1,18 @@ +# GraphQL with Apollo + +GraphQL is a data query language which provides an alternative to REST and ad-hoc web service architectures. It allows clients to define the structure of the data required, and exactly the same structure of the data is returned from the server. + +![GraphQL Playground](../../../.gitbook/assets/graphql-playground%20%281%29.png) + +## Middleware keeps resolvers clean + +![](../.gitbook/assets/grafik-4.png) + + +A well-organized codebase is key for the ability to maintain and easily introduce changes into an app. Figuring out the right structure for your code remains a continuous challenge - especially as an application grows and more developers are joining a project. + +A common problem in GraphQL servers is that resolvers often get cluttered with business logic, making the entire resolver system harder to understand and maintain. + +GraphQL Middleware uses the [_middleware pattern_](https://dzone.com/articles/understanding-middleware-pattern-in-expressjs) \(well-known from Express.js\) to pull out repetitive code from resolvers and execute it before or after one of your resolvers is invoked. This improves code modularity and keeps your resolvers clean and simple. + + diff --git a/backend/package.json b/backend/package.json index 2e0d7301a..7e972d0e6 100644 --- a/backend/package.json +++ b/backend/package.json @@ -11,7 +11,7 @@ "lint": "eslint src --config .eslintrc.js", "test": "run-s test:jest test:cucumber", "test:before:server": "cross-env GRAPHQL_URI=http://localhost:4123 GRAPHQL_PORT=4123 yarn run dev 2> /dev/null", - "test:before:seeder": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 DISABLED_MIDDLEWARES=permissions,activityPub yarn run dev", + "test:before:seeder": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 DISABLED_MIDDLEWARES=permissions,activityPub yarn run dev 2> /dev/null", "test:jest:cmd": "wait-on tcp:4001 tcp:4123 && jest --forceExit --detectOpenHandles --runInBand", "test:cucumber:cmd": "wait-on tcp:4001 tcp:4123 && cucumber-js --require-module @babel/register --exit test/", "test:jest:cmd:debug": "wait-on tcp:4001 tcp:4123 && node --inspect-brk ./node_modules/.bin/jest -i --forceExit --detectOpenHandles --runInBand", @@ -50,7 +50,7 @@ "graphql-custom-directives": "~0.2.14", "graphql-iso-date": "~3.6.1", "graphql-middleware": "~3.0.2", - "graphql-shield": "~5.3.2", + "graphql-shield": "~5.3.4", "graphql-tag": "~2.10.1", "graphql-yoga": "~1.17.4", "helmet": "~3.16.0", @@ -60,22 +60,22 @@ "ms": "~2.1.1", "neo4j-driver": "~1.7.3", "neo4j-graphql-js": "~2.4.2", - "node-fetch": "~2.3.0", + "node-fetch": "~2.4.1", "npm-run-all": "~4.1.5", "request": "~2.88.0", - "sanitize-html": "~1.20.0", + "sanitize-html": "~1.20.1", "slug": "~1.1.0", "trunc-html": "~1.1.2", "uuid": "~3.3.2", "wait-on": "~3.2.0" }, "devDependencies": { - "@babel/cli": "~7.2.3", - "@babel/core": "~7.4.3", + "@babel/cli": "~7.4.4", + "@babel/core": "~7.4.4", "@babel/node": "~7.2.2", "@babel/plugin-proposal-throw-expressions": "^7.2.0", - "@babel/preset-env": "~7.4.3", - "@babel/register": "~7.4.0", + "@babel/preset-env": "~7.4.4", + "@babel/register": "~7.4.4", "apollo-server-testing": "~2.4.8", "babel-core": "~7.0.0-0", "babel-eslint": "~10.0.1", @@ -84,8 +84,8 @@ "cucumber": "~5.1.0", "eslint": "~5.16.0", "eslint-config-standard": "~12.0.0", - "eslint-plugin-import": "~2.16.0", - "eslint-plugin-jest": "~22.4.1", + "eslint-plugin-import": "~2.17.2", + "eslint-plugin-jest": "~22.5.1", "eslint-plugin-node": "~8.0.1", "eslint-plugin-promise": "~4.1.1", "eslint-plugin-standard": "~4.0.0", diff --git a/backend/src/graphql-schema.js b/backend/src/graphql-schema.js index c17b967d2..bad277721 100644 --- a/backend/src/graphql-schema.js +++ b/backend/src/graphql-schema.js @@ -6,8 +6,12 @@ import statistics from './resolvers/statistics.js' import reports from './resolvers/reports.js' import posts from './resolvers/posts.js' import moderation from './resolvers/moderation.js' +import follow from './resolvers/follow.js' +import shout from './resolvers/shout.js' import rewards from './resolvers/rewards.js' +import socialMedia from './resolvers/socialMedia.js' import notifications from './resolvers/notifications' +import comments from './resolvers/comments' export const typeDefs = fs .readFileSync( @@ -19,14 +23,19 @@ export const resolvers = { Query: { ...statistics.Query, ...userManagement.Query, - ...notifications.Query + ...notifications.Query, + ...comments.Query }, Mutation: { ...userManagement.Mutation, ...reports.Mutation, ...posts.Mutation, ...moderation.Mutation, + ...follow.Mutation, + ...shout.Mutation, ...rewards.Mutation, - ...notifications.Mutation + ...socialMedia.Mutation, + ...notifications.Mutation, + ...comments.Mutation } } diff --git a/backend/src/middleware/index.js b/backend/src/middleware/index.js index 8d893a78b..4f725ef72 100644 --- a/backend/src/middleware/index.js +++ b/backend/src/middleware/index.js @@ -10,17 +10,19 @@ import permissionsMiddleware from './permissionsMiddleware' import userMiddleware from './userMiddleware' import includedFieldsMiddleware from './includedFieldsMiddleware' import orderByMiddleware from './orderByMiddleware' -import notificationsMiddleware from './notificationsMiddleware' +import validUrlMiddleware from './validUrlMiddleware' +import notificationsMiddleware from './notifications' export default schema => { let middleware = [ passwordMiddleware, dateTimeMiddleware, + validUrlMiddleware, sluggifyMiddleware, excerptMiddleware, + notificationsMiddleware, xssMiddleware, fixImageUrlsMiddleware, - notificationsMiddleware, softDeleteMiddleware, userMiddleware, includedFieldsMiddleware, diff --git a/backend/src/middleware/notifications/extractMentions.js b/backend/src/middleware/notifications/extractMentions.js new file mode 100644 index 000000000..f2b28444f --- /dev/null +++ b/backend/src/middleware/notifications/extractMentions.js @@ -0,0 +1,17 @@ +import cheerio from 'cheerio' +const ID_REGEX = /\/profile\/([\w\-.!~*'"(),]+)/g + +export default function (content) { + const $ = cheerio.load(content) + const urls = $('.mention').map((_, el) => { + return $(el).attr('href') + }).get() + const ids = [] + urls.forEach((url) => { + let match + while ((match = ID_REGEX.exec(url)) != null) { + ids.push(match[1]) + } + }) + return ids +} diff --git a/backend/src/middleware/notifications/extractMentions.spec.js b/backend/src/middleware/notifications/extractMentions.spec.js new file mode 100644 index 000000000..625b1d8fe --- /dev/null +++ b/backend/src/middleware/notifications/extractMentions.spec.js @@ -0,0 +1,46 @@ +import extractIds from './extractMentions' + +describe('extract', () => { + describe('searches through links', () => { + it('ignores links without .mention class', () => { + const content = '

Something inspirational about @bob-der-baumeister and @jenny-rostock.

' + expect(extractIds(content)).toEqual([]) + }) + + describe('given a link with .mention class', () => { + it('extracts ids', () => { + const content = '

Something inspirational about @bob-der-baumeister and @jenny-rostock.

' + expect(extractIds(content)).toEqual(['u2', 'u3']) + }) + + describe('handles links', () => { + it('with slug and id', () => { + const content = '

Something inspirational about @bob-der-baumeister and @jenny-rostock.

' + expect(extractIds(content)).toEqual(['u2', 'u3']) + }) + + it('with domains', () => { + const content = '

Something inspirational about @bob-der-baumeister and @jenny-rostock.

' + expect(extractIds(content)).toEqual(['u2', 'u3']) + }) + + it('special characters', () => { + const content = '

Something inspirational about @bob-der-baumeister and @jenny-rostock.

' + expect(extractIds(content)).toEqual(['u!*(),2', 'u.~-3']) + }) + }) + + describe('does not crash if', () => { + it('`href` contains no user id', () => { + const content = '

Something inspirational about @bob-der-baumeister and @jenny-rostock.

' + expect(extractIds(content)).toEqual([]) + }) + + it('`href` is empty or invalid', () => { + const content = '

Something inspirational about @bob-der-baumeister and @jenny-rostock.

' + expect(extractIds(content)).toEqual([]) + }) + }) + }) + }) +}) diff --git a/backend/src/middleware/notificationsMiddleware.js b/backend/src/middleware/notifications/index.js similarity index 61% rename from backend/src/middleware/notificationsMiddleware.js rename to backend/src/middleware/notifications/index.js index 30205278b..942eb588d 100644 --- a/backend/src/middleware/notificationsMiddleware.js +++ b/backend/src/middleware/notifications/index.js @@ -1,20 +1,22 @@ -import { extractSlugs } from './notifications/mentions' +import extractIds from './extractMentions' const notify = async (resolve, root, args, context, resolveInfo) => { + // extract user ids before xss-middleware removes link classes + const ids = extractIds(args.content) + const post = await resolve(root, args, context, resolveInfo) const session = context.driver.session() - const { content, id: postId } = post - const slugs = extractSlugs(content) + const { id: postId } = post const createdAt = (new Date()).toISOString() const cypher = ` - match(u:User) where u.slug in $slugs + match(u:User) where u.id in $ids match(p:Post) where p.id = $postId create(n:Notification{id: apoc.create.uuid(), read: false, createdAt: $createdAt}) merge (n)-[:NOTIFIED]->(u) merge (p)-[:NOTIFIED]->(n) ` - await session.run(cypher, { slugs, createdAt, postId }) + await session.run(cypher, { ids, createdAt, postId }) session.close() return post @@ -22,6 +24,7 @@ const notify = async (resolve, root, args, context, resolveInfo) => { export default { Mutation: { - CreatePost: notify + CreatePost: notify, + UpdatePost: notify } } diff --git a/backend/src/middleware/notifications/mentions.js b/backend/src/middleware/notifications/mentions.js deleted file mode 100644 index 137c23f1c..000000000 --- a/backend/src/middleware/notifications/mentions.js +++ /dev/null @@ -1,10 +0,0 @@ -const MENTION_REGEX = /\s@([\w_-]+)/g - -export function extractSlugs (content) { - let slugs = [] - let match - while ((match = MENTION_REGEX.exec(content)) != null) { - slugs.push(match[1]) - } - return slugs -} diff --git a/backend/src/middleware/notifications/mentions.spec.js b/backend/src/middleware/notifications/mentions.spec.js deleted file mode 100644 index f12df7f07..000000000 --- a/backend/src/middleware/notifications/mentions.spec.js +++ /dev/null @@ -1,30 +0,0 @@ -import { extractSlugs } from './mentions' - -describe('extract', () => { - describe('finds mentions in the form of', () => { - it('@user', () => { - const content = 'Hello @user' - expect(extractSlugs(content)).toEqual(['user']) - }) - - it('@user-with-dash', () => { - const content = 'Hello @user-with-dash' - expect(extractSlugs(content)).toEqual(['user-with-dash']) - }) - - it('@user.', () => { - const content = 'Hello @user.' - expect(extractSlugs(content)).toEqual(['user']) - }) - - it('@user-With-Capital-LETTERS', () => { - const content = 'Hello @user-With-Capital-LETTERS' - expect(extractSlugs(content)).toEqual(['user-With-Capital-LETTERS']) - }) - }) - - it('ignores email addresses', () => { - const content = 'Hello somebody@example.org' - expect(extractSlugs(content)).toEqual([]) - }) -}) diff --git a/backend/src/middleware/notifications/spec.js b/backend/src/middleware/notifications/spec.js new file mode 100644 index 000000000..786ee7115 --- /dev/null +++ b/backend/src/middleware/notifications/spec.js @@ -0,0 +1,124 @@ +import { GraphQLClient } from 'graphql-request' +import { host, login } from '../../jest/helpers' +import Factory from '../../seed/factories' + +const factory = Factory() +let client + +beforeEach(async () => { + await factory.create('User', { + id: 'you', + name: 'Al Capone', + slug: 'al-capone', + email: 'test@example.org', + password: '1234' + }) +}) + +afterEach(async () => { + await factory.cleanDatabase() +}) + +describe('currentUser { notifications }', () => { + const query = `query($read: Boolean) { + currentUser { + notifications(read: $read, orderBy: createdAt_desc) { + read + post { + content + } + } + } + }` + + describe('authenticated', () => { + let headers + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) + + describe('given another user', () => { + let authorClient + let authorParams + let authorHeaders + + beforeEach(async () => { + authorParams = { + email: 'author@example.org', + password: '1234', + id: 'author' + } + await factory.create('User', authorParams) + authorHeaders = await login(authorParams) + }) + + describe('who mentions me in a post', () => { + let post + const title = 'Mentioning Al Capone' + const content = 'Hey @al-capone how do you do?' + + beforeEach(async () => { + const createPostMutation = ` + mutation($title: String!, $content: String!) { + CreatePost(title: $title, content: $content) { + id + title + content + } + } + ` + authorClient = new GraphQLClient(host, { headers: authorHeaders }) + const { CreatePost } = await authorClient.request(createPostMutation, { title, content }) + post = CreatePost + }) + + it('sends you a notification', async () => { + const expectedContent = 'Hey @al-capone how do you do?' + const expected = { + currentUser: { + notifications: [ + { read: false, post: { content: expectedContent } } + ] + } + } + await expect(client.request(query, { read: false })).resolves.toEqual(expected) + }) + + describe('who mentions me again', () => { + beforeEach(async () => { + const updatedContent = `${post.content} One more mention to @al-capone` + // The response `post.content` contains a link but the XSSmiddleware + // should have the `mention` CSS class removed. I discovered this + // during development and thought: A feature not a bug! This way we + // can encode a re-mentioning of users when you edit your post or + // comment. + const createPostMutation = ` + mutation($id: ID!, $content: String!) { + UpdatePost(id: $id, content: $content) { + title + content + } + } + ` + authorClient = new GraphQLClient(host, { headers: authorHeaders }) + await authorClient.request(createPostMutation, { id: post.id, content: updatedContent }) + }) + + it('creates exactly one more notification', async () => { + const expectedContent = 'Hey @al-capone how do you do? One more mention to @al-capone' + const expected = { + currentUser: { + notifications: [ + { read: false, post: { content: expectedContent } }, + { read: false, post: { content: expectedContent } } + ] + } + } + await expect(client.request(query, { read: false })).resolves.toEqual(expected) + }) + }) + }) + }) + }) +}) diff --git a/backend/src/middleware/notificationsMiddleware.spec.js b/backend/src/middleware/notificationsMiddleware.spec.js deleted file mode 100644 index e6fc78c52..000000000 --- a/backend/src/middleware/notificationsMiddleware.spec.js +++ /dev/null @@ -1,85 +0,0 @@ -import Factory from '../seed/factories' -import { GraphQLClient } from 'graphql-request' -import { host, login } from '../jest/helpers' - -const factory = Factory() -let client - -beforeEach(async () => { - await factory.create('User', { - id: 'you', - name: 'Al Capone', - slug: 'al-capone', - email: 'test@example.org', - password: '1234' - }) -}) - -afterEach(async () => { - await factory.cleanDatabase() -}) - -describe('currentUser { notifications }', () => { - const query = `query($read: Boolean) { - currentUser { - notifications(read: $read, orderBy: createdAt_desc) { - read - post { - content - } - } - } - }` - - describe('authenticated', () => { - let headers - beforeEach(async () => { - headers = await login({ email: 'test@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) - }) - - describe('given another user', () => { - let authorClient - let authorParams - let authorHeaders - - beforeEach(async () => { - authorParams = { - email: 'author@example.org', - password: '1234', - id: 'author' - } - await factory.create('User', authorParams) - authorHeaders = await login(authorParams) - }) - - describe('who mentions me in a post', () => { - beforeEach(async () => { - const content = 'Hey @al-capone how do you do?' - const title = 'Mentioning Al Capone' - const createPostMutation = ` - mutation($title: String!, $content: String!) { - CreatePost(title: $title, content: $content) { - title - content - } - } - ` - authorClient = new GraphQLClient(host, { headers: authorHeaders }) - await authorClient.request(createPostMutation, { title, content }) - }) - - it('sends you a notification', async () => { - const expected = { - currentUser: { - notifications: [ - { read: false, post: { content: 'Hey @al-capone how do you do?' } } - ] - } - } - await expect(client.request(query, { read: false })).resolves.toEqual(expected) - }) - }) - }) - }) -}) diff --git a/backend/src/middleware/passwordMiddleware.js b/backend/src/middleware/passwordMiddleware.js index 0aff222c8..16272421a 100644 --- a/backend/src/middleware/passwordMiddleware.js +++ b/backend/src/middleware/passwordMiddleware.js @@ -11,10 +11,11 @@ export default { } }, Query: async (resolve, root, args, context, info) => { - const result = await resolve(root, args, context, info) - return walkRecursive(result, ['password'], () => { + let result = await resolve(root, args, context, info) + result = walkRecursive(result, ['password', 'privateKey'], () => { // replace password with asterisk return '*****' }) + return result } } diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 4ff334806..3688aec16 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -74,6 +74,7 @@ const permissions = shield({ UpdateBadge: isAdmin, DeleteBadge: isAdmin, AddUserBadges: isAdmin, + CreateSocialMedia: isAuthenticated, // AddBadgeRewarded: isAdmin, // RemoveBadgeRewarded: isAdmin, reward: isAdmin, @@ -85,12 +86,14 @@ const permissions = shield({ unshout: isAuthenticated, changePassword: isAuthenticated, enable: isModerator, - disable: isModerator + disable: isModerator, + CreateComment: isAuthenticated // CreateUser: allow, }, User: { email: isMyOwn, - password: isMyOwn + password: isMyOwn, + privateKey: isMyOwn } }) diff --git a/backend/src/middleware/softDeleteMiddleware.spec.js b/backend/src/middleware/softDeleteMiddleware.spec.js index 46005a4ff..f007888ed 100644 --- a/backend/src/middleware/softDeleteMiddleware.spec.js +++ b/backend/src/middleware/softDeleteMiddleware.spec.js @@ -23,21 +23,19 @@ beforeAll(async () => { ]) await Promise.all([ - factory.create('Comment', { id: 'c2', content: 'Enabled comment on public post' }) + factory.create('Comment', { id: 'c2', postId: 'p3', content: 'Enabled comment on public post' }) ]) await Promise.all([ - factory.relate('Comment', 'Author', { from: 'u1', to: 'c2' }), - factory.relate('Comment', 'Post', { from: 'c2', to: 'p3' }) + factory.relate('Comment', 'Author', { from: 'u1', to: 'c2' }) ]) const asTroll = Factory() await asTroll.authenticateAs({ email: 'troll@example.org', password: '1234' }) await asTroll.create('Post', { id: 'p2', title: 'Disabled post', content: 'This is an offensive post content', image: '/some/offensive/image.jpg', deleted: false }) - await asTroll.create('Comment', { id: 'c1', content: 'Disabled comment' }) + await asTroll.create('Comment', { id: 'c1', postId: 'p3', content: 'Disabled comment' }) await Promise.all([ - asTroll.relate('Comment', 'Author', { from: 'u2', to: 'c1' }), - asTroll.relate('Comment', 'Post', { from: 'c1', to: 'p3' }) + asTroll.relate('Comment', 'Author', { from: 'u2', to: 'c1' }) ]) const asModerator = Factory() diff --git a/backend/src/middleware/validUrlMiddleware.js b/backend/src/middleware/validUrlMiddleware.js new file mode 100644 index 000000000..37f06199c --- /dev/null +++ b/backend/src/middleware/validUrlMiddleware.js @@ -0,0 +1,18 @@ +const validURL = str => { + const isValid = str.match(/^(?:https?:\/\/)(?:[^@\n])?(?:www\.)?([^:/\n?]+)/g) + return !!isValid +} + +export default { + Mutation: { + CreateSocialMedia: async (resolve, root, args, context, info) => { + let socialMedia + if (validURL(args.url)) { + socialMedia = await resolve(root, args, context, info) + } else { + throw Error('Input is not a URL') + } + return socialMedia + } + } +} diff --git a/backend/src/resolvers/comments.js b/backend/src/resolvers/comments.js new file mode 100644 index 000000000..97b99f4ab --- /dev/null +++ b/backend/src/resolvers/comments.js @@ -0,0 +1,52 @@ +import { neo4jgraphql } from 'neo4j-graphql-js' +import { UserInputError } from 'apollo-server' + +const COMMENT_MIN_LENGTH = 1 +export default { + Query: { + CommentByPost: async (object, params, context, resolveInfo) => { + const { postId } = params + + const session = context.driver.session() + const transactionRes = await session.run(` + MATCH (comment:Comment)-[:COMMENTS]->(post:Post {id: $postId}) + RETURN comment {.id, .contentExcerpt, .createdAt} ORDER BY comment.createdAt ASC`, { + postId + }) + + session.close() + let comments = [] + transactionRes.records.map(record => { + comments.push(record.get('comment')) + }) + + return comments + } + }, + Mutation: { + CreateComment: async (object, params, context, resolveInfo) => { + const content = params.content.replace(/<(?:.|\n)*?>/gm, '').trim() + + if (!params.content || content.length < COMMENT_MIN_LENGTH) { + throw new UserInputError(`Comment must be at least ${COMMENT_MIN_LENGTH} character long!`) + } + const { postId } = params + delete params.postId + const comment = await neo4jgraphql(object, params, context, resolveInfo, false) + + const session = context.driver.session() + + await session.run(` + MATCH (post:Post {id: $postId}), (comment:Comment {id: $commentId}) + MERGE (post)<-[:COMMENTS]-(comment) + RETURN comment {.id, .content}`, { + postId, + commentId: comment.id + } + ) + session.close() + + return comment + } + } +} diff --git a/backend/src/resolvers/comments.spec.js b/backend/src/resolvers/comments.spec.js new file mode 100644 index 000000000..34a18d807 --- /dev/null +++ b/backend/src/resolvers/comments.spec.js @@ -0,0 +1,81 @@ +import Factory from '../seed/factories' +import { GraphQLClient } from 'graphql-request' +import { host, login } from '../jest/helpers' + +const factory = Factory() +let client +let variables + +beforeEach(async () => { + await factory.create('User', { + email: 'test@example.org', + password: '1234' + }) +}) + +afterEach(async () => { + await factory.cleanDatabase() +}) + +describe('CreateComment', () => { + const mutation = ` + mutation($postId: ID, $content: String!) { + CreateComment(postId: $postId, content: $content) { + id + content + } + } + ` + describe('unauthenticated', () => { + it('throws authorization error', async () => { + variables = { + postId: 'p1', + content: 'I\'m not authorised to comment' + } + client = new GraphQLClient(host) + await expect(client.request(mutation, variables)).rejects.toThrow('Not Authorised') + }) + }) + + describe('authenticated', () => { + let headers + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) + + it('creates a comment', async () => { + variables = { + postId: 'p1', + content: 'I\'m authorised to comment' + } + const expected = { + CreateComment: { + content: 'I\'m authorised to comment' + } + } + + await expect(client.request(mutation, variables)).resolves.toMatchObject(expected) + }) + + it('throw an error if an empty string is sent as content', async () => { + variables = { + postId: 'p1', + content: '

' + } + + await expect(client.request(mutation, variables)) + .rejects.toThrow('Comment must be at least 1 character long!') + }) + + it('throws an error if a comment does not contain a single character', async () => { + variables = { + postId: 'p1', + content: '

' + } + + await expect(client.request(mutation, variables)) + .rejects.toThrow('Comment must be at least 1 character long!') + }) + }) +}) diff --git a/backend/src/resolvers/follow.js b/backend/src/resolvers/follow.js new file mode 100644 index 000000000..df7b58891 --- /dev/null +++ b/backend/src/resolvers/follow.js @@ -0,0 +1,51 @@ +export default { + Mutation: { + follow: async (_object, params, context, _resolveInfo) => { + const { id, type } = params + + const session = context.driver.session() + let transactionRes = await session.run( + `MATCH (node {id: $id}), (user:User {id: $userId}) + WHERE $type IN labels(node) AND NOT $id = $userId + MERGE (user)-[relation:FOLLOWS]->(node) + RETURN COUNT(relation) > 0 as isFollowed`, + { + id, + type, + userId: context.user.id + } + ) + + const [isFollowed] = transactionRes.records.map(record => { + return record.get('isFollowed') + }) + + session.close() + + return isFollowed + }, + + unfollow: async (_object, params, context, _resolveInfo) => { + const { id, type } = params + const session = context.driver.session() + + let transactionRes = await session.run( + `MATCH (user:User {id: $userId})-[relation:FOLLOWS]->(node {id: $id}) + WHERE $type IN labels(node) + DELETE relation + RETURN COUNT(relation) > 0 as isFollowed`, + { + id, + type, + userId: context.user.id + } + ) + const [isFollowed] = transactionRes.records.map(record => { + return record.get('isFollowed') + }) + session.close() + + return isFollowed + } + } +} diff --git a/backend/src/resolvers/moderation.spec.js b/backend/src/resolvers/moderation.spec.js index dfbcac80f..f8aa6e10b 100644 --- a/backend/src/resolvers/moderation.spec.js +++ b/backend/src/resolvers/moderation.spec.js @@ -109,11 +109,11 @@ describe('disable', () => { await factory.authenticateAs({ email: 'commenter@example.org', password: '1234' }) await Promise.all([ factory.create('Post', { id: 'p3' }), - factory.create('Comment', { id: 'c47' }) + factory.create('Comment', { id: 'c47', postId: 'p3', content: 'this comment was created for this post' }) ]) + await Promise.all([ - factory.relate('Comment', 'Author', { from: 'u45', to: 'c47' }), - factory.relate('Comment', 'Post', { from: 'c47', to: 'p3' }) + factory.relate('Comment', 'Author', { from: 'u45', to: 'c47' }) ]) } }) @@ -286,8 +286,7 @@ describe('enable', () => { factory.create('Comment', { id: 'c456' }) ]) await Promise.all([ - factory.relate('Comment', 'Author', { from: 'u123', to: 'c456' }), - factory.relate('Comment', 'Post', { from: 'c456', to: 'p9' }) + factory.relate('Comment', 'Author', { from: 'u123', to: 'c456' }) ]) const disableMutation = ` diff --git a/backend/src/resolvers/rewards.js b/backend/src/resolvers/rewards.js index 6bf6ddeea..a7a8c1ab7 100644 --- a/backend/src/resolvers/rewards.js +++ b/backend/src/resolvers/rewards.js @@ -4,7 +4,7 @@ export default { const { fromBadgeId, toUserId } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (badge:Badge {id: $badgeId}), (rewardedUser:User {id: $rewardedUserId}) MERGE (badge)-[:REWARDED]->(rewardedUser) RETURN rewardedUser {.id}`, @@ -14,7 +14,7 @@ export default { } ) - const [rewardedUser] = sessionRes.records.map(record => { + const [rewardedUser] = transactionRes.records.map(record => { return record.get('rewardedUser') }) @@ -27,7 +27,7 @@ export default { const { fromBadgeId, toUserId } = params const session = context.driver.session() - let sessionRes = await session.run( + let transactionRes = await session.run( `MATCH (badge:Badge {id: $badgeId})-[reward:REWARDED]->(rewardedUser:User {id: $rewardedUserId}) DELETE reward RETURN rewardedUser {.id}`, @@ -36,7 +36,7 @@ export default { rewardedUserId: toUserId } ) - const [rewardedUser] = sessionRes.records.map(record => { + const [rewardedUser] = transactionRes.records.map(record => { return record.get('rewardedUser') }) session.close() diff --git a/backend/src/resolvers/shout.js b/backend/src/resolvers/shout.js new file mode 100644 index 000000000..69c39a3a9 --- /dev/null +++ b/backend/src/resolvers/shout.js @@ -0,0 +1,51 @@ +export default { + Mutation: { + shout: async (_object, params, context, _resolveInfo) => { + const { id, type } = params + + const session = context.driver.session() + let transactionRes = await session.run( + `MATCH (node {id: $id})<-[:WROTE]-(userWritten:User), (user:User {id: $userId}) + WHERE $type IN labels(node) AND NOT userWritten.id = $userId + MERGE (user)-[relation:SHOUTED]->(node) + RETURN COUNT(relation) > 0 as isShouted`, + { + id, + type, + userId: context.user.id + } + ) + + const [isShouted] = transactionRes.records.map(record => { + return record.get('isShouted') + }) + + session.close() + + return isShouted + }, + + unshout: async (_object, params, context, _resolveInfo) => { + const { id, type } = params + const session = context.driver.session() + + let transactionRes = await session.run( + `MATCH (user:User {id: $userId})-[relation:SHOUTED]->(node {id: $id}) + WHERE $type IN labels(node) + DELETE relation + RETURN COUNT(relation) > 0 as isShouted`, + { + id, + type, + userId: context.user.id + } + ) + const [isShouted] = transactionRes.records.map(record => { + return record.get('isShouted') + }) + session.close() + + return isShouted + } + } +} diff --git a/backend/src/resolvers/socialMedia.js b/backend/src/resolvers/socialMedia.js new file mode 100644 index 000000000..310375820 --- /dev/null +++ b/backend/src/resolvers/socialMedia.js @@ -0,0 +1,21 @@ +import { neo4jgraphql } from 'neo4j-graphql-js' + +export default { + Mutation: { + CreateSocialMedia: async (object, params, context, resolveInfo) => { + const socialMedia = await neo4jgraphql(object, params, context, resolveInfo, false) + const session = context.driver.session() + await session.run( + `MATCH (owner:User {id: $userId}), (socialMedia:SocialMedia {id: $socialMediaId}) + MERGE (socialMedia)<-[:OWNED]-(owner) + RETURN owner`, { + userId: context.user.id, + socialMediaId: socialMedia.id + } + ) + session.close() + + return socialMedia + } + } +} diff --git a/backend/src/resolvers/socialMedia.spec.js b/backend/src/resolvers/socialMedia.spec.js new file mode 100644 index 000000000..b97316543 --- /dev/null +++ b/backend/src/resolvers/socialMedia.spec.js @@ -0,0 +1,49 @@ +import Factory from '../seed/factories' +import { GraphQLClient } from 'graphql-request' +import { host, login } from '../jest/helpers' + +const factory = Factory() + +describe('CreateSocialMedia', () => { + let client + let headers + const mutation = ` + mutation($url: String!) { + CreateSocialMedia(url: $url) { + url + } + } + ` + beforeEach(async () => { + await factory.create('User', { + avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg', + id: 'acb2d923-f3af-479e-9f00-61b12e864666', + name: 'Matilde Hermiston', + slug: 'matilde-hermiston', + role: 'user', + email: 'test@example.org', + password: '1234' + }) + }) + + afterEach(async () => { + await factory.cleanDatabase() + }) + + describe('authenticated', () => { + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) + + it('rejects empty string', async () => { + const variables = { url: '' } + await expect(client.request(mutation, variables)).rejects.toThrow('Input is not a URL') + }) + + it('validates URLs', async () => { + const variables = { url: 'not-a-url' } + await expect(client.request(mutation, variables)).rejects.toThrow('Input is not a URL') + }) + }) +}) diff --git a/backend/src/resolvers/user_management.spec.js b/backend/src/resolvers/user_management.spec.js index 1c21adac1..94ec04203 100644 --- a/backend/src/resolvers/user_management.spec.js +++ b/backend/src/resolvers/user_management.spec.js @@ -1,3 +1,4 @@ +import gql from 'graphql-tag' import Factory from '../seed/factories' import { GraphQLClient, request } from 'graphql-request' import jwt from 'jsonwebtoken' @@ -254,7 +255,7 @@ describe('change password', () => { } describe('should be authenticated before changing password', () => { - it('throws not "Not Authorised!', async () => { + it('throws "Not Authorised!"', async () => { await expect( request( host, @@ -309,3 +310,97 @@ describe('change password', () => { }) }) }) + +describe('do not expose private RSA key', () => { + let headers + let client + const queryUserPuplicKey = gql` + query($queriedUserSlug: String) { + User(slug: $queriedUserSlug) { + id + publicKey + } + }` + const queryUserPrivateKey = gql` + query($queriedUserSlug: String) { + User(slug: $queriedUserSlug) { + id + privateKey + } + }` + + const actionGenUserWithKeys = async () => { + // Generate user with "privateKey" via 'CreateUser' mutation instead of using the factories "factory.create('User', {...})", see above. + const variables = { + id: 'bcb2d923-f3af-479e-9f00-61b12e864667', + password: 'xYz', + slug: 'apfel-strudel', + name: 'Apfel Strudel', + email: 'apfel-strudel@test.org' + } + await client.request(gql` + mutation($id: ID, $password: String!, $slug: String, $name: String, $email: String) { + CreateUser(id: $id, password: $password, slug: $slug, name: $name, email: $email) { + id + } + }`, variables + ) + } + + // not authenticate + beforeEach(async () => { + client = new GraphQLClient(host) + }) + + describe('unauthenticated query of "publicKey" (does the RSA key pair get generated at all?)', () => { + it('returns publicKey', async () => { + await actionGenUserWithKeys() + await expect( + await client.request(queryUserPuplicKey, { queriedUserSlug: 'apfel-strudel' }) + ).toEqual(expect.objectContaining({ + User: [{ + id: 'bcb2d923-f3af-479e-9f00-61b12e864667', + publicKey: expect.any(String) + }] + })) + }) + }) + + describe('unauthenticated query of "privateKey"', () => { + it('throws "Not Authorised!"', async () => { + await actionGenUserWithKeys() + await expect( + client.request(queryUserPrivateKey, { queriedUserSlug: 'apfel-strudel' }) + ).rejects.toThrow('Not Authorised') + }) + }) + + // authenticate + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) + + describe('authenticated query of "publicKey"', () => { + it('returns publicKey', async () => { + await actionGenUserWithKeys() + await expect( + await client.request(queryUserPuplicKey, { queriedUserSlug: 'apfel-strudel' }) + ).toEqual(expect.objectContaining({ + User: [{ + id: 'bcb2d923-f3af-479e-9f00-61b12e864667', + publicKey: expect.any(String) + }] + })) + }) + }) + + describe('authenticated query of "privateKey"', () => { + it('throws "Not Authorised!"', async () => { + await actionGenUserWithKeys() + await expect( + client.request(queryUserPrivateKey, { queriedUserSlug: 'apfel-strudel' }) + ).rejects.toThrow('Not Authorised') + }) + }) +}) diff --git a/backend/src/schema.graphql b/backend/src/schema.graphql index db468471a..4638fbd0d 100644 --- a/backend/src/schema.graphql +++ b/backend/src/schema.graphql @@ -1,8 +1,8 @@ type Query { isLoggedIn: Boolean! - "Get the currently logged in User based on the given JWT Token" + # Get the currently logged in User based on the given JWT Token currentUser: User - "Get the latest Network Statistics" + # Get the latest Network Statistics statistics: Statistics! findPosts(filter: String!, limit: Int = 10): [Post]! @cypher( statement: """ @@ -16,9 +16,10 @@ type Query { LIMIT $limit """ ) + CommentByPost(postId: ID!): [Comment]! } type Mutation { - "Get a JWT Token for the given Email and password" + # Get a JWT Token for the given Email and password login(email: String!, password: String!): String! signup(email: String!, password: String!): Boolean! changePassword(oldPassword:String!, newPassword: String!): String! @@ -27,34 +28,14 @@ type Mutation { enable(id: ID!): ID reward(fromBadgeId: ID!, toUserId: ID!): ID unreward(fromBadgeId: ID!, toUserId: ID!): ID - "Shout the given Type and ID" - shout(id: ID!, type: ShoutTypeEnum): Boolean! @cypher(statement: """ - MATCH (n {id: $id})<-[:WROTE]-(wu:User), (u:User {id: $cypherParams.currentUserId}) - WHERE $type IN labels(n) AND NOT wu.id = $cypherParams.currentUserId - MERGE (u)-[r:SHOUTED]->(n) - RETURN COUNT(r) > 0 - """) - "Unshout the given Type and ID" - unshout(id: ID!, type: ShoutTypeEnum): Boolean! @cypher(statement: """ - MATCH (:User {id: $cypherParams.currentUserId})-[r:SHOUTED]->(n {id: $id}) - WHERE $type IN labels(n) - DELETE r - RETURN COUNT(r) > 0 - """) - "Follow the given Type and ID" - follow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ - MATCH (n {id: $id}), (u:User {id: $cypherParams.currentUserId}) - WHERE $type IN labels(n) AND NOT $id = $cypherParams.currentUserId - MERGE (u)-[r:FOLLOWS]->(n) - RETURN COUNT(r) > 0 - """) - "Unfollow the given Type and ID" - unfollow(id: ID!, type: FollowTypeEnum): Boolean! @cypher(statement: """ - MATCH (:User {id: $cypherParams.currentUserId})-[r:FOLLOWS]->(n {id: $id}) - WHERE $type IN labels(n) - DELETE r - RETURN COUNT(r) > 0 - """) + # Shout the given Type and ID + shout(id: ID!, type: ShoutTypeEnum): Boolean! + # Unshout the given Type and ID + unshout(id: ID!, type: ShoutTypeEnum): Boolean! + # Follow the given Type and ID + follow(id: ID!, type: FollowTypeEnum): Boolean! + # Unfollow the given Type and ID + unfollow(id: ID!, type: FollowTypeEnum): Boolean! } type Statistics { @@ -128,6 +109,7 @@ type User { location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l") locationName: String about: String + socialMedia: [SocialMedia]! @relation(name: "OWNED", direction: "OUT") createdAt: String updatedAt: String @@ -143,11 +125,13 @@ type User { followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN") followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)") - "Is the currently logged in user following that user?" - followedByCurrentUser: Boolean! @cypher(statement: """ - MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) - RETURN COUNT(u) >= 1 - """) + # Is the currently logged in user following that user? + followedByCurrentUser: Boolean! @cypher( + statement: """ + MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) + RETURN COUNT(u) >= 1 + """ + ) #contributions: [WrittenPost]! #contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]! @@ -155,11 +139,13 @@ type User { # statement: "MATCH (this)-[w:WROTE]->(p:Post) RETURN p as Post, w.timestamp as timestamp" # ) contributions: [Post]! @relation(name: "WROTE", direction: "OUT") - contributionsCount: Int! @cypher(statement: """ - MATCH (this)-[:WROTE]->(r:Post) - WHERE (NOT exists(r.deleted) OR r.deleted = false) - AND (NOT exists(r.disabled) OR r.disabled = false) - RETURN COUNT(r)""" + contributionsCount: Int! @cypher( + statement: """ + MATCH (this)-[:WROTE]->(r:Post) + WHERE (NOT exists(r.deleted) OR r.deleted = false) + AND (NOT exists(r.disabled) OR r.disabled = false) + RETURN COUNT(r) + """ ) comments: [Comment]! @relation(name: "WROTE", direction: "OUT") @@ -196,11 +182,13 @@ type Post { createdAt: String updatedAt: String - relatedContributions: [Post]! @cypher(statement: """ - MATCH (this)-[:TAGGED|CATEGORIZED]->(categoryOrTag)<-[:TAGGED|CATEGORIZED]-(post:Post) - RETURN DISTINCT post - LIMIT 10 - """) + relatedContributions: [Post]! @cypher( + statement: """ + MATCH (this)-[:TAGGED|CATEGORIZED]->(categoryOrTag)<-[:TAGGED|CATEGORIZED]-(post:Post) + RETURN DISTINCT post + LIMIT 10 + """ + ) tags: [Tag]! @relation(name: "TAGGED", direction: "OUT") categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT") @@ -211,16 +199,19 @@ type Post { shoutedBy: [User]! @relation(name: "SHOUTED", direction: "IN") shoutedCount: Int! @cypher(statement: "MATCH (this)<-[:SHOUTED]-(r:User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)") - "Has the currently logged in user shouted that post?" - shoutedByCurrentUser: Boolean! @cypher(statement: """ - MATCH (this)<-[:SHOUTED]-(u:User {id: $cypherParams.currentUserId}) - RETURN COUNT(u) >= 1 - """) + # Has the currently logged in user shouted that post? + shoutedByCurrentUser: Boolean! @cypher( + statement: """ + MATCH (this)<-[:SHOUTED]-(u:User {id: $cypherParams.currentUserId}) + RETURN COUNT(u) >= 1 + """ + ) } type Comment { id: ID! activityId: String + postId: ID author: User @relation(name: "WROTE", direction: "IN") content: String! contentExcerpt: String @@ -314,7 +305,15 @@ type Tag { deleted: Boolean disabled: Boolean } + type SharedInboxEndpoint { id: ID! uri: String } + +type SocialMedia { + id: ID! + url: String + ownedBy: [User]! @relation(name: "OWNED", direction: "IN") +} + diff --git a/backend/src/seed/factories/badges.js b/backend/src/seed/factories/badges.js index e24a67c21..6f5f8d69a 100644 --- a/backend/src/seed/factories/badges.js +++ b/backend/src/seed/factories/badges.js @@ -3,21 +3,26 @@ import uuid from 'uuid/v4' export default function (params) { const { id = uuid(), - key, + key = '', type = 'crowdfunding', status = 'permanent', - icon + icon = '/img/badges/indiegogo_en_panda.svg' } = params - return ` - mutation { - CreateBadge( - id: "${id}", - key: "${key}", - type: ${type}, - status: ${status}, - icon: "${icon}" - ) { id } + return { + mutation: ` + mutation( + $id: ID + $key: String! + $type: BadgeTypeEnum! + $status: BadgeStatusEnum! + $icon: String! + ) { + CreateBadge(id: $id, key: $key, type: $type, status: $status, icon: $icon) { + id + } + } + `, + variables: { id, key, type, status, icon } } - ` } diff --git a/backend/src/seed/factories/categories.js b/backend/src/seed/factories/categories.js index a4b448f4b..5c1b3ce10 100644 --- a/backend/src/seed/factories/categories.js +++ b/backend/src/seed/factories/categories.js @@ -8,14 +8,15 @@ export default function (params) { icon } = params - return ` - mutation { - CreateCategory( - id: "${id}", - name: "${name}", - slug: "${slug}", - icon: "${icon}" - ) { id, name } + return { + mutation: ` + mutation($id: ID, $name: String!, $slug: String, $icon: String!) { + CreateCategory(id: $id, name: $name, slug: $slug, icon: $icon) { + id + name + } } - ` + `, + variables: { id, name, slug, icon } + } } diff --git a/backend/src/seed/factories/comments.js b/backend/src/seed/factories/comments.js index 92dca5b14..ba3a85840 100644 --- a/backend/src/seed/factories/comments.js +++ b/backend/src/seed/factories/comments.js @@ -4,22 +4,21 @@ import uuid from 'uuid/v4' export default function (params) { const { id = uuid(), + postId = 'p6', content = [ faker.lorem.sentence(), faker.lorem.sentence() - ].join('. '), - disabled = false, - deleted = false + ].join('. ') } = params - return ` - mutation { - CreateComment( - id: "${id}", - content: "${content}", - disabled: ${disabled}, - deleted: ${deleted} - ) { id } - } - ` + return { + mutation: ` + mutation($id: ID!, $postId: ID, $content: String!) { + CreateComment(id: $id, postId: $postId, content: $content) { + id + } + } + `, + variables: { id, postId, content } + } } diff --git a/backend/src/seed/factories/index.js b/backend/src/seed/factories/index.js index 7c23226cb..a0cb310ab 100644 --- a/backend/src/seed/factories/index.js +++ b/backend/src/seed/factories/index.js @@ -71,8 +71,8 @@ export default function Factory (options = {}) { return this }, async create (node, properties) { - const mutation = this.factories[node](properties) - this.lastResponse = await this.graphQLClient.request(mutation) + const { mutation, variables } = this.factories[node](properties) + this.lastResponse = await this.graphQLClient.request(mutation, variables) return this }, async relate (node, relationship, properties) { diff --git a/backend/src/seed/factories/notifications.js b/backend/src/seed/factories/notifications.js index 2e2abdd55..f7797200f 100644 --- a/backend/src/seed/factories/notifications.js +++ b/backend/src/seed/factories/notifications.js @@ -6,12 +6,15 @@ export default function (params) { read = false } = params - return ` - mutation { - CreateNotification( - id: "${id}", - read: ${read}, - ) { id, read } - } - ` + return { + mutation: ` + mutation($id: ID, $read: Boolean) { + CreateNotification(id: $id, read: $read) { + id + read + } + } + `, + variables: { id, read } + } } diff --git a/backend/src/seed/factories/organizations.js b/backend/src/seed/factories/organizations.js index e0b2e52d4..dd4100b26 100644 --- a/backend/src/seed/factories/organizations.js +++ b/backend/src/seed/factories/organizations.js @@ -5,20 +5,17 @@ export default function create (params) { const { id = uuid(), name = faker.company.companyName(), - description = faker.company.catchPhrase(), - disabled = false, - deleted = false + description = faker.company.catchPhrase() } = params - return ` - mutation { - CreateOrganization( - id: "${id}", - name: "${name}", - description: "${description}", - disabled: ${disabled}, - deleted: ${deleted} - ) { name } - } - ` + return { + mutation: ` + mutation($id: ID!, $name: String!, $description: String!) { + CreateOrganization(id: $id, name: $name, description: $description) { + name + } + } + `, + variables: { id, name, description } + } } diff --git a/backend/src/seed/factories/posts.js b/backend/src/seed/factories/posts.js index 83d5844d7..cbc73dbf8 100644 --- a/backend/src/seed/factories/posts.js +++ b/backend/src/seed/factories/posts.js @@ -18,17 +18,31 @@ export default function (params) { deleted = false } = params - return ` - mutation { - CreatePost( - id: "${id}", - slug: "${slug}", - title: "${title}", - content: "${content}", - image: "${image}", - visibility: ${visibility}, - deleted: ${deleted} - ) { title, content } - } - ` + return { + mutation: ` + mutation( + $id: ID! + $slug: String + $title: String! + $content: String! + $image: String + $visibility: VisibilityEnum + $deleted: Boolean + ) { + CreatePost( + id: $id + slug: $slug + title: $title + content: $content + image: $image + visibility: $visibility + deleted: $deleted + ) { + title + content + } + } + `, + variables: { id, slug, title, content, image, visibility, deleted } + } } diff --git a/backend/src/seed/factories/reports.js b/backend/src/seed/factories/reports.js index ccf5299bd..130c20c37 100644 --- a/backend/src/seed/factories/reports.js +++ b/backend/src/seed/factories/reports.js @@ -6,15 +6,15 @@ export default function create (params) { id } = params - return ` - mutation { - report( - description: "${description}", - id: "${id}", - ) { - id, - createdAt + return { + mutation: ` + mutation($id: ID!, $description: String!) { + report(description: $description, id: $id) { + id + createdAt + } } - } - ` + `, + variables: { id, description } + } } diff --git a/backend/src/seed/factories/tags.js b/backend/src/seed/factories/tags.js index c603c5629..558b68957 100644 --- a/backend/src/seed/factories/tags.js +++ b/backend/src/seed/factories/tags.js @@ -3,15 +3,17 @@ import uuid from 'uuid/v4' export default function (params) { const { id = uuid(), - name + name = '#human-connection' } = params - return ` - mutation { - CreateTag( - id: "${id}", - name: "${name}", - ) { name } - } - ` + return { + mutation: ` + mutation($id: ID!, $name: String!) { + CreateTag(id: $id, name: $name) { + name + } + } + `, + variables: { id, name } + } } diff --git a/backend/src/seed/factories/users.js b/backend/src/seed/factories/users.js index 9fe957515..1bca0e243 100644 --- a/backend/src/seed/factories/users.js +++ b/backend/src/seed/factories/users.js @@ -10,34 +10,42 @@ export default function create (params) { password = '1234', role = 'user', avatar = faker.internet.avatar(), - about = faker.lorem.paragraph(), - disabled = false, - deleted = false + about = faker.lorem.paragraph() } = params - return ` - mutation { - CreateUser( - id: "${id}", - name: "${name}", - slug: "${slug}", - password: "${password}", - email: "${email}", - avatar: "${avatar}", - about: "${about}", - role: ${role}, - disabled: ${disabled}, - deleted: ${deleted} + return { + mutation: ` + mutation( + $id: ID! + $name: String + $slug: String + $password: String! + $email: String + $avatar: String + $about: String + $role: UserGroupEnum ) { - id - name - slug - email - avatar - role - deleted - disabled + CreateUser( + id: $id + name: $name + slug: $slug + password: $password + email: $email + avatar: $avatar + about: $about + role: $role + ) { + id + name + slug + email + avatar + role + deleted + disabled + } } - } - ` + `, + variables: { id, name, slug, password, email, avatar, about, role } + } } diff --git a/backend/src/seed/seed-db.js b/backend/src/seed/seed-db.js index 3de70e643..f17c20315 100644 --- a/backend/src/seed/seed-db.js +++ b/backend/src/seed/seed-db.js @@ -1,3 +1,4 @@ +import faker from 'faker' import Factory from './factories' /* eslint-disable no-multi-spaces */ @@ -88,20 +89,23 @@ import Factory from './factories' f.create('Tag', { id: 't4', name: 'Freiheit' }) ]) + const mention1 = 'Hey @jenny-rostock, what\'s up?' + const mention2 = 'Hey @jenny-rostock, here is another notification for you!' + await Promise.all([ asAdmin.create('Post', { id: 'p0' }), asModerator.create('Post', { id: 'p1' }), - asUser.create('Post', { id: 'p2', deleted: true }), + asUser.create('Post', { id: 'p2' }), asTick.create('Post', { id: 'p3' }), asTrick.create('Post', { id: 'p4' }), asTrack.create('Post', { id: 'p5' }), asAdmin.create('Post', { id: 'p6' }), - asModerator.create('Post', { id: 'p7' }), + asModerator.create('Post', { id: 'p7', content: `${mention1} ${faker.lorem.paragraph()}` }), asUser.create('Post', { id: 'p8' }), asTick.create('Post', { id: 'p9' }), asTrick.create('Post', { id: 'p10' }), asTrack.create('Post', { id: 'p11' }), - asAdmin.create('Post', { id: 'p12' }), + asAdmin.create('Post', { id: 'p12', content: `${mention2} ${faker.lorem.paragraph()}` }), asModerator.create('Post', { id: 'p13' }), asUser.create('Post', { id: 'p14' }), asTick.create('Post', { id: 'p15' }) @@ -185,45 +189,33 @@ import Factory from './factories' ]) await Promise.all([ - f.create('Comment', { id: 'c1' }), - f.create('Comment', { id: 'c2' }), - f.create('Comment', { id: 'c3' }), - f.create('Comment', { id: 'c4' }), - f.create('Comment', { id: 'c5' }), - f.create('Comment', { id: 'c6' }), - f.create('Comment', { id: 'c7' }), - f.create('Comment', { id: 'c8' }), - f.create('Comment', { id: 'c9' }), - f.create('Comment', { id: 'c10' }), - f.create('Comment', { id: 'c11' }), - f.create('Comment', { id: 'c12' }) + f.create('Comment', { id: 'c1', postId: 'p1' }), + f.create('Comment', { id: 'c2', postId: 'p1' }), + f.create('Comment', { id: 'c3', postId: 'p3' }), + f.create('Comment', { id: 'c4', postId: 'p2' }), + f.create('Comment', { id: 'c5', postId: 'p3' }), + f.create('Comment', { id: 'c6', postId: 'p4' }), + f.create('Comment', { id: 'c7', postId: 'p2' }), + f.create('Comment', { id: 'c8', postId: 'p15' }), + f.create('Comment', { id: 'c9', postId: 'p15' }), + f.create('Comment', { id: 'c10', postId: 'p15' }), + f.create('Comment', { id: 'c11', postId: 'p15' }), + f.create('Comment', { id: 'c12', postId: 'p15' }) ]) await Promise.all([ f.relate('Comment', 'Author', { from: 'u3', to: 'c1' }), - f.relate('Comment', 'Post', { from: 'c1', to: 'p1' }), f.relate('Comment', 'Author', { from: 'u1', to: 'c2' }), - f.relate('Comment', 'Post', { from: 'c2', to: 'p1' }), f.relate('Comment', 'Author', { from: 'u1', to: 'c3' }), - f.relate('Comment', 'Post', { from: 'c3', to: 'p3' }), f.relate('Comment', 'Author', { from: 'u4', to: 'c4' }), - f.relate('Comment', 'Post', { from: 'c4', to: 'p2' }), f.relate('Comment', 'Author', { from: 'u4', to: 'c5' }), - f.relate('Comment', 'Post', { from: 'c5', to: 'p3' }), f.relate('Comment', 'Author', { from: 'u3', to: 'c6' }), - f.relate('Comment', 'Post', { from: 'c6', to: 'p4' }), f.relate('Comment', 'Author', { from: 'u2', to: 'c7' }), - f.relate('Comment', 'Post', { from: 'c7', to: 'p2' }), f.relate('Comment', 'Author', { from: 'u5', to: 'c8' }), - f.relate('Comment', 'Post', { from: 'c8', to: 'p15' }), f.relate('Comment', 'Author', { from: 'u6', to: 'c9' }), - f.relate('Comment', 'Post', { from: 'c9', to: 'p15' }), f.relate('Comment', 'Author', { from: 'u7', to: 'c10' }), - f.relate('Comment', 'Post', { from: 'c10', to: 'p15' }), f.relate('Comment', 'Author', { from: 'u5', to: 'c11' }), - f.relate('Comment', 'Post', { from: 'c11', to: 'p15' }), - f.relate('Comment', 'Author', { from: 'u6', to: 'c12' }), - f.relate('Comment', 'Post', { from: 'c12', to: 'p15' }) + f.relate('Comment', 'Author', { from: 'u6', to: 'c12' }) ]) const disableMutation = 'mutation($id: ID!) { disable(id: $id) }' diff --git a/backend/testing.md b/backend/testing.md new file mode 100644 index 000000000..600973450 --- /dev/null +++ b/backend/testing.md @@ -0,0 +1,2 @@ +# Unit Testing + diff --git a/backend/yarn.lock b/backend/yarn.lock index a58f1f865..fab84f08e 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -14,22 +14,22 @@ resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.6.tgz#022209e28a2b547dcde15b219f0c50f47aa5beb3" integrity sha512-lqK94b+caNtmKFs5oUVXlSpN3sm5IXZ+KfhMxOtr0LR2SqErzkoJilitjDvJ1WbjHlxLI7WtCjRmOLdOGJqtMQ== -"@babel/cli@~7.2.3": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.2.3.tgz#1b262e42a3e959d28ab3d205ba2718e1923cfee6" - integrity sha512-bfna97nmJV6nDJhXNPeEfxyMjWnt6+IjUAaDPiYRTBlm8L41n8nvw6UAqUCbvpFfU246gHPxW7sfWwqtF4FcYA== +"@babel/cli@~7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.4.4.tgz#5454bb7112f29026a4069d8e6f0e1794e651966c" + integrity sha512-XGr5YjQSjgTa6OzQZY57FAJsdeVSAKR/u/KA5exWIz66IKtv/zXtHy+fIZcMry/EgYegwuHE7vzGnrFhjdIAsQ== dependencies: commander "^2.8.1" convert-source-map "^1.1.0" fs-readdir-recursive "^1.1.0" glob "^7.0.0" - lodash "^4.17.10" + lodash "^4.17.11" mkdirp "^0.5.1" output-file-sync "^2.0.0" slash "^2.0.0" source-map "^0.5.0" optionalDependencies: - chokidar "^2.0.3" + chokidar "^2.0.4" "@babel/code-frame@^7.0.0": version "7.0.0" @@ -38,18 +38,18 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@^7.1.0", "@babel/core@~7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.3.tgz#198d6d3af4567be3989550d97e068de94503074f" - integrity sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA== +"@babel/core@^7.1.0", "@babel/core@~7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.4.tgz#84055750b05fcd50f9915a826b44fa347a825250" + integrity sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.4.0" - "@babel/helpers" "^7.4.3" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/generator" "^7.4.4" + "@babel/helpers" "^7.4.4" + "@babel/parser" "^7.4.4" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" convert-source-map "^1.1.0" debug "^4.1.0" json5 "^2.1.0" @@ -58,12 +58,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.0.0", "@babel/generator@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.0.tgz#c230e79589ae7a729fd4631b9ded4dc220418196" - integrity sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ== +"@babel/generator@^7.0.0", "@babel/generator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041" + integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ== dependencies: - "@babel/types" "^7.4.0" + "@babel/types" "^7.4.4" jsesc "^2.5.1" lodash "^4.17.11" source-map "^0.5.0" @@ -84,22 +84,22 @@ "@babel/helper-explode-assignable-expression" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-call-delegate@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.0.tgz#f308eabe0d44f451217853aedf4dea5f6fe3294f" - integrity sha512-SdqDfbVdNQCBp3WhK2mNdDvHd3BD6qbmIc43CAyjnsfCmgHMeqgDcM3BzY2lchi7HBJGJ2CVdynLWbezaE4mmQ== +"@babel/helper-call-delegate@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" + integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== dependencies: - "@babel/helper-hoist-variables" "^7.4.0" - "@babel/traverse" "^7.4.0" - "@babel/types" "^7.4.0" + "@babel/helper-hoist-variables" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" -"@babel/helper-define-map@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.0.tgz#cbfd8c1b2f12708e262c26f600cd16ed6a3bc6c9" - integrity sha512-wAhQ9HdnLIywERVcSvX40CEJwKdAa1ID4neI9NXQPDOHwwA+57DqwLiPEVy2AIyWzAk0CQ8qx4awO0VUURwLtA== +"@babel/helper-define-map@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a" + integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg== dependencies: "@babel/helper-function-name" "^7.1.0" - "@babel/types" "^7.4.0" + "@babel/types" "^7.4.4" lodash "^4.17.11" "@babel/helper-explode-assignable-expression@^7.1.0": @@ -126,12 +126,12 @@ dependencies: "@babel/types" "^7.0.0" -"@babel/helper-hoist-variables@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.0.tgz#25b621399ae229869329730a62015bbeb0a6fbd6" - integrity sha512-/NErCuoe/et17IlAQFKWM24qtyYYie7sFIrW/tIQXpck6vAu2hhtYYsKLBWQV+BQZMbcIYPU/QMYuTufrY4aQw== +"@babel/helper-hoist-variables@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" + integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== dependencies: - "@babel/types" "^7.4.0" + "@babel/types" "^7.4.4" "@babel/helper-member-expression-to-functions@^7.0.0": version "7.0.0" @@ -159,16 +159,16 @@ "@babel/types" "^7.0.0" lodash "^4.17.10" -"@babel/helper-module-transforms@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.3.tgz#b1e357a1c49e58a47211a6853abb8e2aaefeb064" - integrity sha512-H88T9IySZW25anu5uqyaC1DaQre7ofM+joZtAaO2F8NBdFfupH0SZ4gKjgSFVcvtx/aAirqA9L9Clio2heYbZA== +"@babel/helper-module-transforms@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8" + integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/template" "^7.2.2" - "@babel/types" "^7.2.2" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/template" "^7.4.4" + "@babel/types" "^7.4.4" lodash "^4.17.11" "@babel/helper-optimise-call-expression@^7.0.0": @@ -190,10 +190,10 @@ dependencies: lodash "^4.17.10" -"@babel/helper-regex@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.3.tgz#9d6e5428bfd638ab53b37ae4ec8caf0477495147" - integrity sha512-hnoq5u96pLCfgjXuj8ZLX3QQ+6nAulS+zSgi6HulUwFbEruRAKwbGLU5OvXkE14L8XW6XsQEKsIDfgthKLRAyA== +"@babel/helper-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" + integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q== dependencies: lodash "^4.17.11" @@ -218,15 +218,15 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-replace-supers@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.0.tgz#4f56adb6aedcd449d2da9399c2dcf0545463b64c" - integrity sha512-PVwCVnWWAgnal+kJ+ZSAphzyl58XrFeSKSAJRiqg5QToTsjL+Xu1f9+RJ+d+Q0aPhPfBGaYfkox66k86thxNSg== +"@babel/helper-replace-supers@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27" + integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg== dependencies: "@babel/helper-member-expression-to-functions" "^7.0.0" "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.4.0" - "@babel/types" "^7.4.0" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" "@babel/helper-simple-access@^7.1.0": version "7.1.0" @@ -243,12 +243,12 @@ dependencies: "@babel/types" "^7.0.0" -"@babel/helper-split-export-declaration@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz#571bfd52701f492920d63b7f735030e9a3e10b55" - integrity sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw== +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== dependencies: - "@babel/types" "^7.4.0" + "@babel/types" "^7.4.4" "@babel/helper-wrap-function@^7.1.0": version "7.2.0" @@ -260,14 +260,14 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" -"@babel/helpers@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.3.tgz#7b1d354363494b31cb9a2417ae86af32b7853a3b" - integrity sha512-BMh7X0oZqb36CfyhvtbSmcWc3GXocfxv3yNsAEuM0l+fAqSO22rQrUpijr3oE/10jCTrB6/0b9kzmG4VetCj8Q== +"@babel/helpers@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.4.tgz#868b0ef59c1dd4e78744562d5ce1b59c89f2f2a5" + integrity sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A== dependencies: - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" "@babel/highlight@^7.0.0": version "7.0.0" @@ -289,10 +289,10 @@ lodash "^4.17.10" v8flags "^3.1.1" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.0", "@babel/parser@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.3.tgz#eb3ac80f64aa101c907d4ce5406360fe75b7895b" - integrity sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6" + integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w== "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" @@ -311,10 +311,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.3.tgz#be27cd416eceeba84141305b93c282f5de23bbb4" - integrity sha512-xC//6DNSSHVjq8O2ge0dyYlhshsH4T7XdCVoxbi5HzLYWfsC5ooFlJjrXk8RcAT+hjHAK9UjBXdylzSoDK3t4g== +"@babel/plugin-proposal-object-rest-spread@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz#1ef173fcf24b3e2df92a678f027673b55e7e3005" + integrity sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" @@ -335,13 +335,13 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-throw-expressions" "^7.2.0" -"@babel/plugin-proposal-unicode-property-regex@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.0.tgz#202d91ee977d760ef83f4f416b280d568be84623" - integrity sha512-h/KjEZ3nK9wv1P1FSNb9G079jXrNYR0Ko+7XkOx85+gM24iZbPn0rh4vCftk+5QKY7y1uByFataBTmX7irEF1w== +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78" + integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" + "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" "@babel/plugin-syntax-async-generators@^7.2.0": @@ -386,10 +386,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-async-to-generator@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.0.tgz#234fe3e458dce95865c0d152d256119b237834b0" - integrity sha512-EeaFdCeUULM+GPFEsf7pFcNSxM7hYjoj5fiYbyuiXobW4JhFnjAv9OWzNwHyHcKoPNpAfeRDuW6VyaXEDUBa7g== +"@babel/plugin-transform-async-to-generator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz#a3f1d01f2f21cadab20b33a82133116f14fb5894" + integrity sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -402,26 +402,26 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-block-scoping@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.0.tgz#164df3bb41e3deb954c4ca32ffa9fcaa56d30bcb" - integrity sha512-AWyt3k+fBXQqt2qb9r97tn3iBwFpiv9xdAiG+Gr2HpAZpuayvbL55yWrsV3MyHvXk/4vmSiedhDRl1YI2Iy5nQ== +"@babel/plugin-transform-block-scoping@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d" + integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.11" -"@babel/plugin-transform-classes@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.3.tgz#adc7a1137ab4287a555d429cc56ecde8f40c062c" - integrity sha512-PUaIKyFUDtG6jF5DUJOfkBdwAS/kFFV3XFk7Nn0a6vR7ZT8jYw5cGtIlat77wcnd0C6ViGqo/wyNf4ZHytF/nQ== +"@babel/plugin-transform-classes@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6" + integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-define-map" "^7.4.0" + "@babel/helper-define-map" "^7.4.4" "@babel/helper-function-name" "^7.1.0" "@babel/helper-optimise-call-expression" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.4.0" - "@babel/helper-split-export-declaration" "^7.4.0" + "@babel/helper-replace-supers" "^7.4.4" + "@babel/helper-split-export-declaration" "^7.4.4" globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.2.0": @@ -431,20 +431,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-destructuring@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.3.tgz#1a95f5ca2bf2f91ef0648d5de38a8d472da4350f" - integrity sha512-rVTLLZpydDFDyN4qnXdzwoVpk1oaXHIvPEOkOLyr88o7oHxVc/LyrnDx+amuBWGOwUb7D1s/uLsKBNTx08htZg== +"@babel/plugin-transform-destructuring@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz#9d964717829cc9e4b601fc82a26a71a4d8faf20f" + integrity sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-dotall-regex@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.3.tgz#fceff1c16d00c53d32d980448606f812cd6d02bf" - integrity sha512-9Arc2I0AGynzXRR/oPdSALv3k0rM38IMFyto7kOCwb5F9sLUt2Ykdo3V9yUPR+Bgr4kb6bVEyLkPEiBhzcTeoA== +"@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" + integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.3" + "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" "@babel/plugin-transform-duplicate-keys@^7.2.0": @@ -462,17 +462,17 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-for-of@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.3.tgz#c36ff40d893f2b8352202a2558824f70cd75e9fe" - integrity sha512-UselcZPwVWNSURnqcfpnxtMehrb8wjXYOimlYQPBnup/Zld426YzIhNEvuRsEWVHfESIECGrxoI6L5QqzuLH5Q== +"@babel/plugin-transform-for-of@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" + integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-function-name@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.3.tgz#130c27ec7fb4f0cba30e958989449e5ec8d22bbd" - integrity sha512-uT5J/3qI/8vACBR9I1GlAuU/JqBtWdfCrynuOkrWG6nCDieZd5przB1vfP59FRHBZQ9DC2IUfqr/xKqzOD5x0A== +"@babel/plugin-transform-function-name@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" + integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -499,21 +499,21 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-modules-commonjs@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.3.tgz#3917f260463ac08f8896aa5bd54403f6e1fed165" - integrity sha512-sMP4JqOTbMJMimqsSZwYWsMjppD+KRyDIUVW91pd7td0dZKAvPmhCaxhOzkzLParKwgQc7bdL9UNv+rpJB0HfA== +"@babel/plugin-transform-modules-commonjs@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz#0bef4713d30f1d78c2e59b3d6db40e60192cac1e" + integrity sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw== dependencies: - "@babel/helper-module-transforms" "^7.4.3" + "@babel/helper-module-transforms" "^7.4.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" -"@babel/plugin-transform-modules-systemjs@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.0.tgz#c2495e55528135797bc816f5d50f851698c586a1" - integrity sha512-gjPdHmqiNhVoBqus5qK60mWPp1CmYWp/tkh11mvb0rrys01HycEGD7NvvSoKXlWEfSM9TcL36CpsK8ElsADptQ== +"@babel/plugin-transform-modules-systemjs@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz#dc83c5665b07d6c2a7b224c00ac63659ea36a405" + integrity sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ== dependencies: - "@babel/helper-hoist-variables" "^7.4.0" + "@babel/helper-hoist-variables" "^7.4.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-modules-umd@^7.2.0": @@ -524,17 +524,17 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-named-capturing-groups-regex@^7.4.2": - version "7.4.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.2.tgz#800391136d6cbcc80728dbdba3c1c6e46f86c12e" - integrity sha512-NsAuliSwkL3WO2dzWTOL1oZJHm0TM8ZY8ZSxk2ANyKkt5SQlToGA4pzctmq1BEjoacurdwZ3xp2dCQWJkME0gQ== +"@babel/plugin-transform-named-capturing-groups-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.4.tgz#5611d96d987dfc4a3a81c4383bb173361037d68d" + integrity sha512-Ki+Y9nXBlKfhD+LXaRS7v95TtTGYRAf9Y1rTDiE75zf8YQz4GDaWRXosMfJBXxnk88mGFjWdCRIeqDbon7spYA== dependencies: regexp-tree "^0.1.0" -"@babel/plugin-transform-new-target@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.0.tgz#67658a1d944edb53c8d4fa3004473a0dd7838150" - integrity sha512-6ZKNgMQmQmrEX/ncuCwnnw1yVGoaOW5KpxNhoWI7pCQdA0uZ0HqHGqenCUIENAnxRjy2WwNQ30gfGdIgqJXXqw== +"@babel/plugin-transform-new-target@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" + integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -546,12 +546,12 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" -"@babel/plugin-transform-parameters@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.3.tgz#e5ff62929fdf4cf93e58badb5e2430303003800d" - integrity sha512-ULJYC2Vnw96/zdotCZkMGr2QVfKpIT/4/K+xWWY0MbOJyMZuk660BGkr3bEKWQrrciwz6xpmft39nA4BF7hJuA== +"@babel/plugin-transform-parameters@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" + integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== dependencies: - "@babel/helper-call-delegate" "^7.4.0" + "@babel/helper-call-delegate" "^7.4.4" "@babel/helper-get-function-arity" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -562,10 +562,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-regenerator@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.3.tgz#2a697af96887e2bbf5d303ab0221d139de5e739c" - integrity sha512-kEzotPuOpv6/iSlHroCDydPkKYw7tiJGKlmYp6iJn4a6C/+b2FdttlJsLKYxolYHgotTJ5G5UY5h0qey5ka3+A== +"@babel/plugin-transform-regenerator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.4.tgz#5b4da4df79391895fca9e28f99e87e22cfc02072" + integrity sha512-Zz3w+pX1SI0KMIiqshFZkwnVGUhDZzpX2vtPzfJBKQQq8WsP/Xy9DNdELWivxcKOCX/Pywge4SiEaPaLtoDT4g== dependencies: regenerator-transform "^0.13.4" @@ -598,10 +598,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" -"@babel/plugin-transform-template-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz#d87ed01b8eaac7a92473f608c97c089de2ba1e5b" - integrity sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg== +"@babel/plugin-transform-template-literals@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" + integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -613,13 +613,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-unicode-regex@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.3.tgz#3868703fc0e8f443dda65654b298df576f7b863b" - integrity sha512-lnSNgkVjL8EMtnE8eSS7t2ku8qvKH3eqNf/IwIfnSPUqzgqYmRwzdsQWv4mNQAN9Nuo6Gz1Y0a4CSmdpu1Pp6g== +"@babel/plugin-transform-unicode-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" + integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.3" + "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" "@babel/polyfill@^7.0.0": @@ -638,64 +638,64 @@ core-js "^2.5.7" regenerator-runtime "^0.12.0" -"@babel/preset-env@~7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.3.tgz#e71e16e123dc0fbf65a52cbcbcefd072fbd02880" - integrity sha512-FYbZdV12yHdJU5Z70cEg0f6lvtpZ8jFSDakTm7WXeJbLXh4R0ztGEu/SW7G1nJ2ZvKwDhz8YrbA84eYyprmGqw== +"@babel/preset-env@~7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.4.tgz#b6f6825bfb27b3e1394ca3de4f926482722c1d6f" + integrity sha512-FU1H+ACWqZZqfw1x2G1tgtSSYSfxJLkpaUQL37CenULFARDo+h4xJoVHzRoHbK+85ViLciuI7ME4WTIhFRBBlw== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-async-generator-functions" "^7.2.0" "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.4.3" + "@babel/plugin-proposal-object-rest-spread" "^7.4.4" "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" "@babel/plugin-syntax-async-generators" "^7.2.0" "@babel/plugin-syntax-json-strings" "^7.2.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.4.0" + "@babel/plugin-transform-async-to-generator" "^7.4.4" "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.4.0" - "@babel/plugin-transform-classes" "^7.4.3" + "@babel/plugin-transform-block-scoping" "^7.4.4" + "@babel/plugin-transform-classes" "^7.4.4" "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.4.3" - "@babel/plugin-transform-dotall-regex" "^7.4.3" + "@babel/plugin-transform-destructuring" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" "@babel/plugin-transform-duplicate-keys" "^7.2.0" "@babel/plugin-transform-exponentiation-operator" "^7.2.0" - "@babel/plugin-transform-for-of" "^7.4.3" - "@babel/plugin-transform-function-name" "^7.4.3" + "@babel/plugin-transform-for-of" "^7.4.4" + "@babel/plugin-transform-function-name" "^7.4.4" "@babel/plugin-transform-literals" "^7.2.0" "@babel/plugin-transform-member-expression-literals" "^7.2.0" "@babel/plugin-transform-modules-amd" "^7.2.0" - "@babel/plugin-transform-modules-commonjs" "^7.4.3" - "@babel/plugin-transform-modules-systemjs" "^7.4.0" + "@babel/plugin-transform-modules-commonjs" "^7.4.4" + "@babel/plugin-transform-modules-systemjs" "^7.4.4" "@babel/plugin-transform-modules-umd" "^7.2.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.2" - "@babel/plugin-transform-new-target" "^7.4.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.4" + "@babel/plugin-transform-new-target" "^7.4.4" "@babel/plugin-transform-object-super" "^7.2.0" - "@babel/plugin-transform-parameters" "^7.4.3" + "@babel/plugin-transform-parameters" "^7.4.4" "@babel/plugin-transform-property-literals" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.4.3" + "@babel/plugin-transform-regenerator" "^7.4.4" "@babel/plugin-transform-reserved-words" "^7.2.0" "@babel/plugin-transform-shorthand-properties" "^7.2.0" "@babel/plugin-transform-spread" "^7.2.0" "@babel/plugin-transform-sticky-regex" "^7.2.0" - "@babel/plugin-transform-template-literals" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.4.4" "@babel/plugin-transform-typeof-symbol" "^7.2.0" - "@babel/plugin-transform-unicode-regex" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/plugin-transform-unicode-regex" "^7.4.4" + "@babel/types" "^7.4.4" browserslist "^4.5.2" core-js-compat "^3.0.0" invariant "^2.2.2" js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/register@^7.0.0", "@babel/register@~7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.4.0.tgz#d9d0a621db268fb14200f2685a4f8924c822404c" - integrity sha512-ekziebXBnS/7V6xk8sBfLSSD6YZuy6P29igBtR6OL/tswKdxOV+Yqq0nzICMguVYtGRZYUCGpfGV8J9Za2iBdw== +"@babel/register@^7.0.0", "@babel/register@~7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.4.4.tgz#370a68ba36f08f015a8b35d4864176c6b65d7a23" + integrity sha512-sn51H88GRa00+ZoMqCVgOphmswG4b7mhf9VOB0LUBAieykq2GnRFerlN+JQkO/ntT7wz4jaHNSRPg9IdMPEUkA== dependencies: core-js "^3.0.0" find-cache-dir "^2.0.0" @@ -711,34 +711,34 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.2.2", "@babel/template@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b" - integrity sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw== +"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.4.0" - "@babel/types" "^7.4.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.0", "@babel/traverse@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.3.tgz#1a01f078fc575d589ff30c0f71bf3c3d9ccbad84" - integrity sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ== +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.4.tgz#0776f038f6d78361860b6823887d4f3937133fe8" + integrity sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.4.0" + "@babel/generator" "^7.4.4" "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.11" -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" - integrity sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA== +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0" + integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ== dependencies: esutils "^2.0.2" lodash "^4.17.11" @@ -1104,10 +1104,10 @@ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.9.tgz#693e76a52f61a2f1e7fb48c0eef167b95ea4ffd0" integrity sha512-sCZy4SxP9rN2w30Hlmg5dtdRwgYQfYRiLo9usw8X9cxlf+H4FqM1xX7+sNH7NNKVdbXMJWqva7iyy+fxh/V7fA== -"@types/yup@0.26.9": - version "0.26.9" - resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.9.tgz#8a619ac4d2b8dcacb0d81345746018303b479919" - integrity sha512-C7HdLLs1ZNPbYeNsSX++fMosxWAwzVeUs9wc76XlKJrKvLEyNwXMDUjag75EVAPxlZ36YiRJ6iTy4zc5Dbtndw== +"@types/yup@0.26.12": + version "0.26.12" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.12.tgz#60fc1a485923a929699d2107fac46e6769707c4a" + integrity sha512-lWCsvLer6G84Gj7yh+oFGRuGHsqZd1Dwu47CVVL0ATw+bOnGDgMNHbTn80p1onT66fvLfN8FnRA3eRANsnnbbQ== "@types/zen-observable@^0.5.3": version "0.5.4" @@ -1609,6 +1609,14 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + array-map@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" @@ -2149,7 +2157,7 @@ cheerio@~1.0.0-rc.3: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@^2.0.3, chokidar@^2.1.5: +chokidar@^2.0.4, chokidar@^2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== @@ -2892,7 +2900,7 @@ es-abstract@^1.4.3: is-callable "^1.1.3" is-regex "^1.0.4" -es-abstract@^1.5.1: +es-abstract@^1.5.1, es-abstract@^1.7.0: version "1.13.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== @@ -2989,10 +2997,10 @@ eslint-import-resolver-node@^0.3.2: debug "^2.6.9" resolve "^1.5.0" -eslint-module-utils@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz#546178dab5e046c8b562bbb50705e2456d7bda49" - integrity sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w== +eslint-module-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a" + integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw== dependencies: debug "^2.6.8" pkg-dir "^2.0.0" @@ -3005,26 +3013,27 @@ eslint-plugin-es@^1.3.1: eslint-utils "^1.3.0" regexpp "^2.0.1" -eslint-plugin-import@~2.16.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz#97ac3e75d0791c4fac0e15ef388510217be7f66f" - integrity sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A== +eslint-plugin-import@~2.17.2: + version "2.17.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz#d227d5c6dc67eca71eb590d2bb62fb38d86e9fcb" + integrity sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g== dependencies: + array-includes "^3.0.3" contains-path "^0.1.0" debug "^2.6.9" doctrine "1.5.0" eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.3.0" + eslint-module-utils "^2.4.0" has "^1.0.3" lodash "^4.17.11" minimatch "^3.0.4" read-pkg-up "^2.0.0" - resolve "^1.9.0" + resolve "^1.10.0" -eslint-plugin-jest@~22.4.1: - version "22.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.4.1.tgz#a5fd6f7a2a41388d16f527073b778013c5189a9c" - integrity sha512-gcLfn6P2PrFAVx3AobaOzlIEevpAEf9chTpFZz7bYfc7pz8XRv7vuKTIE4hxPKZSha6XWKKplDQ0x9Pq8xX2mg== +eslint-plugin-jest@~22.5.1: + version "22.5.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.5.1.tgz#a31dfe9f9513c6af7c17ece4c65535a1370f060b" + integrity sha512-c3WjZR/HBoi4GedJRwo2OGHa8Pzo1EbSVwQ2HFzJ+4t2OoYM7Alx646EH/aaxZ+9eGcPiq0FT0UGkRuFFx2FHg== eslint-plugin-node@~8.0.1: version "8.0.1" @@ -3743,13 +3752,13 @@ graphql-request@~1.8.2: dependencies: cross-fetch "2.2.2" -graphql-shield@~5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-5.3.2.tgz#2d47907ed9882a0636cb8ade6087123309d215ef" - integrity sha512-fib7rSr5aS/WHL3+Aa5LXhcCuPGEIDXmzfGtFjUXkUiZ6E5u+bDSL+9KRXo/p14A28GkJF+1Vu1hlg9H/QFG1w== +graphql-shield@~5.3.4: + version "5.3.4" + resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-5.3.4.tgz#bd126d7d39adc6ae5b91d93ab5f65ae25f93ce80" + integrity sha512-YasNfKk7d0hiSU9eh0zvJmRmUMDLZrfVTwSke/4y46cBRXFiI9fv6OA12Ux+1DB4TyDAjGGnqx8d92ptL7ZN3w== dependencies: - "@types/yup" "0.26.9" - lightercollective "^0.2.0" + "@types/yup" "0.26.12" + lightercollective "^0.3.0" object-hash "^1.3.1" yup "^0.27.0" @@ -4917,9 +4926,9 @@ joi@^13.0.0: topo "3.x.x" jquery@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" - integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg== + version "3.4.0" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.0.tgz#8de513fa0fa4b2c7d2e48a530e26f0596936efdf" + integrity sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ== js-levenshtein@^1.1.3: version "1.1.4" @@ -5175,10 +5184,10 @@ libphonenumber-js@^1.6.4: semver-compare "^1.0.0" xml2js "^0.4.17" -lightercollective@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.2.0.tgz#4f10cd53ec50405d7da03ee81233067993ca8e67" - integrity sha512-zgFCDiUQQOjislj+1tX7zDxZbgVB6Qi9BSmos41oZcxHdkTveVDzHW0Y3TisNZCWuBN1h0e0xrjkNoLtPkLsUg== +lightercollective@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.3.0.tgz#1f07638642ec645d70bdb69ab2777676f35a28f0" + integrity sha512-RFOLSUVvwdK3xA0P8o6G7QGXLIyy1L2qv5caEI7zXN5ciaEjbAriRF182kbsoJ1S1TgvpyGcN485fMky6qxOPw== linkifyjs@~2.1.8: version "2.1.8" @@ -5625,10 +5634,10 @@ node-fetch@2.1.2: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U= -node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" - integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== +node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.4.1.tgz#b2e38f1117b8acbedbe0524f041fb3177188255d" + integrity sha512-P9UbpFK87NyqBZzUuDBDz4f6Yiys8xm8j7ACDbi6usvFm6KItklQUKjeoqTrYS/S1k6I8oaOC2YLLDr/gg26Mw== node-forge@~0.6.45: version "0.6.49" @@ -6677,7 +6686,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.3.2, resolve@^1.3.3, resolve@^1.5.0, resolve@^1.8.1, resolve@^1.9.0: +resolve@^1.10.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.5.0, resolve@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== @@ -6770,10 +6779,10 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sanitize-html@~1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.20.0.tgz#9a602beb1c9faf960fb31f9890f61911cc4d9156" - integrity sha512-BpxXkBoAG+uKCHjoXFmox6kCSYpnulABoGcZ/R3QyY9ndXbIM5S94eOr1IqnzTG8TnbmXaxWoDDzKC5eJv7fEQ== +sanitize-html@~1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.20.1.tgz#f6effdf55dd398807171215a62bfc21811bacf85" + integrity sha512-txnH8TQjaQvg2Q0HY06G6CDJLVYCpbnxrdO0WN8gjCKaU5J0KbyGYhZxx5QJg3WLZ1lB7XU9kDkfrCXUozqptA== dependencies: chalk "^2.4.1" htmlparser2 "^3.10.0" diff --git a/cypress/README.md b/cypress/README.md new file mode 100644 index 000000000..92b1b8185 --- /dev/null +++ b/cypress/README.md @@ -0,0 +1,50 @@ +# End-to-End Testing + +## Configure cypress + +First, you have to tell cypress how to connect to your local neo4j database +among other things. You can copy our template configuration and change the new +file according to your needs. + +Make sure you are at the root level of the project. Then: +```bash +# in the top level folder Human-Connection/ +$ cp cypress.env.template.json cypress.env.json +``` + +## Run Tests + +To run the tests, do this: + +```bash +# in the top level folder Human-Connection/ +$ yarn cypress:setup +``` + +After verifying that there are no errors with the servers starting, open another tab in your terminal and run the following command: + +```bash +$ yarn cypress:run +``` + +![Console output after running cypress test](../.gitbook/assets/grafik%20%281%29.png) + +After the test runs, you will also get some video footage of the test run which you can then analyse in more detail. + +## Open Interactive Test Console + +If you are like me, you might want to see some visual output. The interactive cypress environment also helps at debugging your tests, you can even time travel between individual steps and see the exact state of the app. + +To use this feature, you will still run the `yarn cypress:setup` above, but instead of `yarn cypress:run` open another tab in your terminal and run the following command: + +```bash +$ yarn cypress:open +``` + +![Interactive Cypress Environment](../.gitbook/assets/grafik-1%20%281%29.png) + +## Write some Tests + +Check out the Cypress documentation for further information on how to write tests: +[https://docs.cypress.io/guides/getting-started/writing-your-first-test.html\#Write-a-simple-test](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html#Write-a-simple-test) + diff --git a/cypress/features.md b/cypress/features.md new file mode 100644 index 000000000..eb8292c3b --- /dev/null +++ b/cypress/features.md @@ -0,0 +1,279 @@ +# Network Specification + +Human Connection is a nonprofit social, action and knowledge network that connects information to action and promotes positive local and global change in all areas of life. + +* **Social**: Interact with other people not just by commenting their posts, but by providing **Pro & Contra** arguments, give a **Versus** or ask them by integrated **Chat** or **Let's Talk** +* **Knowledge**: Read articles about interesting topics and find related posts in the **More Info** tab or by **Filtering** based on **Categories** and **Tagging** or by using the **Fulltext Search**. +* **Action**: Don't just read about how to make the world a better place, but come into **Action** by following provided suggestions on the **Action** tab provided by other people or **Organisations**. + +## Features + +The following features will be implemented. This gets done in three steps: + +1. First we will implement a basic feature set and provide a test system to test the basic network functionality. +2. In a second step we will make our prototype publicly available with an advanced feature set including the technology and organizational structure to drive a bigger public social network. +3. In a third step all the remaining features will be implemented to build the full product. + +### User Account + +[Cucumber Features](./integration/user_account) + +* Sign-up +* Agree to Data Privacy Statement +* Agree to Terms of Service +* Login +* Logoff +* Change User Name +* Change Email Address +* Change Password +* Delete Account +* Download User's Content +* GDPR-Information about stored Content +* Choosing Interface Language \(e.g. German / English / French\) +* Persistent Links + +### User Profile + +[Cucumber Features](./integration/user_profile) + +* Upload and Change Avatar +* Upload and Change Profile Picture +* Edit Social Media Accounts +* Edit Locale information +* Show and delete Bookmarks \(later\) +* Show Posts of a specific User +* Show Comments of a specific User + +### Dashboard + +[Clickdummy](https://preview.uxpin.com/24a2ab8adcd84f9a763d87ed27251351225e0ecd#/pages/99768919/simulate/sitemap?mode=i) + +* Show Link to own Profile +* Show Friends Widget +* Show Favorites Widget +* Show Get Friends Widget +* Show popular Hashtags Widget +* Show Mini-Statistics Widget \(all time\) +* Show Chatrooms Widget +* Show List of Let's Talk requests with online status of requesting people + +### Posts + +[Cucumber Features](./integration/post/) + +* Creating Posts +* Persistent Links +* Upload Teaser Picture for Post +* Upload additional Pictures +* Editing Title and Content +* Allow embedded Conten \(Videos, Sound, ...\) +* Choosing a Category +* Adding Tags +* Choosing Language \(e.g. German / English / French\) +* Choosing Visibility \(Public / Friends / Private\) +* Shout Button for Posts +* Bookmark Posts \(later\) +* Optionally provide Let's Talk Feature +* Optionally provide Commenting Feature + +### Comments + +* Creating Comments +* Deleting Comments +* Editing Comments +* Upvote comments of others + +### Notifications +[Cucumber features](./integration/notifications) + +* User @-mentionings +* Notify authors for comments +* Administrative notifications to all users + +### Contribution List + +* Show Posts by Tiles +* Show Posts as List +* Filter by Category \(Health and Wellbeing, Global Peace & Non-Violence, ...\) +* Filter by Mood \(Funny, Happy, Surprised, Cry, Angry, ...\) +* Filter by Source \(Connections, Following, Individuals, Non-Profits, ...\) +* Filter by Posts & Tools \(Post, Events, CanDos, ...\) +* Filter by Format Type \(Text, Pictures, Video, ...\) +* Extended Filter \(Continent, Country, Language, ...\) +* Sort Posts by Date +* Sort Posts by Shouts +* Sort Posts by most Comments +* Sort Posts by Emoji-Count \(all Types\) + +### Blacklist + +[Video](https://www.youtube.com/watch?v=-uDvvmN8hLQ) + +* Blacklist Users +* Blacklist specific Terms +* Blacklist Tags +* Switch on/off Adult Content + +### Search + +[Cucumber Features](./integration/search) + +* Search for Categories +* Search for Tags +* Fulltext Search + +### CanDos + +* Creating CanDos +* Editing Title and Content +* Choosing a Category +* Adding Tags +* Choosing Language \(e.g. German / English / French\) +* Choosing Visibility \(Public / Friends / Private\) +* Choosing Difficulty +* Editing Why - why should you do this +* Editing Usefulness - what is it good for + +### Versus \(interaction on existing Post\) + +* Create / edit / delete Versus + +### Jobs + +* Create, edit and delete Jobs by an User +* Handle Jobs as Part of Projects +* Handle Jobs done by Organizations + +### Projects + +* Create, edit and delete Projects +* Edit Title and Description for the Project +* Set Project Type +* Set and Edit Timeline for the Project +* Add Media to the Project +* Chat about the Project + +### Pro & Contra + +* Create Pro and Con \(2-row\) +* Add Arguments on Pro or Con Side +* Rate up Arguments +* Add Tags +* Attach Media + +### Votes + +* Create Votes \(Surveys with two or more Choices\) +* Add Title and Description +* Let Users vote +* Add Tags + +### Bestlist + +* Create Bestlist +* Create Votes \(Surveys\) +* Add Title and Description +* Add Tags +* Let Users vote for Best Item +* Set Settings \(allow Uploads, allow Links, ...\) + +### Events + +* Create Events +* Add Title and Description +* Choose Date and Location +* Add Tags + +### More Info + +Shows autmatically releated information for existing post. + +* Show related Posts +* Show Pros and Cons +* Show Bestlist +* Show Votes +* Link to corresponding Chatroom + +### Take Action + +Shows automatically related actions for existing post. + +* Show related Organisations +* Show related CanDos +* Show related Projects +* Show related Jobs +* Show related Events +* Show Map + +### Badges System + +* Importing Badge Information \(CSV\) +* Showing Badges +* Badge Administration by Admins +* Choosing Badges to display by User + +### Chat + +* Basic 1:1 Chat functionality + +### Let's Talk + +* Request Let's talk with Author of Post +* Requestor can request private or public Let's Talk +* Requestor can choose the Chat format \(Video, Audio, Text\) +* Interact with interested People 1:1 +* Approve request from Requestor + +### Organizations + +* Propose Organizations by users +* Set Name and Details +* Set Homepage +* Set Region +* Set Topic +* Commit organizations by HC-Org-Team +* Panel for Organisation Handling by themselfes +* Choose/Mark Users as authorized to manage an Organization + +### Moderation + +[Cucumber Features](./integration/moderation) + +* Report Button for users for doubtful Content +* Moderator Panel +* List of reported Content \(later replaced by User-Moderation\) +* Mark verified Users as Moderators +* Show Posts to be moderated highlighted to User-Moderators +* Statistics about kinds of reported Content by Time +* Statistics about Decisions in Moderation + +### Administration + +* Provide Admin-Interface to send Users Invite Code +* Static Pages for Data Privacy Statement ... +* Create, edit and delete Announcements +* Show Announcements on top of User Interface + +### Invitation + +* Allow Users to invite others by Email +* Allow Users to register with Invite Code +* Double-opt-in by Email + +### Internationalization + +[Cucumber Features](./integration/internationalization) + +* Frontend UI +* Backend Error Messages + +### Federation + +* Provide Server-Server ActivityPub-API +* Provide User-Server Activitypub-API +* Receiving public addressed Article and Note Objects +* Receiving Like and Follow Activities +* Receiving Undo and Delete Activities for Articles and Notes +* Serving Webfinger records and Actor Objects +* Serving Followers, Following and Outbox collections + diff --git a/cypress/integration/common/post.js b/cypress/integration/common/post.js new file mode 100644 index 000000000..85a9f3339 --- /dev/null +++ b/cypress/integration/common/post.js @@ -0,0 +1,20 @@ +import { When, Then } from 'cypress-cucumber-preprocessor/steps' + +Then('I click on the {string} button', text => { + cy.get('button').contains(text).click() +}) + +Then('my comment should be successfully created', () => { + cy.get('.iziToast-message') + .contains('Comment Submitted') +}) + +Then('I should see my comment', () => { + cy.get('div.comment p') + .should('contain', 'Human Connection rocks') +}) + +Then('the editor should be cleared', () => { + cy.get('.ProseMirror p') + .should('have.class', 'is-empty') +}) diff --git a/cypress/integration/common/report.js b/cypress/integration/common/report.js index a35e638e0..2c8b848b4 100644 --- a/cypress/integration/common/report.js +++ b/cypress/integration/common/report.js @@ -49,25 +49,20 @@ When('I click on "Report Post" from the content menu of the post', () => { .click() }) -When( - 'I click on "Report User" from the content menu in the user info box', - () => { - cy.contains('.ds-card', davidIrvingName) - .find('.content-menu-trigger') - .first() - .click() +When('I click on "Report User" from the content menu in the user info box', () => { + cy.contains('.ds-card', davidIrvingPostTitle) + .get('.user-content-menu .content-menu-trigger') + .click({ force: true }) - cy.get('.popover .ds-menu-item-link') - .contains('Report User') - .click() - } -) + cy.get('.popover .ds-menu-item-link') + .contains('Report User') + .click() +}) When('I click on the author', () => { - cy.get('a.user') - .first() + cy.get('.username') .click() - .wait(200) + .url().should('include', '/profile/') }) When('I report the author', () => { diff --git a/cypress/integration/common/settings.js b/cypress/integration/common/settings.js index 3aa6022a8..e1f3cc5a8 100644 --- a/cypress/integration/common/settings.js +++ b/cypress/integration/common/settings.js @@ -61,3 +61,52 @@ Then( 'I can see my new name {string} when I click on my profile picture in the top right', name => matchNameInUserMenu(name) ) + +When('I click on the {string} link', link => { + cy.get('a') + .contains(link) + .click() +}) + +Then('I should be on the {string} page', page => { + cy.location() + .should(loc => { + expect(loc.pathname).to.eq(page) + }) + .get('h3') + .should('contain', 'Social media') +}) + +Then('I add a social media link', () => { + cy.get("input[name='social-media']") + .type('https://freeradical.zone/peter-pan') + .get('button') + .contains('Add link') + .click() +}) + +Then('it gets saved successfully', () => { + cy.get('.iziToast-message') + .should('contain', 'Updated user') +}) + +Then('the new social media link shows up on the page', () => { + cy.get('a[href="https://freeradical.zone/peter-pan"]') + .should('have.length', 1) +}) + +Given('I have added a social media link', () => { + cy.openPage('/settings/my-social-media') + .get("input[name='social-media']") + .type('https://freeradical.zone/peter-pan') + .get('button') + .contains('Add link') + .click() +}) + +Then('they should be able to see my social media links', () => { + cy.get('.ds-card-content') + .contains('Where else can I find Peter Pan?') + .get('a[href="https://freeradical.zone/peter-pan"]') + .should('have.length', 1) +}) diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index 8944b7c25..85a660f43 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -228,7 +228,7 @@ Then('I get redirected to {string}', route => { }) Then('the post was saved successfully', () => { - cy.get('.ds-card-header > .ds-heading').should('contain', lastPost.title) + cy.get('.ds-card-content > .ds-heading').should('contain', lastPost.title) cy.get('.content').should('contain', lastPost.content) }) @@ -293,3 +293,43 @@ Then('I can login successfully with password {string}', password => { }) cy.get('.iziToast-wrapper').should('contain', "You are logged in!") }) + +When('I log in with the following credentials:', table => { + const { email, password } = table.hashes()[0] + cy.login({ email, password }) +}) + +When('open the notification menu and click on the first item', () => { + cy.get('.notifications-menu').click() + cy.get('.notification-mention-post').first().click() +}) + +Then('see {int} unread notifications in the top menu', count => { + cy.get('.notifications-menu').should('contain', count) +}) + +Then('I get to the post page of {string}', path => { + path = path.replace('...', '') + cy.url().should('contain', '/post/') + cy.url().should('contain', path) +}) + +When('I start to write a new post with the title {string} beginning with:', (title, intro) => { + cy.get('.post-add-button').click() + cy.get('input[name="title"]').type(title) + cy.get('.ProseMirror').type(intro) +}) + +When('mention {string} in the text', (mention) => { + cy.get('.ProseMirror').type(' @') + cy.get('.suggestion-list__item').contains(mention).click() + cy.debug() +}) + +Then('the notification gets marked as read', () => { + cy.get('.notification').first().should('have.class', 'read') +}) + +Then('there are no notifications in the top menu', () => { + cy.get('.notifications-menu').should('contain', '0') +}) diff --git a/cypress/integration/02.Internationalization.feature b/cypress/integration/internationalization/Internationalization.feature similarity index 100% rename from cypress/integration/02.Internationalization.feature rename to cypress/integration/internationalization/Internationalization.feature diff --git a/cypress/integration/moderation/ReportContent.feature b/cypress/integration/moderation/ReportContent.feature index 52f7218d4..62fb4f421 100644 --- a/cypress/integration/moderation/ReportContent.feature +++ b/cypress/integration/moderation/ReportContent.feature @@ -1,6 +1,6 @@ Feature: Report and Moderate As a user - I would like to report content that viloates the community guidlines + I would like to report content that violates the community guidlines So the moderators can take action on it As a moderator @@ -12,18 +12,19 @@ Feature: Report and Moderate | Author | id | title | content | | David Irving | p1 | The Truth about the Holocaust | It never existed! | + Scenario Outline: Report a post from various pages Given I am logged in with a "user" role When I see David Irving's post on the And I click on "Report Post" from the content menu of the post And I confirm the reporting dialog because it is a criminal act under German law: - """ - Do you really want to report the contribution "The Truth about the Holocaust"? - """ + """ + Do you really want to report the contribution "The Truth about the Holocaust"? + """ Then I see a success message: - """ - Thanks for reporting! - """ + """ + Thanks for reporting! + """ Examples: | Page | | landing page | @@ -35,13 +36,13 @@ Feature: Report and Moderate When I click on the author And I click on "Report User" from the content menu in the user info box And I confirm the reporting dialog because he is a holocaust denier: - """ - Do you really want to report the user "David Irving"? - """ + """ + Do you really want to report the user "David Irving"? + """ Then I see a success message: - """ - Thanks for reporting! - """ + """ + Thanks for reporting! + """ Scenario: Review reported content Given somebody reported the following posts: diff --git a/cypress/integration/notifications/Mentions.feature b/cypress/integration/notifications/Mentions.feature new file mode 100644 index 000000000..28f7cf456 --- /dev/null +++ b/cypress/integration/notifications/Mentions.feature @@ -0,0 +1,31 @@ +Feature: Notifications for a mentions + As a user + I want to be notified if sb. mentions me in a post or comment + In order join conversations about or related to me + + Background: + Given we have the following user accounts: + | name | slug | email | password | + | Wolle aus Hamburg | wolle-aus-hamburg | wolle@example.org | 1234 | + | Matt Rider | matt-rider | matt@example.org | 4321 | + + Scenario: Mention another user, re-login as this user and see notifications + Given I log in with the following credentials: + | email | password | + | wolle@example.org | 1234 | + And I start to write a new post with the title "Hey Matt" beginning with: + """ + Big shout to our fellow contributor + """ + And mention "@matt-rider" in the text + And I click on "Save" + When I log out + And I log in with the following credentials: + | email | password | + | matt@example.org | 4321 | + And see 1 unread notifications in the top menu + And open the notification menu and click on the first item + Then I get to the post page of ".../hey-matt" + And the notification gets marked as read + But when I refresh the page + Then there are no notifications in the top menu diff --git a/cypress/integration/post/Comment.feature b/cypress/integration/post/Comment.feature new file mode 100644 index 000000000..e7e462824 --- /dev/null +++ b/cypress/integration/post/Comment.feature @@ -0,0 +1,22 @@ +Feature: Post Comment + As a user + I want to comment on contributions of others + To be able to express my thoughts and emotions about these, discuss, and add give further information. + + Background: + Given we have the following posts in our database: + | id | title | slug | + | bWBjpkTKZp | 101 Essays that will change the way you think | 101-essays | + And I have a user account + And I am logged in + + Scenario: Comment creation + Given I visit "post/bWBjpkTKZp/101-essays" + And I type in the following text: + """ + Human Connection rocks + """ + And I click on the "Comment" button + Then my comment should be successfully created + And I should see my comment + And the editor should be cleared diff --git a/cypress/integration/identifier/PersistentLinks.feature b/cypress/integration/post/PersistentLinks.feature similarity index 100% rename from cypress/integration/identifier/PersistentLinks.feature rename to cypress/integration/post/PersistentLinks.feature diff --git a/cypress/integration/06.WritePost.feature b/cypress/integration/post/WritePost.feature similarity index 100% rename from cypress/integration/06.WritePost.feature rename to cypress/integration/post/WritePost.feature diff --git a/cypress/integration/06.Search.feature b/cypress/integration/search/Search.feature similarity index 100% rename from cypress/integration/06.Search.feature rename to cypress/integration/search/Search.feature diff --git a/cypress/integration/settings/ChangePassword.feature b/cypress/integration/user_account/ChangePassword.feature similarity index 100% rename from cypress/integration/settings/ChangePassword.feature rename to cypress/integration/user_account/ChangePassword.feature diff --git a/cypress/integration/01.Login.feature b/cypress/integration/user_account/Login.feature similarity index 100% rename from cypress/integration/01.Login.feature rename to cypress/integration/user_account/Login.feature diff --git a/cypress/integration/04.AboutMeAndLocation.feature b/cypress/integration/user_profile/AboutMeAndLocation.feature similarity index 100% rename from cypress/integration/04.AboutMeAndLocation.feature rename to cypress/integration/user_profile/AboutMeAndLocation.feature diff --git a/cypress/integration/user_profile/SocialMedia.feature b/cypress/integration/user_profile/SocialMedia.feature new file mode 100644 index 000000000..988923c17 --- /dev/null +++ b/cypress/integration/user_profile/SocialMedia.feature @@ -0,0 +1,21 @@ +Feature: List Social Media Accounts + As a User + I'd like to enter my social media + So I can show them to other users to get in contact + + Background: + Given I have a user account + And I am logged in + + Scenario: Adding Social Media + Given I am on the "settings" page + And I click on the "Social media" link + Then I should be on the "/settings/my-social-media" page + When I add a social media link + Then it gets saved successfully + And the new social media link shows up on the page + + Scenario: Other user's viewing my Social Media + Given I have added a social media link + When people visit my profile page + Then they should be able to see my social media links diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 5b4c2055b..a7cb76a27 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -46,7 +46,8 @@ Cypress.Commands.add('login', ({ email, password }) => { cy.get('button[name=submit]') .as('submitButton') .click() - cy.location('pathname').should('eq', '/') // we're in! + cy.get('.iziToast-message').should('contain', 'You are logged in!') + cy.get('.iziToast-close').click() }) Cypress.Commands.add('logout', (email, password) => { diff --git a/deployment/.gitignore b/deployment/.gitignore index aad0daea8..14cfa18ed 100644 --- a/deployment/.gitignore +++ b/deployment/.gitignore @@ -1,3 +1,4 @@ secrets.yaml -*/secrets.yaml -kubeconfig.yaml +configmap.yaml +**/secrets.yaml +**/configmap.yaml diff --git a/deployment/README.md b/deployment/README.md index f8cff30eb..0615ccf9b 100644 --- a/deployment/README.md +++ b/deployment/README.md @@ -1,225 +1,11 @@ -# Human-Connection Nitro | Deployment Configuration -[![Build Status](https://travis-ci.com/Human-Connection/Nitro-Deployment.svg?branch=master)](https://travis-ci.com/Human-Connection/Nitro-Deployment) +# Human-Connection Nitro \| Deployment Configuration -Todos: -- [x] check labels and selectors if they all are correct -- [x] configure NGINX from yml -- [x] configure Let's Encrypt cert-manager from yml -- [x] configure ingress from yml -- [x] configure persistent & shared storage between nodes -- [x] reproduce setup locally +We deploy with [kubernetes](https://kubernetes.io/). In order to deploy your own +network you have to [install kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) +and get a kubernetes cluster. -## Minikube -There are many Kubernetes distributions, but if you're just getting started, -Minikube is a tool that you can use to get your feet wet. +We have tested two different kubernetes providers: [Minikube](./minikube/README.md) +and [Digital Ocean](./digital-ocean/README.md). -[Install Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/) - -Open minikube dashboard: -``` -$ minikube dashboard -``` -This will give you an overview. -Some of the steps below need some timing to make ressources available to other -dependent deployments. Keeping an eye on the dashboard is a great way to check -that. - -Follow the [installation instruction](#installation-with-kubernetes) below. -If all the pods and services have settled and everything looks green in your -minikube dashboard, expose the `nitro-web` service on your host system with: - -```shell -$ minikube service nitro-web --namespace=human-connection -``` - -## Digital Ocean - -1. At first, create a cluster on Digital Ocean. -2. Download the config.yaml if the process has finished. -3. Put the config file where you can find it later (preferable in your home directory under `~/.kube/`) -4. In the open terminal you can set the current config for the active session: `export KUBECONFIG=~/.kube/THE-NAME-OF-YOUR-CLUSTER-kubeconfig.yaml`. You could make this change permanent by adding the line to your `.bashrc` or `~/.config/fish/config.fish` depending on your shell. - - Otherwise you would have to always add `--kubeconfig ~/.kube/THE-NAME-OF-YOUR-CLUSTER-kubeconfig.yaml` on every `kubectl` command that you are running. - -5. Now check if you can connect to the cluster and if its your newly created one by running: `kubectl get nodes` - -If you got the steps right above and see your nodes you can continue. - -First, install kubernetes dashboard: -```sh -$ kubectl apply -f dashboard/ -$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml - -``` -Get your token on the command line: -```sh -$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') -``` -It should print something like: -``` -Name: admin-user-token-6gl6l -Namespace: kube-system -Labels: -Annotations: kubernetes.io/service-account.name=admin-user - kubernetes.io/service-account.uid=b16afba9-dfec-11e7-bbb9-901b0e532516 - -Type: kubernetes.io/service-account-token - -Data -==== -ca.crt: 1025 bytes -namespace: 11 bytes -token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLTZnbDZsIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJiMTZhZmJhOS1kZmVjLTExZTctYmJiOS05MDFiMGU1MzI1MTYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06YWRtaW4tdXNlciJ9.M70CU3lbu3PP4OjhFms8PVL5pQKj-jj4RNSLA4YmQfTXpPUuxqXjiTf094_Rzr0fgN_IVX6gC4fiNUL5ynx9KU-lkPfk0HnX8scxfJNzypL039mpGt0bbe1IXKSIRaq_9VW59Xz-yBUhycYcKPO9RM2Qa1Ax29nqNVko4vLn1_1wPqJ6XSq3GYI8anTzV8Fku4jasUwjrws6Cn6_sPEGmL54sq5R4Z5afUtv-mItTmqZZdxnkRqcJLlg2Y8WbCPogErbsaCDJoABQ7ppaqHetwfM_0yMun6ABOQbIwwl8pspJhpplKwyo700OSpvTT9zlBsu-b35lzXGBRHzv5g_RA - -``` - -Proxy localhost to the remote kubernetes dashboard: -```sh -$ kubectl proxy -``` - -Grab the token from above and paste it into the login screen at [http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/](http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/) - - -## Installation with kubernetes - -You have to do some prerequisites e.g. change some secrets according to your -own setup. - -### Edit secrets - -```sh -$ cp secrets.template.yaml human-connection/secrets.yaml -``` -Change all secrets as needed. - -If you want to edit secrets, you have to `base64` encode them. See [kubernetes -documentation](https://kubernetes.io/docs/concepts/configuration/secret/#creating-a-secret-manually). -```shell -# example how to base64 a string: -$ echo -n 'admin' | base64 -YWRtaW4= -``` -Those secrets get `base64` decoded in a kubernetes pod. - -### Create a namespace -```shell -$ kubectl apply -f namespace-human-connection.yaml -``` -Switch to the namespace `human-connection` in your kubernetes dashboard. - - -### Run the configuration -```shell -$ kubectl apply -f human-connection/ -``` - -This can take a while because kubernetes will download the docker images. -Sit back and relax and have a look into your kubernetes dashboard. -Wait until all pods turn green and they don't show a warning -`Waiting: ContainerCreating` anymore. - -#### Setup Ingress and HTTPS - -Follow [this quick start guide](https://docs.cert-manager.io/en/latest/tutorials/acme/quick-start/index.html) -and install certmanager via helm and tiller: -``` -$ kubectl create serviceaccount tiller --namespace=kube-system -$ kubectl create clusterrolebinding tiller-admin --serviceaccount=kube-system:tiller --clusterrole=cluster-admin -$ helm init --service-account=tiller -$ helm repo update -$ helm install stable/nginx-ingress -$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.6/deploy/manifests/00-crds.yaml -$ helm install --name cert-manager --namespace cert-manager stable/cert-manager -``` - -Create letsencrypt issuers. *Change the email address* in these files before -running this command. -```sh -$ kubectl apply -f human-connection/https/ -``` -Create an ingress service in namespace `human-connection`. *Change the domain -name* according to your needs: -```sh -$ kubectl apply -f human-connection/ingress/ -``` -Check the ingress server is working correctly: -```sh -$ curl -kivL -H 'Host: ' 'https://' -``` -If the response looks good, configure your domain registrar for the new IP -address and the domain. - -Now let's get a valid HTTPS certificate. According to the tutorial above, check -your tls certificate for staging: -```sh -$ kubectl describe --namespace=human-connection certificate tls -$ kubectl describe --namespace=human-connection secret tls -``` - -If everything looks good, update the issuer of your ingress. Change the -annotation `certmanager.k8s.io/issuer` from `letsencrypt-staging` to -`letsencrypt-prod` in your ingress configuration in -`human-connection/ingress/ingress.yaml`. - -```sh -$ kubectl apply -f human-connection/ingress/ingress.yaml -``` -Delete the former secret to force a refresh: -``` -$ kubectl --namespace=human-connection delete secret tls -``` -Now, HTTPS should be configured on your domain. Congrats. - -#### Legacy data migration - -This setup is completely optional and only required if you have data on a server -which is running our legacy code and you want to import that data. It will -import the uploads folder and migrate a dump of mongodb into neo4j. - -##### Prepare migration of Human Connection legacy server -Create a configmap with the specific connection data of your legacy server: -```sh -$ kubectl create configmap db-migration-worker \ - --namespace=human-connection \ - --from-literal=SSH_USERNAME=someuser \ - --from-literal=SSH_HOST=yourhost \ - --from-literal=MONGODB_USERNAME=hc-api \ - --from-literal=MONGODB_PASSWORD=secretpassword \ - --from-literal=MONGODB_AUTH_DB=hc_api \ - --from-literal=MONGODB_DATABASE=hc_api \ - --from-literal=UPLOADS_DIRECTORY=/var/www/api/uploads \ - --from-literal=NEO4J_URI=bolt://localhost:7687 -``` - -Create a secret with your public and private ssh keys. As the -[kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/#use-case-pod-with-ssh-keys) -points out, you should be careful with your ssh keys. Anyone with access to your -cluster will have access to your ssh keys. Better create a new pair with -`ssh-keygen` and copy the public key to your legacy server with `ssh-copy-id`: - -```sh -$ kubectl create secret generic ssh-keys \ - --namespace=human-connection \ - --from-file=id_rsa=/path/to/.ssh/id_rsa \ - --from-file=id_rsa.pub=/path/to/.ssh/id_rsa.pub \ - --from-file=known_hosts=/path/to/.ssh/known_hosts -``` - -##### Migrate legacy database -Patch the existing deployments to use a multi-container setup: -```bash -cd legacy-migration -kubectl apply -f volume-claim-mongo-export.yaml -kubectl patch --namespace=human-connection deployment nitro-backend --patch "$(cat deployment-backend.yaml)" -kubectl patch --namespace=human-connection deployment nitro-neo4j --patch "$(cat deployment-neo4j.yaml)" -cd .. -``` - -Run the migration: -```shell -$ kubectl --namespace=human-connection get pods -# change below -$ kubectl --namespace=human-connection exec -it nitro-neo4j-65bbdb597c-nc2lv migrate -$ kubectl --namespace=human-connection exec -it nitro-backend-c6cc5ff69-8h96z sync_uploads -``` +Check out the specific documentation for your provider. After that, learn how +to apply the specific kubernetes configuration for [Human Connection](./human-connection/README.md). diff --git a/deployment/backup.md b/deployment/backup.md new file mode 100644 index 000000000..5d6d61866 --- /dev/null +++ b/deployment/backup.md @@ -0,0 +1,83 @@ +# Backup (offline) + +This tutorial explains how to carry out an offline backup of your Neo4J +database in a kubernetes cluster. + +An offline backup requires the Neo4J database to be stopped. Read +[the docs](https://neo4j.com/docs/operations-manual/current/tools/dump-load/). +Neo4J also offers online backups but this is available in enterprise edition +only. + +The tricky part is to stop the Neo4J database *without* stopping the container. +Neo4J's docker container image starts `neo4j` by default, so we have to override +this command with sth. that keeps the container spinning but does not terminate +it. + +## Stop and Restart Neo4J Database in Kubernetes + +[This tutorial](http://bigdatums.net/2017/11/07/how-to-keep-docker-containers-running/) +explains how to keep a docker container running. For kubernetes, the way to +override the docker image `CMD` is explained [here](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#define-a-command-and-arguments-when-you-create-a-pod). + +So, all we have to do is edit the kubernetes deployment of our Neo4J database +and set a custom `command` every time we have to carry out tasks like backup, +restore, seed etc. + +{% hint style="info" %} TODO: implement maintenance mode {% endhint %} +First bring the application into maintenance mode to ensure there are no +database connections left and nobody can access the application. + +Run the following: + +```sh +kubectl --namespace=human-connection edit deployment nitro-neo4j +``` + +Add the following to `spec.template.spec.containers`: +``` +["tail", "-f", "/dev/null"] +``` +and write the file which will update the deployment. + +The command `tail -f /dev/null` is the equivalent of *sleep forever*. It is a +hack to keep the container busy and to prevent its shutdown. It will also +override the default `neo4j` command and the kubernetes pod will not start the +database. + +Now perform your tasks! + +When you're done, edit the deployment again and remove the `command`. Write the +file and trigger an update of the deployment. + +## Create a Backup in Kubernetes + +First stop your Neo4J database, see above. Then: +```sh +kubectl --namespace=human-connection get pods +# Copy the ID of the pod running Neo4J. +kubectl --namespace=human-connection exec -it bash +# Once you're in the pod, dump the db to a file e.g. `/root/neo4j-backup`. +neo4j-admin dump --to=/root/neo4j-backup +exit +# Download the file from the pod to your computer. + kubectl cp human-connection/:/root/neo4j-backup ./neo4j-backup +``` +Revert your changes to deployment `nitro-neo4j` which will restart the database. + +## Restore a Backup in Kubernetes + +First stop your Neo4J database. Then: +```sh +kubectl --namespace=human-connection get pods +# Copy the ID of the pod running Neo4J. +# Then upload your local backup to the pod. Note that once the pod gets deleted +# e.g. if you change the deployment, the backup file is gone with it. +kubectl cp ./neo4j-backup human-connection/:/root/ +kubectl --namespace=human-connection exec -it bash +# Once you're in the pod restore the backup and overwrite the default database +# called `graph.db` with `--force`. +# This will delete all existing data in database `graph.db`! +neo4j-admin load --from=/root/neo4j-backup --force +exit +``` +Revert your changes to deployment `nitro-neo4j` which will restart the database. diff --git a/deployment/human-connection/configmap.yaml b/deployment/configmap.template.yaml similarity index 67% rename from deployment/human-connection/configmap.yaml rename to deployment/configmap.template.yaml index 5e4d6ba89..baf41661a 100644 --- a/deployment/human-connection/configmap.yaml +++ b/deployment/configmap.template.yaml @@ -9,8 +9,6 @@ NEO4J_USER: "neo4j" NEO4J_AUTH: "none" CLIENT_URI: "https://nitro-staging.human-connection.org" - MAPBOX_TOKEN: "pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.KZ8KK9l70omjXbEkkbHGsQ" - PRIVATE_KEY_PASSPHRASE: "a7dsf78sadg87ad87sfagsadg78" metadata: name: configmap namespace: human-connection diff --git a/deployment/db-migration-worker.yaml b/deployment/db-migration-worker.yaml deleted file mode 100644 index 55743e360..000000000 --- a/deployment/db-migration-worker.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- - kind: Pod - apiVersion: v1 - metadata: - name: nitro-db-migration-worker - namespace: human-connection - spec: - volumes: - - name: secret-volume - secret: - secretName: ssh-keys - defaultMode: 0400 - - name: mongo-export - persistentVolumeClaim: - claimName: mongo-export-claim - containers: - - name: nitro-db-migration-worker - image: humanconnection/db-migration-worker:latest - envFrom: - - configMapRef: - name: db-migration-worker - volumeMounts: - - name: secret-volume - readOnly: false - mountPath: /root/.ssh - - name: mongo-export - mountPath: /mongo-export/ ---- - kind: PersistentVolumeClaim - apiVersion: v1 - metadata: - name: mongo-export-claim - namespace: human-connection - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi diff --git a/deployment/digital-ocean/README.md b/deployment/digital-ocean/README.md new file mode 100644 index 000000000..12c272691 --- /dev/null +++ b/deployment/digital-ocean/README.md @@ -0,0 +1,26 @@ +# Digital Ocean + +As a start, read the [introduction into kubernetes](https://www.digitalocean.com/community/tutorials/an-introduction-to-kubernetes) by the folks at Digital Ocean. The following section should enable you to deploy Human Connection to your kubernetes cluster. + +## Connect to your local cluster + +1. Create a cluster at [Digital Ocean](https://www.digitalocean.com/). +2. Download the `***-kubeconfig.yaml` from the Web UI. +3. Move the file to the default location where kubectl expects it to be: `mv ***-kubeconfig.yaml ~/.kube/config`. Alternatively you can set the config on every command: `--kubeconfig ***-kubeconfig.yaml` +4. Now check if you can connect to the cluster and if its your newly created one by running: `kubectl get nodes` + +The output should look about like this: +``` +$ kubectl get nodes +NAME STATUS ROLES AGE VERSION +nifty-driscoll-uu1w Ready 69d v1.13.2 +nifty-driscoll-uuiw Ready 69d v1.13.2 +nifty-driscoll-uusn Ready 69d v1.13.2 +``` + +If you got the steps right above and see your nodes you can continue. + +Digital Ocean kubernetes clusters don't have a graphical interface, so I suggest +to setup the [kubernetes dashboard](./dashboard/README.md) as a next step. +Configuring [HTTPS](./https/README.md) is bit tricky and therefore I suggest to +do this as a last step. diff --git a/deployment/digital-ocean/dashboard/README.md b/deployment/digital-ocean/dashboard/README.md new file mode 100644 index 000000000..3ae6378bf --- /dev/null +++ b/deployment/digital-ocean/dashboard/README.md @@ -0,0 +1,55 @@ +# Install Kubernetes Dashboard + +The kubernetes dashboard is optional but very helpful for debugging. If you want to install it, you have to do so only **once** per cluster: + +```bash +# in folder deployment/digital-ocean/ +$ kubectl apply -f dashboard/ +$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml +``` + +### Login to your dashboard + +Proxy the remote kubernetes dashboard to localhost: + +```bash +$ kubectl proxy +``` + +Visit: + +[http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/](http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/) + +You should see a login screen. + +To get your token for the dashboard you can run this command: + +```bash +$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}') +``` + +It should print something like: + +```text +Name: admin-user-token-6gl6l +Namespace: kube-system +Labels: +Annotations: kubernetes.io/service-account.name=admin-user + kubernetes.io/service-account.uid=b16afba9-dfec-11e7-bbb9-901b0e532516 + +Type: kubernetes.io/service-account-token + +Data +==== +ca.crt: 1025 bytes +namespace: 11 bytes +token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLTZnbDZsIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJiMTZhZmJhOS1kZmVjLTExZTctYmJiOS05MDFiMGU1MzI1MTYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06YWRtaW4tdXNlciJ9.M70CU3lbu3PP4OjhFms8PVL5pQKj-jj4RNSLA4YmQfTXpPUuxqXjiTf094_Rzr0fgN_IVX6gC4fiNUL5ynx9KU-lkPfk0HnX8scxfJNzypL039mpGt0bbe1IXKSIRaq_9VW59Xz-yBUhycYcKPO9RM2Qa1Ax29nqNVko4vLn1_1wPqJ6XSq3GYI8anTzV8Fku4jasUwjrws6Cn6_sPEGmL54sq5R4Z5afUtv-mItTmqZZdxnkRqcJLlg2Y8WbCPogErbsaCDJoABQ7ppaqHetwfM_0yMun6ABOQbIwwl8pspJhpplKwyo700OSpvTT9zlBsu-b35lzXGBRHzv5g_RA +``` + +Grab the token from above and paste it into the [login screen](http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/) + +When you are logged in, you should see sth. like: + +![Dashboard](./dashboard-screenshot.png) + +Feel free to save the login token from above in your password manager. Unlike the `kubeconfig` file, this token does not expire. diff --git a/deployment/dashboard/admin-user.yaml b/deployment/digital-ocean/dashboard/admin-user.yaml similarity index 100% rename from deployment/dashboard/admin-user.yaml rename to deployment/digital-ocean/dashboard/admin-user.yaml diff --git a/deployment/digital-ocean/dashboard/dashboard-screenshot.png b/deployment/digital-ocean/dashboard/dashboard-screenshot.png new file mode 100644 index 000000000..6aefb5414 Binary files /dev/null and b/deployment/digital-ocean/dashboard/dashboard-screenshot.png differ diff --git a/deployment/dashboard/role-binding.yaml b/deployment/digital-ocean/dashboard/role-binding.yaml similarity index 100% rename from deployment/dashboard/role-binding.yaml rename to deployment/digital-ocean/dashboard/role-binding.yaml diff --git a/deployment/digital-ocean/https/README.md b/deployment/digital-ocean/https/README.md new file mode 100644 index 000000000..398601e78 --- /dev/null +++ b/deployment/digital-ocean/https/README.md @@ -0,0 +1,57 @@ +# Setup Ingress and HTTPS + +Follow [this quick start guide](https://docs.cert-manager.io/en/latest/tutorials/acme/quick-start/index.html) and install certmanager via helm and tiller: + +```text +$ kubectl create serviceaccount tiller --namespace=kube-system +$ kubectl create clusterrolebinding tiller-admin --serviceaccount=kube-system:tiller --clusterrole=cluster-admin +$ helm init --service-account=tiller +$ helm repo update +$ helm install stable/nginx-ingress +$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.6/deploy/manifests/00-crds.yaml +$ helm install --name cert-manager --namespace cert-manager stable/cert-manager +``` + +Create letsencrypt issuers. _Change the email address_ in these files before running this command. + +```bash +# in folder deployment/digital-ocean/https/ +$ kubectl apply -f issuer.yaml +``` + +Create an ingress service in namespace `human-connection`. _Change the domain name_ according to your needs: + +```bash +# in folder deployment/digital-ocean/https/ +$ kubectl apply -f ingress.yaml +``` + +Check the ingress server is working correctly: + +```bash +$ curl -kivL -H 'Host: ' 'https://' +``` + +If the response looks good, configure your domain registrar for the new IP address and the domain. + +Now let's get a valid HTTPS certificate. According to the tutorial above, check your tls certificate for staging: + +```bash +$ kubectl describe --namespace=human-connection certificate tls +$ kubectl describe --namespace=human-connection secret tls +``` + +If everything looks good, update the issuer of your ingress. Change the annotation `certmanager.k8s.io/issuer` from `letsencrypt-staging` to `letsencrypt-prod` in your ingress configuration in `ingress.yaml`. + +```bash +# in folder deployment/digital-ocean/https/ +$ kubectl apply -f ingress.yaml +``` + +Delete the former secret to force a refresh: + +```text +$ kubectl --namespace=human-connection delete secret tls +``` + +Now, HTTPS should be configured on your domain. Congrats. diff --git a/deployment/human-connection/ingress/ingress.yaml b/deployment/digital-ocean/https/ingress.yaml similarity index 100% rename from deployment/human-connection/ingress/ingress.yaml rename to deployment/digital-ocean/https/ingress.yaml diff --git a/deployment/human-connection/https/issuer.yaml b/deployment/digital-ocean/https/issuer.yaml similarity index 100% rename from deployment/human-connection/https/issuer.yaml rename to deployment/digital-ocean/https/issuer.yaml diff --git a/deployment/human-connection/README.md b/deployment/human-connection/README.md new file mode 100644 index 000000000..d6a2dd989 --- /dev/null +++ b/deployment/human-connection/README.md @@ -0,0 +1,58 @@ +# Kubernetes Configuration for Human Connection + +Deploying Human Connection with kubernetes is straight forward. All you have to +do is to change certain parameters, like domain names and API keys, then you +just apply our provided configuration files to your cluster. + +## Configuration + +Copy our provided templates: + +```bash +$ cp secrets.template.yaml human-connection/secrets.yaml +$ cp configmap.template.yaml human-connection/configmap.yaml +``` + +Change the `configmap.yaml` as needed, all variables will be available as +environment variables in your deployed kubernetes pods. + +If you want to edit secrets, you have to `base64` encode them. See [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/#creating-a-secret-manually). + +```bash +# example how to base64 a string: +$ echo -n 'admin' | base64 --wrap 0 +YWRtaW4= +``` + +Those secrets get `base64` decoded and are available as environment variables in +your deployed kubernetes pods. + +## Create a namespace + +```bash +$ kubectl apply -f namespace-human-connection.yaml +``` + +If you have a [kubernets dashboard](../digital-ocean/dashboard/README.md) +deployed you should switch to namespace `human-connection` in order to +monitor the state of your deployments. + +## Create persistent volumes + +While the deployments and services can easily be restored, simply by deleting +and applying the kubernetes configurations again, certain data is not that +easily recovered. Therefore we separated persistent volumes from deployments +and services. There is a [dedicated section](../volumes/README.md). Create those +persistent volumes once before you apply the configuration. + +## Apply the configuration + +```bash +# in folder deployment/ +$ kubectl apply -f human-connection/ +``` + +This can take a while because kubernetes will download the docker images. Sit +back and relax and have a look into your kubernetes dashboard. Wait until all +pods turn green and they don't show a warning `Waiting: ContainerCreating` +anymore. diff --git a/deployment/human-connection/deployment-backend.yaml b/deployment/human-connection/deployment-backend.yaml index 29992ef7e..a873b7bb2 100644 --- a/deployment/human-connection/deployment-backend.yaml +++ b/deployment/human-connection/deployment-backend.yaml @@ -43,15 +43,3 @@ restartPolicy: Always terminationGracePeriodSeconds: 30 status: {} ---- - kind: PersistentVolumeClaim - apiVersion: v1 - metadata: - name: uploads-claim - namespace: human-connection - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi diff --git a/deployment/human-connection/deployment-neo4j.yaml b/deployment/human-connection/deployment-neo4j.yaml index 2c76a3322..4a715da76 100644 --- a/deployment/human-connection/deployment-neo4j.yaml +++ b/deployment/human-connection/deployment-neo4j.yaml @@ -6,6 +6,10 @@ namespace: human-connection spec: replicas: 1 + strategy: + rollingUpdate: + maxSurge: 0 + maxUnavailable: "100%" selector: matchLabels: human-connection.org/selector: deployment-human-connection-neo4j @@ -53,15 +57,3 @@ claimName: neo4j-data-claim restartPolicy: Always terminationGracePeriodSeconds: 30 ---- - kind: PersistentVolumeClaim - apiVersion: v1 - metadata: - name: neo4j-data-claim - namespace: human-connection - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi diff --git a/deployment/legacy-migration/README.md b/deployment/legacy-migration/README.md new file mode 100644 index 000000000..8cc7bd746 --- /dev/null +++ b/deployment/legacy-migration/README.md @@ -0,0 +1,85 @@ +# Legacy data migration + +This setup is **completely optional** and only required if you have data on a +server which is running our legacy code and you want to import that data. It +will import the uploads folder and migrate a dump of the legacy Mongo database +into our new Neo4J graph database. + +## Configure Maintenance-Worker Pod + +Create a configmap with the specific connection data of your legacy server: + +```bash +$ kubectl create configmap maintenance-worker \ + --namespace=human-connection \ + --from-literal=SSH_USERNAME=someuser \ + --from-literal=SSH_HOST=yourhost \ + --from-literal=MONGODB_USERNAME=hc-api \ + --from-literal=MONGODB_PASSWORD=secretpassword \ + --from-literal=MONGODB_AUTH_DB=hc_api \ + --from-literal=MONGODB_DATABASE=hc_api \ + --from-literal=UPLOADS_DIRECTORY=/var/www/api/uploads +``` + +Create a secret with your public and private ssh keys. As the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/#use-case-pod-with-ssh-keys) points out, you should be careful with your ssh keys. Anyone with access to your cluster will have access to your ssh keys. Better create a new pair with `ssh-keygen` and copy the public key to your legacy server with `ssh-copy-id`: + +```bash +$ kubectl create secret generic ssh-keys \ + --namespace=human-connection \ + --from-file=id_rsa=/path/to/.ssh/id_rsa \ + --from-file=id_rsa.pub=/path/to/.ssh/id_rsa.pub \ + --from-file=known_hosts=/path/to/.ssh/known_hosts +``` + +## Deploy a Temporary Maintenance-Worker Pod + +Bring the application into maintenance mode. + +{% hint style="info" %} TODO: implement maintenance mode {% endhint %} + + +Then temporarily delete backend and database deployments + +```bash +$ kubectl --namespace=human-connection get deployments +NAME READY UP-TO-DATE AVAILABLE AGE +nitro-backend 1/1 1 1 3d11h +nitro-neo4j 1/1 1 1 3d11h +nitro-web 2/2 2 2 73d +$ kubectl --namespace=human-connection delete deployment nitro-neo4j +deployment.extensions "nitro-neo4j" deleted +$ kubectl --namespace=human-connection delete deployment nitro-backend +deployment.extensions "nitro-backend" deleted +``` + +Deploy one-time maintenance-worker pod: + +```bash +# in deployment/legacy-migration/ +$ kubectl apply -f db-migration-worker.yaml +pod/nitro-maintenance-worker created +``` + +Import legacy database and uploads: + +```bash +$ kubectl --namespace=human-connection exec -it nitro-maintenance-worker bash +$ import_legacy_db +$ import_uploads +$ exit +``` + +Delete the pod when you're done: + +```bash +$ kubectl --namespace=human-connection delete pod nitro-maintenance-worker +``` + +Oh, and of course you have to get those deleted deployments back. One way of +doing it would be: + +```bash +# in folder deployment/ +$ kubectl apply -f human-connection/deployment-backend.yaml -f human-connection/deployment-neo4j.yaml +``` + diff --git a/deployment/legacy-migration/deployment-backend.yaml b/deployment/legacy-migration/deployment-backend.yaml deleted file mode 100644 index 1adeb0665..000000000 --- a/deployment/legacy-migration/deployment-backend.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- - apiVersion: extensions/v1beta1 - kind: Deployment - metadata: - name: nitro-backend - namespace: human-connection - spec: - template: - spec: - containers: - - name: nitro-db-migration-worker - image: humanconnection/db-migration-worker:latest - imagePullPolicy: Always - envFrom: - - configMapRef: - name: db-migration-worker - volumeMounts: - - name: secret-volume - readOnly: false - mountPath: /root/.ssh - - name: uploads - mountPath: /uploads/ - volumes: - - name: secret-volume - secret: - secretName: ssh-keys - defaultMode: 0400 diff --git a/deployment/legacy-migration/deployment-neo4j.yaml b/deployment/legacy-migration/deployment-neo4j.yaml deleted file mode 100644 index 2852b90cb..000000000 --- a/deployment/legacy-migration/deployment-neo4j.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- - apiVersion: extensions/v1beta1 - kind: Deployment - metadata: - name: nitro-neo4j - namespace: human-connection - spec: - template: - spec: - containers: - - name: nitro-db-migration-worker - image: humanconnection/db-migration-worker:latest - imagePullPolicy: Always - envFrom: - - configMapRef: - name: db-migration-worker - env: - - name: COMMIT - value: - - name: NEO4J_URI - value: bolt://localhost:7687 - volumeMounts: - - name: secret-volume - readOnly: false - mountPath: /root/.ssh - - name: mongo-export - mountPath: /mongo-export/ - - name: nitro-neo4j - volumeMounts: - - mountPath: /mongo-export/ - name: mongo-export - volumes: - - name: secret-volume - secret: - secretName: ssh-keys - defaultMode: 0400 - - name: mongo-export - persistentVolumeClaim: - claimName: mongo-export-claim diff --git a/deployment/legacy-migration/maintenance-worker.yaml b/deployment/legacy-migration/maintenance-worker.yaml new file mode 100644 index 000000000..cda17400a --- /dev/null +++ b/deployment/legacy-migration/maintenance-worker.yaml @@ -0,0 +1,34 @@ +--- + kind: Pod + apiVersion: v1 + metadata: + name: nitro-maintenance-worker + namespace: human-connection + spec: + containers: + - name: nitro-maintenance-worker + image: humanconnection/maintenance-worker:latest + envFrom: + - configMapRef: + name: maintenance-worker + - configMapRef: + name: configmap + volumeMounts: + - name: secret-volume + readOnly: false + mountPath: /root/.ssh + - name: uploads + mountPath: /nitro-backend/public/uploads + - name: neo4j-data + mountPath: /data/ + volumes: + - name: secret-volume + secret: + secretName: ssh-keys + defaultMode: 0400 + - name: uploads + persistentVolumeClaim: + claimName: uploads-claim + - name: neo4j-data + persistentVolumeClaim: + claimName: neo4j-data-claim diff --git a/backend/db-migration-worker/.dockerignore b/deployment/legacy-migration/maintenance-worker/.dockerignore similarity index 100% rename from backend/db-migration-worker/.dockerignore rename to deployment/legacy-migration/maintenance-worker/.dockerignore diff --git a/backend/db-migration-worker/.gitignore b/deployment/legacy-migration/maintenance-worker/.gitignore similarity index 100% rename from backend/db-migration-worker/.gitignore rename to deployment/legacy-migration/maintenance-worker/.gitignore diff --git a/deployment/legacy-migration/maintenance-worker/Dockerfile b/deployment/legacy-migration/maintenance-worker/Dockerfile new file mode 100644 index 000000000..1fafce5e8 --- /dev/null +++ b/deployment/legacy-migration/maintenance-worker/Dockerfile @@ -0,0 +1,11 @@ +FROM humanconnection/neo4j:latest + +ENV NODE_ENV=maintenance +EXPOSE 7687 7474 + +RUN apk upgrade --update +RUN apk add --no-cache mongodb-tools openssh nodejs yarn rsync + +COPY known_hosts /root/.ssh/known_hosts +COPY migration ./migration +COPY ./binaries/* /usr/local/bin/ diff --git a/deployment/legacy-migration/maintenance-worker/binaries/create_private_ssh_key_from_env b/deployment/legacy-migration/maintenance-worker/binaries/create_private_ssh_key_from_env new file mode 100755 index 000000000..f44671978 --- /dev/null +++ b/deployment/legacy-migration/maintenance-worker/binaries/create_private_ssh_key_from_env @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -e + +mkdir -p ~/.ssh +echo $SSH_PRIVATE_KEY | base64 -d > ~/.ssh/id_rsa +chmod 600 ~/.ssh/id_rsa diff --git a/backend/db-migration-worker/migrate.sh b/deployment/legacy-migration/maintenance-worker/binaries/import_legacy_db similarity index 100% rename from backend/db-migration-worker/migrate.sh rename to deployment/legacy-migration/maintenance-worker/binaries/import_legacy_db diff --git a/backend/db-migration-worker/sync_uploads.sh b/deployment/legacy-migration/maintenance-worker/binaries/import_legacy_uploads similarity index 81% rename from backend/db-migration-worker/sync_uploads.sh rename to deployment/legacy-migration/maintenance-worker/binaries/import_legacy_uploads index d24936e3b..24ae0fca5 100755 --- a/backend/db-migration-worker/sync_uploads.sh +++ b/deployment/legacy-migration/maintenance-worker/binaries/import_legacy_uploads @@ -9,4 +9,5 @@ do fi done +[ -z "$SSH_PRIVATE_KEY" ] || create_private_ssh_key_from_env rsync --archive --update --verbose ${SSH_USERNAME}@${SSH_HOST}:${UPLOADS_DIRECTORY}/* /uploads/ diff --git a/deployment/legacy-migration/maintenance-worker/docker-compose.yml b/deployment/legacy-migration/maintenance-worker/docker-compose.yml new file mode 100644 index 000000000..a45a5163a --- /dev/null +++ b/deployment/legacy-migration/maintenance-worker/docker-compose.yml @@ -0,0 +1,42 @@ +version: "3.4" + +services: + maintenance: + image: humanconnection/maintenance-worker:latest + build: + context: . + volumes: + - uploads:/uploads + - neo4j-data:/data + - ./migration/:/migration + networks: + - hc-network + environment: + - GRAPHQL_PORT=4000 + - GRAPHQL_URI=http://localhost:4000 + - CLIENT_URI=http://localhost:3000 + - JWT_SECRET=b/&&7b78BF&fv/Vd + - MOCK=false + - MAPBOX_TOKEN=pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.KZ8KK9l70omjXbEkkbHGsQ + - PRIVATE_KEY_PASSPHRASE=a7dsf78sadg87ad87sfagsadg78 + - NEO4J_URI=bolt://localhost:7687 + - NEO4J_apoc_import_file_enabled=true + - NEO4J_AUTH=none + - "SSH_USERNAME=${SSH_USERNAME}" + - "SSH_HOST=${SSH_HOST}" + - "SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}" + - "MONGODB_USERNAME=${MONGODB_USERNAME}" + - "MONGODB_PASSWORD=${MONGODB_PASSWORD}" + - "MONGODB_AUTH_DB=${MONGODB_AUTH_DB}" + - "MONGODB_DATABASE=${MONGODB_DATABASE}" + - "UPLOADS_DIRECTORY=${UPLOADS_DIRECTORY}" + ports: + - 7687:7687 + - 7474:7474 + +volumes: + uploads: + neo4j-data: + +networks: + hc-network: diff --git a/backend/db-migration-worker/.ssh/known_hosts b/deployment/legacy-migration/maintenance-worker/known_hosts similarity index 100% rename from backend/db-migration-worker/.ssh/known_hosts rename to deployment/legacy-migration/maintenance-worker/known_hosts diff --git a/backend/db-migration-worker/migration/mongo/import.sh b/deployment/legacy-migration/maintenance-worker/migration/mongo/import.sh similarity index 61% rename from backend/db-migration-worker/migration/mongo/import.sh rename to deployment/legacy-migration/maintenance-worker/migration/mongo/import.sh index 7cf3e91e4..328560bfc 100755 --- a/backend/db-migration-worker/migration/mongo/import.sh +++ b/deployment/legacy-migration/maintenance-worker/migration/mongo/import.sh @@ -9,16 +9,17 @@ echo "MONGODB_DATABASE ${MONGODB_DATABASE}" echo "MONGODB_AUTH_DB ${MONGODB_AUTH_DB}" echo "-------------------------------------------------" -mongo ${MONGODB_DATABASE} --eval "db.dropDatabase();" -rm -rf /mongo-export/* +[ -z "$SSH_PRIVATE_KEY" ] || create_private_ssh_key_from_env + +rm -rf /tmp/mongo-export/* +mkdir -p /tmp/mongo-export ssh -4 -M -S my-ctrl-socket -fnNT -L 27018:localhost:27017 -l ${SSH_USERNAME} ${SSH_HOST} -mongodump --host localhost -d ${MONGODB_DATABASE} --port 27018 --username ${MONGODB_USERNAME} --password ${MONGODB_PASSWORD} --authenticationDatabase ${MONGODB_AUTH_DB} --gzip --archive=/tmp/mongodump.archive -mongorestore --gzip --archive=/tmp/mongodump.archive -ssh -S my-ctrl-socket -O check -l ${SSH_USERNAME} ${SSH_HOST} -ssh -S my-ctrl-socket -O exit -l ${SSH_USERNAME} ${SSH_HOST} for collection in "categories" "badges" "users" "contributions" "comments" "follows" "shouts" do - mongoexport --db ${MONGODB_DATABASE} --collection $collection --out "/mongo-export/$collection.json" + mongoexport --host localhost -d ${MONGODB_DATABASE} --port 27018 --username ${MONGODB_USERNAME} --password ${MONGODB_PASSWORD} --authenticationDatabase ${MONGODB_AUTH_DB} --db ${MONGODB_DATABASE} --collection $collection --out "/tmp/mongo-export/$collection.json" done + +ssh -S my-ctrl-socket -O check -l ${SSH_USERNAME} ${SSH_HOST} +ssh -S my-ctrl-socket -O exit -l ${SSH_USERNAME} ${SSH_HOST} diff --git a/backend/db-migration-worker/migration/neo4j/badges.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/badges.cql similarity index 75% rename from backend/db-migration-worker/migration/neo4j/badges.cql rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/badges.cql index 90e4755b4..f4bf67dda 100644 --- a/backend/db-migration-worker/migration/neo4j/badges.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/badges.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/mongo-export/badges.json') YIELD value as badge +CALL apoc.load.json('file:/tmp/mongo-export/badges.json') YIELD value as badge MERGE(b:Badge {id: badge._id["$oid"]}) ON CREATE SET b.key = badge.key, diff --git a/backend/db-migration-worker/migration/neo4j/categories.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/categories.cql similarity index 94% rename from backend/db-migration-worker/migration/neo4j/categories.cql rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/categories.cql index a2bf6a352..c22354cbe 100644 --- a/backend/db-migration-worker/migration/neo4j/categories.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/categories.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/mongo-export/categories.json') YIELD value as category +CALL apoc.load.json('file:/tmp/mongo-export/categories.json') YIELD value as category MERGE(c:Category {id: category._id["$oid"]}) ON CREATE SET c.name = category.title, diff --git a/backend/db-migration-worker/migration/neo4j/comments.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/comments.cql similarity index 84% rename from backend/db-migration-worker/migration/neo4j/comments.cql rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/comments.cql index 6709acbc8..eb645108a 100644 --- a/backend/db-migration-worker/migration/neo4j/comments.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/comments.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/mongo-export/comments.json') YIELD value as json +CALL apoc.load.json('file:/tmp/mongo-export/comments.json') YIELD value as json MERGE (comment:Comment {id: json._id["$oid"]}) ON CREATE SET comment.content = json.content, diff --git a/backend/db-migration-worker/migration/neo4j/contributions.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/contributions.cql similarity index 89% rename from backend/db-migration-worker/migration/neo4j/contributions.cql rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/contributions.cql index 0c7b18959..134c276cf 100644 --- a/backend/db-migration-worker/migration/neo4j/contributions.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/contributions.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/mongo-export/contributions.json') YIELD value as post +CALL apoc.load.json('file:/tmp/mongo-export/contributions.json') YIELD value as post MERGE (p:Post {id: post._id["$oid"]}) ON CREATE SET p.title = post.title, diff --git a/backend/db-migration-worker/migration/neo4j/follows.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows.cql similarity index 55% rename from backend/db-migration-worker/migration/neo4j/follows.cql rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/follows.cql index 0dad6a435..6f5416723 100644 --- a/backend/db-migration-worker/migration/neo4j/follows.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/mongo-export/follows.json') YIELD value as follow +CALL apoc.load.json('file:/tmp/mongo-export/follows.json') YIELD value as follow MATCH (u1:User {id: follow.userId}), (u2:User {id: follow.foreignId}) MERGE (u1)-[:FOLLOWS]->(u2) ; diff --git a/backend/db-migration-worker/migration/neo4j/import.sh b/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh similarity index 100% rename from backend/db-migration-worker/migration/neo4j/import.sh rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh diff --git a/backend/db-migration-worker/migration/neo4j/shouts.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/shouts.cql similarity index 54% rename from backend/db-migration-worker/migration/neo4j/shouts.cql rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/shouts.cql index 60aca50c9..cd72ab66b 100644 --- a/backend/db-migration-worker/migration/neo4j/shouts.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/shouts.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/mongo-export/shouts.json') YIELD value as shout +CALL apoc.load.json('file:/tmp/mongo-export/shouts.json') YIELD value as shout MATCH (u:User {id: shout.userId}), (p:Post {id: shout.foreignId}) MERGE (u)-[:SHOUTED]->(p) ; diff --git a/backend/db-migration-worker/migration/neo4j/users.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/users.cql similarity index 87% rename from backend/db-migration-worker/migration/neo4j/users.cql rename to deployment/legacy-migration/maintenance-worker/migration/neo4j/users.cql index 5f87bb273..22eb46882 100644 --- a/backend/db-migration-worker/migration/neo4j/users.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/users.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/mongo-export/users.json') YIELD value as user +CALL apoc.load.json('file:/tmp/mongo-export/users.json') YIELD value as user MERGE(u:User {id: user._id["$oid"]}) ON CREATE SET u.name = user.name, diff --git a/deployment/minikube/README.md b/deployment/minikube/README.md new file mode 100644 index 000000000..e77ddd667 --- /dev/null +++ b/deployment/minikube/README.md @@ -0,0 +1,25 @@ +# Minikube + +There are many Kubernetes providers, but if you're just getting started, Minikube is a tool that you can use to get your feet wet. + +After you [installed Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/) +open your minikube dashboard: + +```text +$ minikube dashboard +``` + +This will give you an overview. Some of the steps below need some timing to make ressources available to other dependent deployments. Keeping an eye on the dashboard is a great way to check that. + +Follow the installation instruction for [Human Connection](../human-connection/README.md). +If all the pods and services have settled and everything looks green in your +minikube dashboard, expose the services you want on your host system. + +For example: + +```text +$ minikube service nitro-web --namespace=human-connection +# optionally +$ minikube service nitro-backend --namespace=human-connection +``` + diff --git a/deployment/secrets.template.yaml b/deployment/secrets.template.yaml index ac56b7aa1..8f18dbf46 100644 --- a/deployment/secrets.template.yaml +++ b/deployment/secrets.template.yaml @@ -4,6 +4,7 @@ data: JWT_SECRET: "Yi8mJjdiNzhCRiZmdi9WZA==" MONGODB_PASSWORD: "TU9OR09EQl9QQVNTV09SRA==" PRIVATE_KEY_PASSPHRASE: "YTdkc2Y3OHNhZGc4N2FkODdzZmFnc2FkZzc4" + MAPBOX_TOKEN: "cGsuZXlKMUlqb2lhSFZ0WVc0dFkyOXVibVZqZEdsdmJpSXNJbUVpT2lKamFqbDBjbkJ1Ykdvd2VUVmxNM1Z3WjJsek5UTnVkM1p0SW4wLktaOEtLOWw3MG9talhiRWtrYkhHc1EK" metadata: name: human-connection namespace: human-connection diff --git a/deployment/volumes/README.md b/deployment/volumes/README.md new file mode 100644 index 000000000..b838794d5 --- /dev/null +++ b/deployment/volumes/README.md @@ -0,0 +1,42 @@ +# Persistent Volumes + +At the moment, the application needs two persistent volumes: + +* The `/data/` folder where `neo4j` stores its database and +* the folder `/nitro-backend/public/uploads` where the backend stores uploads. + +As a matter of precaution, the persistent volume claims that setup these volumes +live in a separate folder. You don't want to accidently loose all your data in +your database by running `kubectl delete -f human-connection/`, do you? + +## Create Persistent Volume Claims + +Run the following: +```sh +# in folder deployments/ +$ kubectl apply -f volumes +persistentvolumeclaim/neo4j-data-claim created +persistentvolumeclaim/uploads-claim created +``` + +## Change Reclaim Policy + +We recommend to change the `ReclaimPolicy`, so if you delete the persistent +volume claims, the associated volumes will be released, not deleted: + +```sh +$ kubectl --namespace=human-connection get pv + +NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE +pvc-bd02a715-66d0-11e9-be52-ba9c337f4551 1Gi RWO Delete Bound human-connection/neo4j-data-claim do-block-storage 4m24s +pvc-bd208086-66d0-11e9-be52-ba9c337f4551 2Gi RWO Delete Bound human-connection/uploads-claim do-block-storage 4m12s +``` + +Get the volume id from above, then change `ReclaimPolicy` with: +```sh +kubectl patch pv -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' + +# in the above example +kubectl patch pv pvc-bd02a715-66d0-11e9-be52-ba9c337f4551 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' +kubectl patch pv pvc-bd208086-66d0-11e9-be52-ba9c337f4551 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' +``` diff --git a/deployment/legacy-migration/volume-claim-mongo-export.yaml b/deployment/volumes/neo4j-data.yaml similarity index 86% rename from deployment/legacy-migration/volume-claim-mongo-export.yaml rename to deployment/volumes/neo4j-data.yaml index 106ef4736..f077be933 100644 --- a/deployment/legacy-migration/volume-claim-mongo-export.yaml +++ b/deployment/volumes/neo4j-data.yaml @@ -2,7 +2,7 @@ kind: PersistentVolumeClaim apiVersion: v1 metadata: - name: mongo-export-claim + name: neo4j-data-claim namespace: human-connection spec: accessModes: diff --git a/deployment/volumes/uploads.yaml b/deployment/volumes/uploads.yaml new file mode 100644 index 000000000..11a8027e9 --- /dev/null +++ b/deployment/volumes/uploads.yaml @@ -0,0 +1,12 @@ +--- + kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: uploads-claim + namespace: human-connection + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi diff --git a/docker-compose.yml b/docker-compose.yml index a7e7c0802..896d1bef9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,7 +38,7 @@ services: neo4j: image: humanconnection/neo4j:latest build: - context: backend/neo4j + context: neo4j networks: - hc-network diff --git a/edit-this-documentation.md b/edit-this-documentation.md new file mode 100644 index 000000000..b01ace78f --- /dev/null +++ b/edit-this-documentation.md @@ -0,0 +1,120 @@ +# Edit this Documentation + +Go to the section and theme you want to change: On the left navigator. + +Click **Edit on GitHub** on the right. + +On the **Issue** tab you’ll find the open issues. Read what need to be done by clicking on the issue you like to fix. + +By going backwards in the browser **\(!\)**, again go to the **Code** tab. + +Click on the **edit pencil** on the right side directly above the text to edit this file on your fork of Human Connection \(HC\). + +You can see a preview of your changes by clicking the **Preview changes** tab aside the **Edit file** tab. + +If you are ready, fill in the **Propose file change** at the end of the webpage. + +After that you have to send your change to the HC basis with a pull request. Here make a comment which issue you have fixed. At least the number. + +## Markdown your documentation + +To design your documentation see the syntax description at GitBook: + +[https://toolchain.gitbook.com/syntax/markdown.html](https://toolchain.gitbook.com/syntax/markdown.html) + +### Some quick Examples + +#### Headlines + +```text +# Main headline +## Smaller headlines +### Small headlines +``` + +#### Tabs + +```text +{% tabs %} +{% tab title="XXX" %} +XXX +{% endtab %} +{% tab title="XXX" %} +XXX +{% endtab %} +… +{% endtabs %} +``` + +#### Commands + +```text +```LANGUAGE (for text highlighting) +XXX +``` + +```text +#### Links + +```text +[https://XXX](XXX) +``` + +#### Screenshots or other Images + +```text +![XXX](https://XXX) +``` + +#### Hints for ToDos + +```text +{% hint style="info" %} TODO: XXX {% endhint %} +``` + +## Host the screenshots + +### Host on Human Connection + +{% hint style="info" %} +TODO: How to host on Human Connection \(GitHub\) ... +{% endhint %} + +### Quick Solution + +To quickly host the screenshots go to: + +[https://imgur.com](https://imgur.com). + +There click the green button **New post**. + +Drag the image into the appropriate area. + +Right click on it and choose kind of **Open link in new tab**. + +Copy the URL and paste it were you need it. + +## Screenshot modification + +### Add an arrow or some other marking stuff + +{% tabs %} +{% tab title="macOS" %} +#### In the Preview App + +Got to: **Menu** + **Tools** \(GER: Werkzeuge\) + **Annotate** \(GER: Anmerkungen\) + etc. +{% endtab %} + +{% tab title="Windows" %} +{% hint style="info" %} +TODO: How to modify screenshots in Windows ... +{% endhint %} +{% endtab %} + +{% tab title="Linux" %} +{% hint style="info" %} +TODO: How to modify screenshots in Linux ... +{% endhint %} +{% endtab %} +{% endtabs %} + diff --git a/installation.md b/installation.md new file mode 100644 index 000000000..37531f95d --- /dev/null +++ b/installation.md @@ -0,0 +1,82 @@ +# Installation + +The repository can be found on GitHub. [https://github.com/Human-Connection/Human-Connection](https://github.com/Human-Connection/Human-Connection) + +We give write permissions to every developer who asks for it. Just text us on +[Discord](https://discord.gg/6ub73U3). + +## Clone the Repository + + +Clone the repository, this will create a new folder called `Human-Connection`: + +{% tabs %} +{% tab title="HTTPS" %} +```bash +$ git clone https://github.com/Human-Connection/Human-Connection.git +``` +{% endtab %} + +{% tab title="SSH" %} +```bash +$ git clone git@github.com:Human-Connection/Human-Connection.git +``` +{% endtab %} +{% endtabs %} + +Change into the new folder. + +```bash +$ cd Human-Connection +``` + +## Directory Layout + +There are four important directories: +* [Backend](./backend) runs on the server and is a middleware between database and frontend +* [Frontend](./webapp) is a server-side-rendered and client-side-rendered web frontend +* [Deployment](./deployment) configuration for kubernetes +* [Cypress](./cypress) contains end-to-end tests and executable feature specifications + +In order to setup the application and start to develop features you have to +setup **frontend** and **backend**. + +There are two approaches: + +1. Local installation, which means you have to take care of dependencies yourself +2. **Or** Install everything through docker which takes care of dependencies for you + +## Docker Installation + +Docker is a software development container tool that combines software and its dependencies into one standardized unit that contains everything needed to run it. This helps us to avoid problems with dependencies and makes installation easier. + +### General Installation of Docker + +There are [sevaral ways to install Docker CE](https://docs.docker.com/install/) on your computer or server. + +{% tabs %} +{% tab title="Docker Desktop macOS" %} +Follow these instructions to [install Docker Desktop on macOS](https://docs.docker.com/docker-for-mac/install/). +{% endtab %} + +{% tab title="Docker Desktop Windows" %} +Follow these instructions to [install Docker Desktop on Windows](https://docs.docker.com/docker-for-windows/install/). +{% endtab %} + +{% tab title="Docker CE" %} +Follow these instructions to [install Docker CE](https://docs.docker.com/install/). + +This is a great option for Linux users. +{% endtab %} +{% endtabs %} + +Check the correct Docker installation by checking the version before proceeding. E.g. we have the following versions: + +```bash +$ docker --version +Docker version 18.09.2 +$ docker-compose --version +docker-compose version 1.23.2 +``` + + diff --git a/backend/neo4j/Dockerfile b/neo4j/Dockerfile similarity index 90% rename from backend/neo4j/Dockerfile rename to neo4j/Dockerfile index 79f1e5200..a02d41f38 100644 --- a/backend/neo4j/Dockerfile +++ b/neo4j/Dockerfile @@ -1,3 +1,3 @@ -FROM neo4j:3.5.3 +FROM neo4j:3.5.4 RUN wget https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/download/3.5.0.1/apoc-3.5.0.1-all.jar -P plugins/ COPY migrate.sh /usr/local/bin/migrate diff --git a/backend/neo4j/migrate.sh b/neo4j/migrate.sh similarity index 100% rename from backend/neo4j/migrate.sh rename to neo4j/migrate.sh diff --git a/package.json b/package.json index be1e4a90d..703997ee1 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "nonGlobalStepDefinitions": true }, "scripts": { + "db:seed": "cd backend && yarn run db:seed", + "db:reset": "cd backend && yarn run db:reset", "cypress:backend:server": "cd backend && yarn run test:before:server", "cypress:backend:seeder": "cd backend && yarn run test:before:seeder", "cypress:webapp": "cd webapp && cross-env GRAPHQL_URI=http://localhost:4123 yarn run dev", diff --git a/testing.md b/testing.md new file mode 100644 index 000000000..2414c748f --- /dev/null +++ b/testing.md @@ -0,0 +1,20 @@ +# Testing Guide + +## End-to-End Testing + +To test all the pieces together, from the user perspective, we use integration tests. They also show if the the backend and the frontend are working as expected in conjunction and also if the browser likes our app. + +[more...](cypress/README.md) + +## Component Testing + +Individual Vue Components should also be documented and tested properly. This guarantees that they are reusable and the api gets more solid in the process. + +[more...](webapp/testing.md) + +## Unit Testing + +Expecially the Backend relies on Unit Tests, as there are no Vue Components. + +[more...](backend/testing.md) + diff --git a/webapp/README.md b/webapp/README.md index d395a54e0..ce27eca2f 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -1,40 +1,33 @@ -

- Human Connection -

+# Webapp -# NITRO Web -[![Build Status](https://img.shields.io/travis/com/Human-Connection/Nitro-Web/master.svg)](https://travis-ci.com/Human-Connection/Nitro-Web) -[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/Human-Connection/Nitro-Web/blob/master/LICENSE.md) -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Web.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Web?ref=badge_shield) -[![Discord Channel](https://img.shields.io/discord/489522408076738561.svg)](https://discord.gg/6ub73U3) +![UI Screenshot](../.gitbook/assets/screenshot.png) -![UI Screenshot](screenshot.png) +## Installation -## Build Setup - - - -### Install -``` bash +```bash # install all dependencies $ yarn install ``` Copy: -``` + +```text cp .env.template .env cp cypress.env.template.json cypress.env.json ``` + Configure the files according to your needs and your local setup. -### Development -``` bash +### Build for Development + +```bash # serve with hot reload at localhost:3000 $ yarn dev ``` -### Build for production -``` bash +### Build for Production + +```bash # build for production and launch server $ yarn build $ yarn start @@ -42,27 +35,10 @@ $ yarn start ## Styleguide -All reusable Components (for example avatar) should be done inside the [Nitro-Styleguide](https://github.com/Human-Connection/Nitro-Styleguide) repository. +All reusable Components \(for example avatar\) should be done inside the [Nitro-Styleguide](https://github.com/Human-Connection/Nitro-Styleguide) repository. -![Styleguide Screenshot](screenshot-styleguide.png) +![Styleguide Screenshot](../.gitbook/assets/screenshot-styleguide%20%281%29.png) -More information can be found here: https://github.com/Human-Connection/Nitro-Styleguide +More information can be found here: [https://github.com/Human-Connection/Nitro-Styleguide](https://github.com/Human-Connection/Nitro-Styleguide) - -If you need to change something in the styleguide and want to see the effects on the frontend immediately, then we have you covered. -You need to clone the styleguide to the parent directory `../Nitro-Styleguide` and run `yarn && yarn run dev`. After that you run `yarn run dev:styleguide` instead of `yarn run dev` and you will see your changes reflected inside the fronten! - -## Internationalization (i18n) - -You can help translating the interface by joining us on [lokalise.co](https://lokalise.co/public/556252725c18dd752dd546.13222042/). - -Thanks lokalise.co that we can use your premium account! - -localise.co - -## Attributions - -
Locale Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY
- -## License -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Web.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FHuman-Connection%2FNitro-Web?ref=badge_large) +If you need to change something in the styleguide and want to see the effects on the frontend immediately, then we have you covered. You need to clone the styleguide to the parent directory `../Nitro-Styleguide` and run `yarn && yarn run dev`. After that you run `yarn run dev:styleguide` instead of `yarn run dev` and you will see your changes reflected inside the fronten! diff --git a/webapp/assets/README.md b/webapp/assets.md similarity index 99% rename from webapp/assets/README.md rename to webapp/assets.md index 34766f934..06786539d 100644 --- a/webapp/assets/README.md +++ b/webapp/assets.md @@ -5,3 +5,4 @@ This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked). + diff --git a/webapp/components/README.md b/webapp/components.md similarity index 99% rename from webapp/components/README.md rename to webapp/components.md index a079f1060..be43ae454 100644 --- a/webapp/components/README.md +++ b/webapp/components.md @@ -5,3 +5,4 @@ The components directory contains your Vue.js Components. _Nuxt.js doesn't supercharge these components._ + diff --git a/webapp/components/Category/Readme.md b/webapp/components/Category/Readme.md new file mode 100644 index 000000000..50e07f966 --- /dev/null +++ b/webapp/components/Category/Readme.md @@ -0,0 +1,7 @@ +### Example + +Category "IT, Internet & Data Privacy" with icon "mouse-cursor" + +``` + +``` \ No newline at end of file diff --git a/webapp/components/Category/index.spec.js b/webapp/components/Category/index.spec.js new file mode 100644 index 000000000..149f96189 --- /dev/null +++ b/webapp/components/Category/index.spec.js @@ -0,0 +1,35 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils' +import Styleguide from '@human-connection/styleguide' +import Category from './index' + +const localVue = createLocalVue() +localVue.use(Styleguide) + +describe('Category', () => { + let icon + let name + + let Wrapper = () => { + return shallowMount(Category, { + localVue, + propsData: { + icon, + name + } + }) + } + + describe('given Strings for Icon and Name', () => { + beforeEach(() => { + icon = 'mouse-cursor' + name = 'Peter' + }) + + it('shows Name', () => { + expect(Wrapper().text()).toContain('Peter') + }) + it('shows Icon Svg', () => { + expect(Wrapper().contains('svg')) + }) + }) +}) diff --git a/webapp/components/Category/index.vue b/webapp/components/Category/index.vue new file mode 100644 index 000000000..af602d4d0 --- /dev/null +++ b/webapp/components/Category/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/webapp/components/Comment.vue b/webapp/components/Comment.vue index 71043e90d..13edc9c0d 100644 --- a/webapp/components/Comment.vue +++ b/webapp/components/Comment.vue @@ -4,16 +4,15 @@ style="padding-left: 40px; font-weight: bold;" color="soft" > - {{ this.$t('comment.content.unavailable-placeholder') }} + + {{ this.$t('comment.content.unavailable-placeholder') }}
- + @@ -32,13 +31,13 @@ style="padding-left: 40px;" v-html="comment.contentExcerpt" /> - +
diff --git a/webapp/components/ContributionForm.vue b/webapp/components/ContributionForm/index.vue similarity index 90% rename from webapp/components/ContributionForm.vue rename to webapp/components/ContributionForm/index.vue index 3ef041569..6dc74f104 100644 --- a/webapp/components/ContributionForm.vue +++ b/webapp/components/ContributionForm/index.vue @@ -16,6 +16,7 @@ /> @@ -48,7 +49,7 @@ diff --git a/webapp/components/Editor/Editor.vue b/webapp/components/Editor/index.vue similarity index 55% rename from webapp/components/Editor/Editor.vue rename to webapp/components/Editor/index.vue index b59ca376d..5b542b3ce 100644 --- a/webapp/components/Editor/Editor.vue +++ b/webapp/components/Editor/index.vue @@ -1,5 +1,29 @@ diff --git a/webapp/components/notifications/Notification/spec.js b/webapp/components/notifications/Notification/spec.js new file mode 100644 index 000000000..8c6c846a4 --- /dev/null +++ b/webapp/components/notifications/Notification/spec.js @@ -0,0 +1,64 @@ +import { config, mount, createLocalVue, RouterLinkStub } from '@vue/test-utils' +import Notification from '.' +import Styleguide from '@human-connection/styleguide' +import Filters from '~/plugins/vue-filters' + +const localVue = createLocalVue() + +localVue.use(Styleguide) +localVue.use(Filters) + +config.stubs['no-ssr'] = '' + +describe('Notification', () => { + let wrapper + let stubs + let mocks + let propsData + beforeEach(() => { + propsData = {} + mocks = { + $t: jest.fn() + } + stubs = { + NuxtLink: RouterLinkStub + } + }) + + const Wrapper = () => { + return mount(Notification, { + stubs, + mocks, + propsData, + localVue + }) + } + + describe('given a notification', () => { + beforeEach(() => { + propsData.notification = { + post: { + title: "It's a title" + } + } + }) + + it('renders title', () => { + expect(Wrapper().text()).toContain("It's a title") + }) + + it('has no class "read"', () => { + expect(Wrapper().classes()).not.toContain('read') + }) + + describe('that is read', () => { + beforeEach(() => { + propsData.notification.read = true + }) + + it('has class "read"', () => { + expect(Wrapper().classes()).toContain('read') + }) + }) + }) +}) diff --git a/webapp/components/notifications/NotificationList/index.vue b/webapp/components/notifications/NotificationList/index.vue new file mode 100644 index 000000000..b8235f853 --- /dev/null +++ b/webapp/components/notifications/NotificationList/index.vue @@ -0,0 +1,32 @@ + + + diff --git a/webapp/components/notifications/NotificationList/spec.js b/webapp/components/notifications/NotificationList/spec.js new file mode 100644 index 000000000..c433abd80 --- /dev/null +++ b/webapp/components/notifications/NotificationList/spec.js @@ -0,0 +1,130 @@ +import { + config, + shallowMount, + mount, + createLocalVue, + RouterLinkStub +} from '@vue/test-utils' +import NotificationList from '.' +import Notification from '../Notification' +import Vue from 'vue' +import Vuex from 'vuex' +import Filters from '~/plugins/vue-filters' + +import Styleguide from '@human-connection/styleguide' + +const localVue = createLocalVue() + +localVue.use(Vuex) +localVue.use(Styleguide) +localVue.use(Filters) +localVue.filter('truncate', string => string) + +config.stubs['no-ssr'] = '' +config.stubs['v-popover'] = '' + +describe('NotificationList.vue', () => { + let wrapper + let Wrapper + let mocks + let stubs + let store + let propsData + + beforeEach(() => { + store = new Vuex.Store({ + getters: { + 'auth/user': () => { + return {} + } + } + }) + mocks = { + $t: jest.fn() + } + stubs = { + NuxtLink: RouterLinkStub + } + propsData = { + notifications: [ + { + id: 'notification-41', + read: false, + post: { + id: 'post-1', + title: 'some post title', + contentExcerpt: 'this is a post content', + author: { + id: 'john-1', + slug: 'john-doe', + name: 'John Doe' + } + } + }, + { + id: 'notification-42', + read: false, + post: { + id: 'post-2', + title: 'another post title', + contentExcerpt: 'this is yet another post content', + author: { + id: 'john-1', + slug: 'john-doe', + name: 'John Doe' + } + } + } + ] + } + }) + + describe('shallowMount', () => { + const Wrapper = () => { + return shallowMount(NotificationList, { + propsData, + mocks, + store, + localVue + }) + } + + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders Notification.vue for each notification of the user', () => { + expect(wrapper.findAll(Notification)).toHaveLength(2) + }) + }) + + describe('mount', () => { + const Wrapper = () => { + return mount(NotificationList, { + propsData, + mocks, + stubs, + store, + localVue + }) + } + + beforeEach(() => { + wrapper = Wrapper() + }) + + describe('click on a notification', () => { + beforeEach(() => { + wrapper + .findAll('.notification-mention-post') + .at(1) + .trigger('click') + }) + + it("emits 'markAsRead' with the notificationId", () => { + expect(wrapper.emitted('markAsRead')).toBeTruthy() + expect(wrapper.emitted('markAsRead')[0]).toEqual(['notification-42']) + }) + }) + }) +}) diff --git a/webapp/components/notifications/NotificationMenu/index.vue b/webapp/components/notifications/NotificationMenu/index.vue new file mode 100644 index 000000000..819858e3b --- /dev/null +++ b/webapp/components/notifications/NotificationMenu/index.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/webapp/components/notifications/NotificationMenu/spec.js b/webapp/components/notifications/NotificationMenu/spec.js new file mode 100644 index 000000000..4c9dd9d43 --- /dev/null +++ b/webapp/components/notifications/NotificationMenu/spec.js @@ -0,0 +1,94 @@ +import { config, shallowMount, createLocalVue } from '@vue/test-utils' +import NotificationMenu from '.' + +import Styleguide from '@human-connection/styleguide' +import Filters from '~/plugins/vue-filters' + +const localVue = createLocalVue() + +localVue.use(Styleguide) +localVue.use(Filters) +localVue.filter('truncate', string => string) + +config.stubs['dropdown'] = '' + +describe('NotificationMenu.vue', () => { + let wrapper + let Wrapper + let mocks + let data + beforeEach(() => { + mocks = { + $t: jest.fn() + } + data = () => { + return { + notifications: [] + } + } + }) + + describe('shallowMount', () => { + const Wrapper = () => { + return shallowMount(NotificationMenu, { + data, + mocks, + localVue + }) + } + + it('counter displays 0', () => { + wrapper = Wrapper() + expect(wrapper.find('ds-button-stub').text()).toEqual('0') + }) + + it('no dropdown is rendered', () => { + wrapper = Wrapper() + expect(wrapper.contains('.dropdown')).toBe(false) + }) + + describe('given some notifications', () => { + beforeEach(() => { + data = () => { + return { + notifications: [ + { + id: 'notification-41', + read: false, + post: { + id: 'post-1', + title: 'some post title', + contentExcerpt: 'this is a post content', + author: { + id: 'john-1', + slug: 'john-doe', + name: 'John Doe' + } + } + }, + { + id: 'notification-42', + read: false, + post: { + id: 'post-2', + title: 'another post title', + contentExcerpt: 'this is yet another post content', + author: { + id: 'john-1', + slug: 'john-doe', + name: 'John Doe' + } + } + } + ] + } + } + }) + + it('displays the total number of notifications', () => { + wrapper = Wrapper() + expect(wrapper.find('ds-button-stub').text()).toEqual('2') + }) + }) + }) +}) diff --git a/webapp/docker-compose.yml b/webapp/docker-compose.yml index 4ce3de926..f20fdf9f9 100644 --- a/webapp/docker-compose.yml +++ b/webapp/docker-compose.yml @@ -8,7 +8,6 @@ services: target: production ports: - 3000:3000 - - 8080:8080 networks: - hc-network environment: diff --git a/webapp/graphql/CommentQuery.js b/webapp/graphql/CommentQuery.js new file mode 100644 index 000000000..299916823 --- /dev/null +++ b/webapp/graphql/CommentQuery.js @@ -0,0 +1,13 @@ +import gql from 'graphql-tag' + +export default app => { + return gql(` + query CommentByPost($postId: ID!) { + CommentByPost(postId: $postId) { + id + contentExcerpt + createdAt + } + } + `) +} diff --git a/webapp/graphql/UserProfileQuery.js b/webapp/graphql/UserProfileQuery.js index f0d7720ae..16e7e1440 100644 --- a/webapp/graphql/UserProfileQuery.js +++ b/webapp/graphql/UserProfileQuery.js @@ -98,6 +98,10 @@ export default app => { } } } + socialMedia { + id + url + } } } `) diff --git a/webapp/layouts/README.md b/webapp/layouts.md similarity index 99% rename from webapp/layouts/README.md rename to webapp/layouts.md index cad1ad573..300b5af89 100644 --- a/webapp/layouts/README.md +++ b/webapp/layouts.md @@ -5,3 +5,4 @@ This directory contains your Application Layouts. More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts). + diff --git a/webapp/layouts/blank.vue b/webapp/layouts/blank.vue index 140ec9f6e..570799a4d 100644 --- a/webapp/layouts/blank.vue +++ b/webapp/layouts/blank.vue @@ -10,7 +10,7 @@ diff --git a/webapp/plugins/README.md b/webapp/plugins.md similarity index 99% rename from webapp/plugins/README.md rename to webapp/plugins.md index 0d227f3ff..a54b05d0b 100644 --- a/webapp/plugins/README.md +++ b/webapp/plugins.md @@ -5,3 +5,4 @@ This directory contains your Javascript plugins that you want to run before mounting the root Vue.js application. More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins). + diff --git a/webapp/plugins/vue-filters.js b/webapp/plugins/vue-filters.js index 948de9c3f..bf59a7dba 100644 --- a/webapp/plugins/vue-filters.js +++ b/webapp/plugins/vue-filters.js @@ -6,7 +6,7 @@ import formatRelative from 'date-fns/formatRelative' import addSeconds from 'date-fns/addSeconds' import accounting from 'accounting' -export default ({ app }) => { +export default ({ app = {} }) => { const locales = { en: enUS, de: de, @@ -34,12 +34,6 @@ export default ({ app }) => { locale: getLocalizedFormat() }) }, - relativeDateTime: value => { - if (!value) return '' - return formatRelative(new Date(value), new Date(), { - locale: getLocalizedFormat() - }) - }, number: ( value, precision = 2, @@ -94,6 +88,17 @@ export default ({ app }) => { return index === 0 ? letter.toUpperCase() : letter.toLowerCase() }) .replace(/\s+/g, '') + }, + removeLinks: content => { + if (!content) return '' + // remove all links from excerpt to prevent issues with the surrounding link + let excerpt = content.replace(/(.+)<\/a>/gim, '$1') + // do not display content that is only linebreaks + if (excerpt.replace(/
/gim, '').trim() === '') { + excerpt = '' + } + + return excerpt } }) diff --git a/webapp/static/README.md b/webapp/static.md similarity index 74% rename from webapp/static/README.md rename to webapp/static.md index 3fc500234..748e8c5ed 100644 --- a/webapp/static/README.md +++ b/webapp/static.md @@ -2,9 +2,9 @@ **This directory is not required, you can delete it if you don't want to use it.** -This directory contains your static files. -Each file inside this directory is mapped to `/`. +This directory contains your static files. Each file inside this directory is mapped to `/`. Example: `/static/robots.txt` is mapped as `/robots.txt`. More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static). + diff --git a/webapp/store/README.md b/webapp/store.md similarity index 73% rename from webapp/store/README.md rename to webapp/store.md index 111fea1b3..1310aa2da 100644 --- a/webapp/store/README.md +++ b/webapp/store.md @@ -2,9 +2,9 @@ **This directory is not required, you can delete it if you don't want to use it.** -This directory contains your Vuex Store files. -Vuex Store option is implemented in the Nuxt.js framework. +This directory contains your Vuex Store files. Vuex Store option is implemented in the Nuxt.js framework. Creating a file in this directory activate the option in the framework automatically. More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). + diff --git a/webapp/store/auth.js b/webapp/store/auth.js index 4785ff0c0..ca1b453ba 100644 --- a/webapp/store/auth.js +++ b/webapp/store/auth.js @@ -74,17 +74,38 @@ export const actions = { data: { currentUser } } = await client.query({ query: gql(`{ - currentUser { + currentUser { + id + name + slug + email + avatar + role + about + locationName + socialMedia { id - name - slug - email - avatar - role - about - locationName + url } - }`) + notifications(read: false, orderBy: createdAt_desc) { + id + read + createdAt + post { + author { + id + slug + name + disabled + deleted + } + title + contentExcerpt + slug + } + } + } + }`) }) if (!currentUser) return dispatch('logout') commit('SET_USER', currentUser) diff --git a/webapp/store/notifications.js b/webapp/store/notifications.js new file mode 100644 index 000000000..cfb41e333 --- /dev/null +++ b/webapp/store/notifications.js @@ -0,0 +1,89 @@ +import gql from 'graphql-tag' + +export const state = () => { + return { + notifications: null, + pending: false + } +} + +export const mutations = { + SET_NOTIFICATIONS(state, notifications) { + state.notifications = notifications + }, + SET_PENDING(state, pending) { + state.pending = pending + }, + UPDATE_NOTIFICATIONS(state, notification) { + const notifications = state.notifications + const toBeUpdated = notifications.find(n => { + return n.id === notification.id + }) + toBeUpdated = { ...toBeUpdated, ...notification } + } +} +export const getters = { + notifications(state) { + return !!state.notifications + } +} + +export const actions = { + async init({ getters, commit }) { + if (getters.notifications) return + commit('SET_PENDING', true) + const client = this.app.apolloProvider.defaultClient + let notifications + try { + const { + data: { currentUser } + } = await client.query({ + query: gql(`{ + currentUser { + id + notifications(orderBy: createdAt_desc) { + id + read + createdAt + post { + author { + id + slug + name + disabled + deleted + } + title + contentExcerpt + slug + } + } + } + }`) + }) + notifications = currentUser.notifications + console.log(notifications) + commit('SET_NOTIFICATIONS', notifications) + } finally { + commit('SET_PENDING', false) + } + return notifications + }, + + async markAsRead({ commit, rootGetters }, notificationId) { + const client = this.app.apolloProvider.defaultClient + const mutation = gql(` + mutation($id: ID!, $read: Boolean!) { + UpdateNotification(id: $id, read: $read) { + id + read + } + } + `) + const variables = { id: notificationId, read: true } + const { + data: { UpdateNotification } + } = await client.mutate({ mutation, variables }) + commit('UPDATE_NOTIFICATIONS', UpdateNotification) + } +} diff --git a/webapp/styleguide.md b/webapp/styleguide.md new file mode 100644 index 000000000..1c3951494 --- /dev/null +++ b/webapp/styleguide.md @@ -0,0 +1,12 @@ +# Styleguide + +For this Projoject we decided to use [Jörg Bayreuther's](https://github.com/visualjerk) _\(visualjerk\)_ fantastic Design System called [CION](https://cion.visualjerk.de/). _\(see a_ [_demo_](https://styleguide.cion.visualjerk.de/)_\)_ + +![Styleguide in action under https://localhost:8080](../.gitbook/assets/screenshot-styleguide.png) + +## Checkout the Styleguide + +It's now an npm package. Want to help with it's development or maintenance? + +[Head over to the repo](https://github.com/Human-Connection/Nitro-Styleguide) + diff --git a/webapp/testing.md b/webapp/testing.md new file mode 100644 index 000000000..8da854316 --- /dev/null +++ b/webapp/testing.md @@ -0,0 +1,8 @@ +# Component Testing + +We are using `Jest` as our test runner, along with `vue-test-utils`. + +Head over and check out the documentation on [Jest](https://jestjs.io/docs/en/getting-started.html) + +Also, check out [vue-test-utils](https://vue-test-utils.vuejs.org/) + diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 6ce40972b..536b77b69 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -21,18 +21,18 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@^7.1.0", "@babel/core@^7.2.2", "@babel/core@~7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.3.tgz#198d6d3af4567be3989550d97e068de94503074f" - integrity sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA== +"@babel/core@^7.1.0", "@babel/core@^7.4.3", "@babel/core@~7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.4.tgz#84055750b05fcd50f9915a826b44fa347a825250" + integrity sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.4.0" - "@babel/helpers" "^7.4.3" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/generator" "^7.4.4" + "@babel/helpers" "^7.4.4" + "@babel/parser" "^7.4.4" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" convert-source-map "^1.1.0" debug "^4.1.0" json5 "^2.1.0" @@ -41,12 +41,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.0.0", "@babel/generator@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.0.tgz#c230e79589ae7a729fd4631b9ded4dc220418196" - integrity sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ== +"@babel/generator@^7.0.0", "@babel/generator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041" + integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ== dependencies: - "@babel/types" "^7.4.0" + "@babel/types" "^7.4.4" jsesc "^2.5.1" lodash "^4.17.11" source-map "^0.5.0" @@ -67,33 +67,34 @@ "@babel/helper-explode-assignable-expression" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-call-delegate@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.0.tgz#f308eabe0d44f451217853aedf4dea5f6fe3294f" - integrity sha512-SdqDfbVdNQCBp3WhK2mNdDvHd3BD6qbmIc43CAyjnsfCmgHMeqgDcM3BzY2lchi7HBJGJ2CVdynLWbezaE4mmQ== +"@babel/helper-call-delegate@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" + integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== dependencies: - "@babel/helper-hoist-variables" "^7.4.0" - "@babel/traverse" "^7.4.0" - "@babel/types" "^7.4.0" + "@babel/helper-hoist-variables" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" -"@babel/helper-create-class-features-plugin@^7.3.0": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.2.tgz#ba1685603eb1c9f2f51c9106d5180135c163fe73" - integrity sha512-tdW8+V8ceh2US4GsYdNVNoohq5uVwOf9k6krjwW4E1lINcHgttnWcNqgdoessn12dAy8QkbezlbQh2nXISNY+A== +"@babel/helper-create-class-features-plugin@^7.4.0": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.4.3.tgz#5bbd279c6c3ac6a60266b89bbfe7f8021080a1ef" + integrity sha512-UMl3TSpX11PuODYdWGrUeW6zFkdYhDn7wRLrOuNVM6f9L+S9CzmDXYyrp3MTHcwWjnzur1f/Op8A7iYZWya2Yg== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-member-expression-to-functions" "^7.0.0" "@babel/helper-optimise-call-expression" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.2.3" + "@babel/helper-replace-supers" "^7.4.0" + "@babel/helper-split-export-declaration" "^7.4.0" -"@babel/helper-define-map@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.0.tgz#cbfd8c1b2f12708e262c26f600cd16ed6a3bc6c9" - integrity sha512-wAhQ9HdnLIywERVcSvX40CEJwKdAa1ID4neI9NXQPDOHwwA+57DqwLiPEVy2AIyWzAk0CQ8qx4awO0VUURwLtA== +"@babel/helper-define-map@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a" + integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg== dependencies: "@babel/helper-function-name" "^7.1.0" - "@babel/types" "^7.4.0" + "@babel/types" "^7.4.4" lodash "^4.17.11" "@babel/helper-explode-assignable-expression@^7.1.0": @@ -120,12 +121,12 @@ dependencies: "@babel/types" "^7.0.0" -"@babel/helper-hoist-variables@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.0.tgz#25b621399ae229869329730a62015bbeb0a6fbd6" - integrity sha512-/NErCuoe/et17IlAQFKWM24qtyYYie7sFIrW/tIQXpck6vAu2hhtYYsKLBWQV+BQZMbcIYPU/QMYuTufrY4aQw== +"@babel/helper-hoist-variables@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" + integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== dependencies: - "@babel/types" "^7.4.0" + "@babel/types" "^7.4.4" "@babel/helper-member-expression-to-functions@^7.0.0": version "7.0.0" @@ -153,16 +154,16 @@ "@babel/types" "^7.2.2" lodash "^4.17.10" -"@babel/helper-module-transforms@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.3.tgz#b1e357a1c49e58a47211a6853abb8e2aaefeb064" - integrity sha512-H88T9IySZW25anu5uqyaC1DaQre7ofM+joZtAaO2F8NBdFfupH0SZ4gKjgSFVcvtx/aAirqA9L9Clio2heYbZA== +"@babel/helper-module-transforms@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8" + integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/template" "^7.2.2" - "@babel/types" "^7.2.2" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/template" "^7.4.4" + "@babel/types" "^7.4.4" lodash "^4.17.11" "@babel/helper-optimise-call-expression@^7.0.0": @@ -184,10 +185,10 @@ dependencies: lodash "^4.17.10" -"@babel/helper-regex@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.3.tgz#9d6e5428bfd638ab53b37ae4ec8caf0477495147" - integrity sha512-hnoq5u96pLCfgjXuj8ZLX3QQ+6nAulS+zSgi6HulUwFbEruRAKwbGLU5OvXkE14L8XW6XsQEKsIDfgthKLRAyA== +"@babel/helper-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" + integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q== dependencies: lodash "^4.17.11" @@ -202,7 +203,7 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.2.3": +"@babel/helper-replace-supers@^7.1.0": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz#19970020cf22677d62b3a689561dbd9644d8c5e5" integrity sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA== @@ -222,6 +223,16 @@ "@babel/traverse" "^7.4.0" "@babel/types" "^7.4.0" +"@babel/helper-replace-supers@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27" + integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" + "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" @@ -244,6 +255,13 @@ dependencies: "@babel/types" "^7.4.0" +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -254,14 +272,14 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" -"@babel/helpers@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.3.tgz#7b1d354363494b31cb9a2417ae86af32b7853a3b" - integrity sha512-BMh7X0oZqb36CfyhvtbSmcWc3GXocfxv3yNsAEuM0l+fAqSO22rQrUpijr3oE/10jCTrB6/0b9kzmG4VetCj8Q== +"@babel/helpers@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.4.tgz#868b0ef59c1dd4e78744562d5ce1b59c89f2f2a5" + integrity sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A== dependencies: - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" "@babel/highlight@^7.0.0": version "7.0.0" @@ -272,10 +290,10 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.0", "@babel/parser@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.3.tgz#eb3ac80f64aa101c907d4ce5406360fe75b7895b" - integrity sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6" + integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w== "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" @@ -286,20 +304,20 @@ "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-syntax-async-generators" "^7.2.0" -"@babel/plugin-proposal-class-properties@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz#272636bc0fa19a0bc46e601ec78136a173ea36cd" - integrity sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg== +"@babel/plugin-proposal-class-properties@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.0.tgz#d70db61a2f1fd79de927eea91f6411c964e084b8" + integrity sha512-t2ECPNOXsIeK1JxJNKmgbzQtoG27KIlVE61vTqX0DKR9E9sZlVVxWUtEW9D5FlZ8b8j7SBNCHY47GgPKCKlpPg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.3.0" + "@babel/helper-create-class-features-plugin" "^7.4.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-proposal-decorators@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.3.0.tgz#637ba075fa780b1f75d08186e8fb4357d03a72a7" - integrity sha512-3W/oCUmsO43FmZIqermmq6TKaRSYhmh/vybPfVFwQWdSb8xwki38uAIvknCRzuyHRuYfCYmJzL9or1v0AffPjg== +"@babel/plugin-proposal-decorators@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.0.tgz#8e1bfd83efa54a5f662033afcc2b8e701f4bb3a9" + integrity sha512-d08TLmXeK/XbgCo7ZeZ+JaeZDtDai/2ctapTRsWWkkmy7G/cqz8DQN/HlWG7RR4YmfXxmExsbU3SuCjlM7AtUg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.3.0" + "@babel/helper-create-class-features-plugin" "^7.4.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-decorators" "^7.2.0" @@ -311,10 +329,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.3.tgz#be27cd416eceeba84141305b93c282f5de23bbb4" - integrity sha512-xC//6DNSSHVjq8O2ge0dyYlhshsH4T7XdCVoxbi5HzLYWfsC5ooFlJjrXk8RcAT+hjHAK9UjBXdylzSoDK3t4g== +"@babel/plugin-proposal-object-rest-spread@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz#1ef173fcf24b3e2df92a678f027673b55e7e3005" + integrity sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" @@ -327,13 +345,13 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" -"@babel/plugin-proposal-unicode-property-regex@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.0.tgz#202d91ee977d760ef83f4f416b280d568be84623" - integrity sha512-h/KjEZ3nK9wv1P1FSNb9G079jXrNYR0Ko+7XkOx85+gM24iZbPn0rh4vCftk+5QKY7y1uByFataBTmX7irEF1w== +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78" + integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" + "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" "@babel/plugin-syntax-async-generators@^7.2.0": @@ -392,10 +410,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-async-to-generator@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.0.tgz#234fe3e458dce95865c0d152d256119b237834b0" - integrity sha512-EeaFdCeUULM+GPFEsf7pFcNSxM7hYjoj5fiYbyuiXobW4JhFnjAv9OWzNwHyHcKoPNpAfeRDuW6VyaXEDUBa7g== +"@babel/plugin-transform-async-to-generator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz#a3f1d01f2f21cadab20b33a82133116f14fb5894" + integrity sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -408,26 +426,26 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-block-scoping@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.0.tgz#164df3bb41e3deb954c4ca32ffa9fcaa56d30bcb" - integrity sha512-AWyt3k+fBXQqt2qb9r97tn3iBwFpiv9xdAiG+Gr2HpAZpuayvbL55yWrsV3MyHvXk/4vmSiedhDRl1YI2Iy5nQ== +"@babel/plugin-transform-block-scoping@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d" + integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.11" -"@babel/plugin-transform-classes@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.3.tgz#adc7a1137ab4287a555d429cc56ecde8f40c062c" - integrity sha512-PUaIKyFUDtG6jF5DUJOfkBdwAS/kFFV3XFk7Nn0a6vR7ZT8jYw5cGtIlat77wcnd0C6ViGqo/wyNf4ZHytF/nQ== +"@babel/plugin-transform-classes@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6" + integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-define-map" "^7.4.0" + "@babel/helper-define-map" "^7.4.4" "@babel/helper-function-name" "^7.1.0" "@babel/helper-optimise-call-expression" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.4.0" - "@babel/helper-split-export-declaration" "^7.4.0" + "@babel/helper-replace-supers" "^7.4.4" + "@babel/helper-split-export-declaration" "^7.4.4" globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.2.0": @@ -437,20 +455,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-destructuring@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.3.tgz#1a95f5ca2bf2f91ef0648d5de38a8d472da4350f" - integrity sha512-rVTLLZpydDFDyN4qnXdzwoVpk1oaXHIvPEOkOLyr88o7oHxVc/LyrnDx+amuBWGOwUb7D1s/uLsKBNTx08htZg== +"@babel/plugin-transform-destructuring@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz#9d964717829cc9e4b601fc82a26a71a4d8faf20f" + integrity sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-dotall-regex@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.3.tgz#fceff1c16d00c53d32d980448606f812cd6d02bf" - integrity sha512-9Arc2I0AGynzXRR/oPdSALv3k0rM38IMFyto7kOCwb5F9sLUt2Ykdo3V9yUPR+Bgr4kb6bVEyLkPEiBhzcTeoA== +"@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" + integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.3" + "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" "@babel/plugin-transform-duplicate-keys@^7.2.0": @@ -468,17 +486,17 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-for-of@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.3.tgz#c36ff40d893f2b8352202a2558824f70cd75e9fe" - integrity sha512-UselcZPwVWNSURnqcfpnxtMehrb8wjXYOimlYQPBnup/Zld426YzIhNEvuRsEWVHfESIECGrxoI6L5QqzuLH5Q== +"@babel/plugin-transform-for-of@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" + integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-function-name@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.3.tgz#130c27ec7fb4f0cba30e958989449e5ec8d22bbd" - integrity sha512-uT5J/3qI/8vACBR9I1GlAuU/JqBtWdfCrynuOkrWG6nCDieZd5przB1vfP59FRHBZQ9DC2IUfqr/xKqzOD5x0A== +"@babel/plugin-transform-function-name@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" + integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -505,21 +523,21 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-modules-commonjs@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.3.tgz#3917f260463ac08f8896aa5bd54403f6e1fed165" - integrity sha512-sMP4JqOTbMJMimqsSZwYWsMjppD+KRyDIUVW91pd7td0dZKAvPmhCaxhOzkzLParKwgQc7bdL9UNv+rpJB0HfA== +"@babel/plugin-transform-modules-commonjs@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz#0bef4713d30f1d78c2e59b3d6db40e60192cac1e" + integrity sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw== dependencies: - "@babel/helper-module-transforms" "^7.4.3" + "@babel/helper-module-transforms" "^7.4.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" -"@babel/plugin-transform-modules-systemjs@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.0.tgz#c2495e55528135797bc816f5d50f851698c586a1" - integrity sha512-gjPdHmqiNhVoBqus5qK60mWPp1CmYWp/tkh11mvb0rrys01HycEGD7NvvSoKXlWEfSM9TcL36CpsK8ElsADptQ== +"@babel/plugin-transform-modules-systemjs@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz#dc83c5665b07d6c2a7b224c00ac63659ea36a405" + integrity sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ== dependencies: - "@babel/helper-hoist-variables" "^7.4.0" + "@babel/helper-hoist-variables" "^7.4.4" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-modules-umd@^7.2.0": @@ -530,17 +548,17 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-named-capturing-groups-regex@^7.4.2": - version "7.4.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.2.tgz#800391136d6cbcc80728dbdba3c1c6e46f86c12e" - integrity sha512-NsAuliSwkL3WO2dzWTOL1oZJHm0TM8ZY8ZSxk2ANyKkt5SQlToGA4pzctmq1BEjoacurdwZ3xp2dCQWJkME0gQ== +"@babel/plugin-transform-named-capturing-groups-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.4.tgz#5611d96d987dfc4a3a81c4383bb173361037d68d" + integrity sha512-Ki+Y9nXBlKfhD+LXaRS7v95TtTGYRAf9Y1rTDiE75zf8YQz4GDaWRXosMfJBXxnk88mGFjWdCRIeqDbon7spYA== dependencies: regexp-tree "^0.1.0" -"@babel/plugin-transform-new-target@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.0.tgz#67658a1d944edb53c8d4fa3004473a0dd7838150" - integrity sha512-6ZKNgMQmQmrEX/ncuCwnnw1yVGoaOW5KpxNhoWI7pCQdA0uZ0HqHGqenCUIENAnxRjy2WwNQ30gfGdIgqJXXqw== +"@babel/plugin-transform-new-target@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" + integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -552,12 +570,12 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" -"@babel/plugin-transform-parameters@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.3.tgz#e5ff62929fdf4cf93e58badb5e2430303003800d" - integrity sha512-ULJYC2Vnw96/zdotCZkMGr2QVfKpIT/4/K+xWWY0MbOJyMZuk660BGkr3bEKWQrrciwz6xpmft39nA4BF7hJuA== +"@babel/plugin-transform-parameters@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" + integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== dependencies: - "@babel/helper-call-delegate" "^7.4.0" + "@babel/helper-call-delegate" "^7.4.4" "@babel/helper-get-function-arity" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -568,10 +586,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-regenerator@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.3.tgz#2a697af96887e2bbf5d303ab0221d139de5e739c" - integrity sha512-kEzotPuOpv6/iSlHroCDydPkKYw7tiJGKlmYp6iJn4a6C/+b2FdttlJsLKYxolYHgotTJ5G5UY5h0qey5ka3+A== +"@babel/plugin-transform-regenerator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.4.tgz#5b4da4df79391895fca9e28f99e87e22cfc02072" + integrity sha512-Zz3w+pX1SI0KMIiqshFZkwnVGUhDZzpX2vtPzfJBKQQq8WsP/Xy9DNdELWivxcKOCX/Pywge4SiEaPaLtoDT4g== dependencies: regenerator-transform "^0.13.4" @@ -582,10 +600,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-runtime@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz#566bc43f7d0aedc880eaddbd29168d0f248966ea" - integrity sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw== +"@babel/plugin-transform-runtime@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.3.tgz#4d6691690ecdc9f5cb8c3ab170a1576c1f556371" + integrity sha512-7Q61bU+uEI7bCUFReT1NKn7/X6sDQsZ7wL1sJ9IYMAO7cI+eg6x9re1cEw2fCRMbbTVyoeUKWSV1M6azEfKCfg== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -614,10 +632,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" -"@babel/plugin-transform-template-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz#d87ed01b8eaac7a92473f608c97c089de2ba1e5b" - integrity sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg== +"@babel/plugin-transform-template-literals@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" + integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -629,112 +647,104 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-unicode-regex@^7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.3.tgz#3868703fc0e8f443dda65654b298df576f7b863b" - integrity sha512-lnSNgkVjL8EMtnE8eSS7t2ku8qvKH3eqNf/IwIfnSPUqzgqYmRwzdsQWv4mNQAN9Nuo6Gz1Y0a4CSmdpu1Pp6g== +"@babel/plugin-transform-unicode-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" + integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.3" + "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" -"@babel/polyfill@^7.2.5": - version "7.2.5" - resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.2.5.tgz#6c54b964f71ad27edddc567d065e57e87ed7fa7d" - integrity sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug== - dependencies: - core-js "^2.5.7" - regenerator-runtime "^0.12.0" - -"@babel/preset-env@^7.3.1", "@babel/preset-env@~7.4.3": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.3.tgz#e71e16e123dc0fbf65a52cbcbcefd072fbd02880" - integrity sha512-FYbZdV12yHdJU5Z70cEg0f6lvtpZ8jFSDakTm7WXeJbLXh4R0ztGEu/SW7G1nJ2ZvKwDhz8YrbA84eYyprmGqw== +"@babel/preset-env@^7.4.3", "@babel/preset-env@~7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.4.tgz#b6f6825bfb27b3e1394ca3de4f926482722c1d6f" + integrity sha512-FU1H+ACWqZZqfw1x2G1tgtSSYSfxJLkpaUQL37CenULFARDo+h4xJoVHzRoHbK+85ViLciuI7ME4WTIhFRBBlw== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-async-generator-functions" "^7.2.0" "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.4.3" + "@babel/plugin-proposal-object-rest-spread" "^7.4.4" "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" "@babel/plugin-syntax-async-generators" "^7.2.0" "@babel/plugin-syntax-json-strings" "^7.2.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.4.0" + "@babel/plugin-transform-async-to-generator" "^7.4.4" "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.4.0" - "@babel/plugin-transform-classes" "^7.4.3" + "@babel/plugin-transform-block-scoping" "^7.4.4" + "@babel/plugin-transform-classes" "^7.4.4" "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.4.3" - "@babel/plugin-transform-dotall-regex" "^7.4.3" + "@babel/plugin-transform-destructuring" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" "@babel/plugin-transform-duplicate-keys" "^7.2.0" "@babel/plugin-transform-exponentiation-operator" "^7.2.0" - "@babel/plugin-transform-for-of" "^7.4.3" - "@babel/plugin-transform-function-name" "^7.4.3" + "@babel/plugin-transform-for-of" "^7.4.4" + "@babel/plugin-transform-function-name" "^7.4.4" "@babel/plugin-transform-literals" "^7.2.0" "@babel/plugin-transform-member-expression-literals" "^7.2.0" "@babel/plugin-transform-modules-amd" "^7.2.0" - "@babel/plugin-transform-modules-commonjs" "^7.4.3" - "@babel/plugin-transform-modules-systemjs" "^7.4.0" + "@babel/plugin-transform-modules-commonjs" "^7.4.4" + "@babel/plugin-transform-modules-systemjs" "^7.4.4" "@babel/plugin-transform-modules-umd" "^7.2.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.2" - "@babel/plugin-transform-new-target" "^7.4.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.4" + "@babel/plugin-transform-new-target" "^7.4.4" "@babel/plugin-transform-object-super" "^7.2.0" - "@babel/plugin-transform-parameters" "^7.4.3" + "@babel/plugin-transform-parameters" "^7.4.4" "@babel/plugin-transform-property-literals" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.4.3" + "@babel/plugin-transform-regenerator" "^7.4.4" "@babel/plugin-transform-reserved-words" "^7.2.0" "@babel/plugin-transform-shorthand-properties" "^7.2.0" "@babel/plugin-transform-spread" "^7.2.0" "@babel/plugin-transform-sticky-regex" "^7.2.0" - "@babel/plugin-transform-template-literals" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.4.4" "@babel/plugin-transform-typeof-symbol" "^7.2.0" - "@babel/plugin-transform-unicode-regex" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/plugin-transform-unicode-regex" "^7.4.4" + "@babel/types" "^7.4.4" browserslist "^4.5.2" core-js-compat "^3.0.0" invariant "^2.2.2" js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/runtime@^7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" - integrity sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA== - dependencies: - regenerator-runtime "^0.12.0" - -"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.2.2", "@babel/template@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b" - integrity sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.4.0" - "@babel/types" "^7.4.0" - -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.2.3", "@babel/traverse@^7.4.0", "@babel/traverse@^7.4.3": +"@babel/runtime@^7.4.3": version "7.4.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.3.tgz#1a01f078fc575d589ff30c0f71bf3c3d9ccbad84" - integrity sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ== + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc" + integrity sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA== + dependencies: + regenerator-runtime "^0.13.2" + +"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.2.2", "@babel/template@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.4.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.2.3", "@babel/traverse@^7.4.0", "@babel/traverse@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.4.tgz#0776f038f6d78361860b6823887d4f3937133fe8" + integrity sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.4.4" "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/types" "^7.4.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.11" -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.4.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" - integrity sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA== +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0" + integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ== dependencies: esutils "^2.0.2" lodash "^4.17.11" @@ -904,88 +914,93 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" -"@nuxt/babel-preset-app@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/babel-preset-app/-/babel-preset-app-2.4.5.tgz#707043fe4686b7375df0917cca9134b7681ae9bf" - integrity sha512-Pfpp9++AjTLSvr0EQY00SPacSxw6nvIgARVTiFG8xEkqzUzChx1xz424u4e8mKhu3qEgj9ldcF5iKC5A87RYkw== +"@nuxt/babel-preset-app@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/babel-preset-app/-/babel-preset-app-2.6.3.tgz#c096603c573491058f232063d8dbb0511e7cb38f" + integrity sha512-Rwb5CE+hPZ4JovKi7tpoq9zsGzPD2YUL3hQjGNliF6cERlF40mVu/aeVTwRcAGxc02yMcKM2zq3Q2WjRYLcwwA== dependencies: - "@babel/core" "^7.2.2" - "@babel/plugin-proposal-class-properties" "^7.3.0" - "@babel/plugin-proposal-decorators" "^7.3.0" + "@babel/core" "^7.4.3" + "@babel/plugin-proposal-class-properties" "^7.4.0" + "@babel/plugin-proposal-decorators" "^7.4.0" "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-transform-runtime" "^7.2.0" - "@babel/preset-env" "^7.3.1" - "@babel/runtime" "^7.3.1" - "@vue/babel-preset-jsx" "^1.0.0-beta.2" + "@babel/plugin-transform-runtime" "^7.4.3" + "@babel/preset-env" "^7.4.3" + "@babel/runtime" "^7.4.3" + "@vue/babel-preset-jsx" "^1.0.0-beta.3" + core-js "^2.6.5" -"@nuxt/builder@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/builder/-/builder-2.4.5.tgz#afe5b1b91b7fd315cd7a1fe2c461ba361fe3e020" - integrity sha512-WPgNmDK7UgInCNECl13u6tJ9woC8c1ToPXgEfqL0pTZWlztqOyGXMcXaQnI0n1QKsqQPWFUfNAtztAum7xZLpw== +"@nuxt/builder@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/builder/-/builder-2.6.3.tgz#9754977eee6d91028a2a627d18fae21cf37a2aff" + integrity sha512-891cZlCImxu1jj/TxltcGkRRVpaR42wdxCFeaQqCLcZ3K0SJOhWPqXBrt/iroUl2fjaxNskrVmoTtxEFRBIlTg== dependencies: - "@nuxt/devalue" "^1.2.0" - "@nuxt/utils" "2.4.5" - "@nuxt/vue-app" "2.4.5" - chokidar "^2.0.4" - consola "^2.3.2" + "@nuxt/devalue" "^1.2.3" + "@nuxt/utils" "2.6.3" + "@nuxt/vue-app" "2.6.3" + chokidar "^2.1.5" + consola "^2.6.0" fs-extra "^7.0.1" glob "^7.1.3" hash-sum "^1.0.2" + ignore "^5.1.0" lodash "^4.17.11" pify "^4.0.1" - semver "^5.6.0" + semver "^6.0.0" serialize-javascript "^1.6.1" - upath "^1.1.0" + upath "^1.1.2" -"@nuxt/cli@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-2.4.5.tgz#f923963b8238d4530ac390e4e32025f687a9347a" - integrity sha512-mBrh8sZySEx4v6IqAgdq9aPY6JKl0m3BREt90anV8w+63YMmNHRFizGdWyEgq/6YUrCvuCua2RvJCZphBdnhFQ== +"@nuxt/cli@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-2.6.3.tgz#0eb743b3b9cd419bd7bb1c099fc29e3c23ea47f1" + integrity sha512-8WGRG2BIMcQpqwNltRGw/JskCvnVcQNQhXgFoKDcwQYFjLqdvQ+TeF7H2eSaWjfsxknKQb5PPQW5LXe9+CjZZA== dependencies: - "@nuxt/config" "2.4.5" - boxen "^3.0.0" + "@nuxt/config" "2.6.3" + "@nuxt/utils" "2.6.3" + boxen "^3.1.0" chalk "^2.4.2" - consola "^2.3.2" - esm "^3.2.3" + consola "^2.6.0" + esm "3.2.20" execa "^1.0.0" exit "^0.1.2" + fs-extra "^7.0.1" minimist "^1.2.0" + opener "1.5.1" pretty-bytes "^5.1.0" std-env "^2.2.1" - wrap-ansi "^4.0.0" + wrap-ansi "^5.1.0" -"@nuxt/config@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/config/-/config-2.4.5.tgz#78a03fe347006d5f3b620cb9acd73f62c13db61e" - integrity sha512-Yn1FqOVG7Si+clikYg5ILAxDWfTlweKULzZDtAZriWjQPg0D2sJ9VWV+mdggPQfyn+n4mvPvD4BEIyzvKVaXdg== +"@nuxt/config@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/config/-/config-2.6.3.tgz#2753970a92c445ba0196af77a1716c8278a6e08f" + integrity sha512-uVwD6rjmMpcpP7ZG5qXdP66XOH1AETqVMBX+gAqiUd4HtS4DL63XhRcS5EZKwq6fdPM6LrMC0Bol9KZeHy2eow== dependencies: - "@nuxt/utils" "2.4.5" - consola "^2.3.2" + "@nuxt/utils" "2.6.3" + consola "^2.6.0" std-env "^2.2.1" -"@nuxt/core@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/core/-/core-2.4.5.tgz#92cc97c99fadd90d34ad29db94eab22b6a494680" - integrity sha512-2hjyLRLmLMkG+9e1bhLmeU+ow4Ph5lPrArW8BPBNohO4Oxjzb/A3UUO6UhMMA24/9+qsBQT6rwsQ0WA66UCpJA== +"@nuxt/core@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/core/-/core-2.6.3.tgz#17302c0f46cc27ecaa3fc4e0ee04e0817e0b796b" + integrity sha512-gnAXeSZD+gYM2w1WMWrdOhGb/KfqSPzFQoFGQ8+r5PzuH3+onrWhvJHF4xZ5LTkoJ7ckIJf0/P/3jMsccCVx7A== dependencies: - "@nuxt/config" "2.4.5" - "@nuxt/devalue" "^1.2.0" - "@nuxt/server" "2.4.5" - "@nuxt/utils" "2.4.5" - "@nuxt/vue-renderer" "2.4.5" - consola "^2.3.2" + "@nuxt/config" "2.6.3" + "@nuxt/devalue" "^1.2.3" + "@nuxt/server" "2.6.3" + "@nuxt/utils" "2.6.3" + "@nuxt/vue-renderer" "2.6.3" + consola "^2.6.0" debug "^4.1.1" - esm "^3.2.3" + esm "3.2.20" fs-extra "^7.0.1" hash-sum "^1.0.2" std-env "^2.2.1" -"@nuxt/devalue@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@nuxt/devalue/-/devalue-1.2.0.tgz#a76f12fbabf43fbfde6823942338674ba7ae3265" - integrity sha512-t4HOJiCc4uqjgDIFjLpVBom/071SroKiJW6fXMg1Tga1ahnSPHBvo7YIPjPzpVSzDJhwKHaio7t0J/trH4+43g== +"@nuxt/devalue@^1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@nuxt/devalue/-/devalue-1.2.3.tgz#0a814d7e10519ffcb1a2a9930add831f91783092" + integrity sha512-iA25xn409pguKhJwfNKQNCzWDZS44yhLcuVPpfy2CQ4xMqrJRpBxePTpkdCRxf7/m66M3rmCgkDZlvex4ygc6w== dependencies: - consola "^2.3.0" + consola "^2.5.6" "@nuxt/friendly-errors-webpack-plugin@^2.4.0": version "2.4.0" @@ -997,104 +1012,119 @@ error-stack-parser "^2.0.0" string-width "^2.0.0" -"@nuxt/generator@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/generator/-/generator-2.4.5.tgz#9471d0fe7584597fc7089f1247127ed355a31f15" - integrity sha512-DUi8BnoGiuBN1jVe3J8QZNR68IvD/xhE6fX3vgcBylaeKTL5kC7h+CBnQ2w30bFQpsdmjWcaitTzdklvrm44Tg== +"@nuxt/generator@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/generator/-/generator-2.6.3.tgz#99ca792e8edbc83a17fc82f105a51bd18973b8e7" + integrity sha512-thvGaVZPHW9PcdTf6aYjqvn/KKrwNp4DVDKiQlvP1BjBqiEN26F5WDKMw2y1N/UnH7tt5CvTpMd5+awXAizPYQ== dependencies: - "@nuxt/utils" "2.4.5" + "@nuxt/utils" "2.6.3" chalk "^2.4.2" - consola "^2.3.2" + consola "^2.6.0" fs-extra "^7.0.1" - html-minifier "^3.5.21" + html-minifier "^4.0.0" -"@nuxt/opencollective@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@nuxt/opencollective/-/opencollective-0.2.1.tgz#8290f1220072637e575c3935733719a78ad2d056" - integrity sha512-NP2VSUKRFGutbhWeKgIU0MnY4fmpH8UWxxwTJNPurCQ5BeWhOxp+Gp5ltO39P/Et/J2GYGb3+ALNqZJ+5cGBBw== +"@nuxt/loading-screen@^0.5.0": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@nuxt/loading-screen/-/loading-screen-0.5.1.tgz#8adbdaa01b5445b98931d3f304f25a0e4d410d68" + integrity sha512-2v1gr5hNUpqbe6IMtbzmQizeiO67gumjTz9hI0copeamrTW1Xr/qbFarrqFCXV+ytLGyRJwGZsr5o58UHH+hbw== + dependencies: + connect "^3.6.6" + fs-extra "^7.0.1" + serve-static "^1.13.2" + ws "^6.2.1" + +"@nuxt/opencollective@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@nuxt/opencollective/-/opencollective-0.2.2.tgz#17adc7d380457379cd14cbb64a435ea196cc4a6e" + integrity sha512-ie50SpS47L+0gLsW4yP23zI/PtjsDRglyozX2G09jeiUazC1AJlGPZo0JUs9iuCDUoIgsDEf66y7/bSfig0BpA== dependencies: chalk "^2.4.1" consola "^2.3.0" node-fetch "^2.3.0" -"@nuxt/server@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/server/-/server-2.4.5.tgz#c4b921a878423215bfbbb6d02855a3c26a82f946" - integrity sha512-bJAA53xS5JV80mGjVcZRffU2FA/qL6diLyMAykO9MdTB8OOo6onLssWXH0Rl/89uWfs+z4iVXUpZsv9nMdhL0w== +"@nuxt/server@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/server/-/server-2.6.3.tgz#34c51629d56a88a73bee9122fa0128dce0774878" + integrity sha512-pxpbrF52aui0jMWfPzWg8sSnFF/VUj34HPSqMEMVAqX2cwgiytrGWfN5Iom6YfWeBvxYaOrTd8WA0hM5Dr1aMw== dependencies: - "@nuxt/config" "2.4.5" - "@nuxt/utils" "2.4.5" + "@nuxt/config" "2.6.3" + "@nuxt/utils" "2.6.3" "@nuxtjs/youch" "^4.2.3" chalk "^2.4.2" - compression "^1.7.3" + compression "^1.7.4" connect "^3.6.6" - consola "^2.3.2" + consola "^2.6.0" etag "^1.8.1" fresh "^0.5.2" fs-extra "^7.0.1" ip "^1.1.5" launch-editor-middleware "^2.2.1" - on-headers "^1.0.1" + on-headers "^1.0.2" pify "^4.0.1" - semver "^5.6.0" - serve-placeholder "^1.1.1" + semver "^6.0.0" + serve-placeholder "^1.2.1" serve-static "^1.13.2" server-destroy "^1.0.1" ua-parser-js "^0.7.19" -"@nuxt/utils@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/utils/-/utils-2.4.5.tgz#2f1b5ed9ecdfc356e7901cc5337c31e94dbf1a40" - integrity sha512-/FLBP1KFwBKIaq7ht7YBrhdHG9l1uSg2B3egZdVoVLbK+Uj10uZ+XeaU+IIpC4S+hLc1FY3WTjdCb2GHp91oIw== +"@nuxt/utils@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/utils/-/utils-2.6.3.tgz#29214eebd62336f7e94062831038e2553da3a95c" + integrity sha512-gkfV98DCGCS22jWiy5vy/Ugh79odaJt603czoQB5VVizFpDKS+YK27EvAz6Ljz3lxPBjSvsKjGkAnTsQ9VmqXg== dependencies: - consola "^2.3.2" + consola "^2.6.0" + fs-extra "^7.0.1" + hash-sum "^1.0.2" + proper-lockfile "^4.1.1" serialize-javascript "^1.6.1" + signal-exit "^3.0.2" -"@nuxt/vue-app@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/vue-app/-/vue-app-2.4.5.tgz#c164f6ab269c54dc6f892aedff9ce769f80eb3c2" - integrity sha512-dtcT7KDrZEAc3imCc+JEeJ4Lqgbf5ZfjKLXjzUCj3tk16OG7wR4H4bKcDLcHv63S+DTHuCaYOtzcHn44p6jTCQ== +"@nuxt/vue-app@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/vue-app/-/vue-app-2.6.3.tgz#5d2bdec87e95193cebc0af0d3e73e063f174e5ea" + integrity sha512-Lx7OWzDsoKAv5PmWJKcM0g0z50Os4uL8N27Z+hJT5fTKKt7ZPoBp84ckszQ2pr6yOqpHo9zldbljBXLR2C13mA== dependencies: - vue "^2.5.22" - vue-meta "^1.5.8" + node-fetch "^2.3.0" + unfetch "^4.1.0" + vue "^2.6.10" + vue-meta "^1.6.0" vue-no-ssr "^1.1.1" - vue-router "^3.0.2" - vue-template-compiler "^2.5.22" + vue-router "^3.0.6" + vue-template-compiler "^2.6.10" vuex "^3.1.0" -"@nuxt/vue-renderer@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/vue-renderer/-/vue-renderer-2.4.5.tgz#11c6fab292a944de19b7108baed8f92a5cdc37ce" - integrity sha512-NsS0ZHV/HEWAbzOBXiwbhcdb1KJFj8ucma+gnbfw/rIh5hgufqAxs4btt3U0ma/i3Bm0nQo+doZAWtl/HJX6mQ== +"@nuxt/vue-renderer@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/vue-renderer/-/vue-renderer-2.6.3.tgz#a9f2cbad2541d08e55ec979c5909686efc8de520" + integrity sha512-3kB6ymfwQ1iQrapAAdxCgYQgNPQU+GmOFSmxnmDSk5ZjXsTDAT9egx6hDs0JvrutqxU3G2eomXDYNaEVxhwUWA== dependencies: - "@nuxt/devalue" "^1.2.0" - "@nuxt/utils" "2.4.5" - consola "^2.3.2" + "@nuxt/devalue" "^1.2.3" + "@nuxt/utils" "2.6.3" + consola "^2.6.0" fs-extra "^7.0.1" lru-cache "^5.1.1" - vue "^2.5.22" - vue-meta "^1.5.8" - vue-server-renderer "^2.5.22" + vue "^2.6.10" + vue-meta "^1.6.0" + vue-server-renderer "^2.6.10" -"@nuxt/webpack@2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@nuxt/webpack/-/webpack-2.4.5.tgz#c7981deb8a1e2fb499f918b80b966443f982e277" - integrity sha512-UXC9Yw4PMIBDqGR9eB11G6v7YpahgJq4llz4ybDnWMVxOJR+yAOw5jD+8AGSBDDo/apSJ/LgzJX2TIOtopx+LA== +"@nuxt/webpack@2.6.3": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@nuxt/webpack/-/webpack-2.6.3.tgz#c51d7c4cb60cb1b05b1bf843be19d33edf34f0a0" + integrity sha512-awABdA1YJUnoZ0J1TNfB5d0JMU029PqAeydHJ13CA/THqo244bGeCP81IGLBgHR6A0YBwmcdXAe+r18r2EkS2Q== dependencies: - "@babel/core" "^7.2.2" - "@babel/polyfill" "^7.2.5" - "@nuxt/babel-preset-app" "2.4.5" + "@babel/core" "^7.4.3" + "@nuxt/babel-preset-app" "2.6.3" "@nuxt/friendly-errors-webpack-plugin" "^2.4.0" - "@nuxt/utils" "2.4.5" + "@nuxt/utils" "2.6.3" babel-loader "^8.0.5" cache-loader "^2.0.1" - caniuse-lite "^1.0.30000932" + caniuse-lite "^1.0.30000959" chalk "^2.4.2" - consola "^2.3.2" - css-loader "^2.1.0" - cssnano "^4.1.8" + consola "^2.6.0" + css-loader "^2.1.1" + cssnano "^4.1.10" eventsource-polyfill "^0.9.6" - extract-css-chunks-webpack-plugin "^3.3.2" + extract-css-chunks-webpack-plugin "^4.3.1" file-loader "^3.0.1" fs-extra "^7.0.1" glob "^7.1.3" @@ -1106,23 +1136,23 @@ pify "^4.0.1" postcss "^7.0.14" postcss-import "^12.0.1" - postcss-import-resolver "^1.1.0" + postcss-import-resolver "^1.2.2" postcss-loader "^3.0.0" - postcss-preset-env "^6.5.0" + postcss-preset-env "^6.6.0" postcss-url "^8.0.0" std-env "^2.2.1" style-resources-loader "^1.2.1" - terser-webpack-plugin "^1.2.2" + terser-webpack-plugin "^1.2.3" thread-loader "^1.2.0" time-fix-plugin "^2.0.5" url-loader "^1.1.2" - vue-loader "^15.6.2" - webpack "^4.29.2" - webpack-bundle-analyzer "^3.0.3" - webpack-dev-middleware "^3.5.1" + vue-loader "^15.7.0" + webpack "^4.30.0" + webpack-bundle-analyzer "^3.3.2" + webpack-dev-middleware "^3.6.2" webpack-hot-middleware "^2.24.3" webpack-node-externals "^1.7.2" - webpackbar "^3.1.5" + webpackbar "^3.2.0" "@nuxtjs/apollo@4.0.0-rc4": version "4.0.0-rc4" @@ -1401,74 +1431,74 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d" integrity sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg== -"@vue/babel-helper-vue-jsx-merge-props@^1.0.0-beta.2": - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0-beta.2.tgz#f3e20d77b89ddb7a4b9b7a75372f05cd3ac22d92" - integrity sha512-Yj92Q1GcGjjctecBfnBmVqKSlMdyZaVq10hlZB4HSd1DJgu4cWgpEImJSzcJRUCZmas6UigwE7f4IjJuQs+JvQ== +"@vue/babel-helper-vue-jsx-merge-props@^1.0.0-beta.3": + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0-beta.3.tgz#e4c2e7125b3e0d2a9d493e457850b2abb0fd3cad" + integrity sha512-cbFQnd3dDPsfWuxbWW2phynX2zsckwC4GfAkcE1QH1lZL2ZAD2V97xY3BmvTowMkjeFObRKQt1P3KKA6AoB0hQ== -"@vue/babel-plugin-transform-vue-jsx@^1.0.0-beta.2": - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.0.0-beta.2.tgz#6f7903fe66a34a02163f418c426cf419e862d97e" - integrity sha512-fvAymRZAPHitomRE+jIipWRj0STXNSMqeOSdOFu9Ffjqg9WGOxSdCjORxexManfZ2y5QDv7gzI1xfgprsK3nlw== +"@vue/babel-plugin-transform-vue-jsx@^1.0.0-beta.3": + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.0.0-beta.3.tgz#a1a44e801d8ed615e49f145ef1b3eaca2c16e2e6" + integrity sha512-yn+j2B/2aEagaxXrMSK3qcAJnlidfXg9v+qmytqrjUXc4zfi8QVC/b4zCev1FDmTip06/cs/csENA4law6Xhpg== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/plugin-syntax-jsx" "^7.2.0" - "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0-beta.2" + "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0-beta.3" html-tags "^2.0.0" lodash.kebabcase "^4.1.1" svg-tags "^1.0.0" -"@vue/babel-preset-jsx@^1.0.0-beta.2": - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vue/babel-preset-jsx/-/babel-preset-jsx-1.0.0-beta.2.tgz#3e5dc2b73da58391c1c7327c2bd2ef154fe4e46e" - integrity sha512-nZoAKBR/h6iPMQ66ieQcIdlpPBmqhtUUcgjBS541jIVxSog1rwzrc00jlsuecLonzUMWPU0PabyitsG74vhN1w== +"@vue/babel-preset-jsx@^1.0.0-beta.3": + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@vue/babel-preset-jsx/-/babel-preset-jsx-1.0.0-beta.3.tgz#15c584bd62c0286a80f0196749ae38cde5cd703b" + integrity sha512-qMKGRorTI/0nE83nLEM7MyQiBZUqc62sZyjkBdVaaU7S61MHI8RKHPtbLMMZlWXb2NCJ0fQci8xJWUK5JE+TFA== dependencies: - "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0-beta.2" - "@vue/babel-plugin-transform-vue-jsx" "^1.0.0-beta.2" - "@vue/babel-sugar-functional-vue" "^1.0.0-beta.2" - "@vue/babel-sugar-inject-h" "^1.0.0-beta.2" - "@vue/babel-sugar-v-model" "^1.0.0-beta.2" - "@vue/babel-sugar-v-on" "^1.0.0-beta.2" + "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0-beta.3" + "@vue/babel-plugin-transform-vue-jsx" "^1.0.0-beta.3" + "@vue/babel-sugar-functional-vue" "^1.0.0-beta.3" + "@vue/babel-sugar-inject-h" "^1.0.0-beta.3" + "@vue/babel-sugar-v-model" "^1.0.0-beta.3" + "@vue/babel-sugar-v-on" "^1.0.0-beta.3" -"@vue/babel-sugar-functional-vue@^1.0.0-beta.2": - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.0.0-beta.2.tgz#8831f686e7614f282d5170b902483ef538deef38" - integrity sha512-5qvi4hmExgjtrESDk0vflL69dIxkDAukJcYH9o4663E8Nh12Jpbmr+Ja8WmgkAPtTVhk90UVcVUFCCZLHBmhkQ== +"@vue/babel-sugar-functional-vue@^1.0.0-beta.3": + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.0.0-beta.3.tgz#41a855786971dacbbe8044858eefe98de089bf12" + integrity sha512-CBIa0sQWn3vfBS2asfTgv0WwdyKvNTKtE/cCfulZ7MiewLBh0RlvvSmdK9BIMTiHErdeZNSGUGlU6JuSHLyYkQ== dependencies: "@babel/plugin-syntax-jsx" "^7.2.0" -"@vue/babel-sugar-inject-h@^1.0.0-beta.2": - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.0.0-beta.2.tgz#5f92f994bf4b4126fad8633f554e8a426b51b413" - integrity sha512-qGXZ6yE+1trk82xCVJ9j3shsgI+R2ePj3+o8b2Ee7JNaRqQvMfTwpgx5BRlk4q1+CTjvYexdqBS+q4Kg7sSxcg== +"@vue/babel-sugar-inject-h@^1.0.0-beta.3": + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.0.0-beta.3.tgz#be1d00b74a1a89fed35a9b1415a738c36f125966" + integrity sha512-HKMBMmFfdK9GBp3rX2bHIwILBdgc5F3ahmCB72keJxzaAQrgDAnD+ho70exUge+inAGlNF34WsQcGPElTf9QZg== dependencies: "@babel/plugin-syntax-jsx" "^7.2.0" -"@vue/babel-sugar-v-model@^1.0.0-beta.2": - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.0.0-beta.2.tgz#051d3ae3ef5e70d514e09058ec5790f6a42e8c28" - integrity sha512-63US3IMEtATJzzK2le/Na53Sk2bp3LHfwZ8eMFwbTaz6e2qeV9frBl3ZYaha64ghT4IDSbrDXUmm0J09EAzFfA== +"@vue/babel-sugar-v-model@^1.0.0-beta.3": + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.0.0-beta.3.tgz#ea935b0e08bf58c125a1349b819156059590993c" + integrity sha512-et39eTEh7zW4wfZoSl9Jf0/n2r9OTT8U02LtSbXsjgYcqaDQFusN0+n7tw4bnOqvnnSVjEp7bVsQCWwykC3Wgg== dependencies: "@babel/plugin-syntax-jsx" "^7.2.0" - "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0-beta.2" - "@vue/babel-plugin-transform-vue-jsx" "^1.0.0-beta.2" + "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0-beta.3" + "@vue/babel-plugin-transform-vue-jsx" "^1.0.0-beta.3" camelcase "^5.0.0" html-tags "^2.0.0" svg-tags "^1.0.0" -"@vue/babel-sugar-v-on@^1.0.0-beta.2": - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.0.0-beta.2.tgz#3e2d122e229b10017f091d178346b601d9245260" - integrity sha512-XH/m3k11EKdMY0MrTg4+hQv8BFM8juzHT95chYkgxDmvDdVJnSCuf9+mcysEJttWD4PVuUGN7EHoIWsIhC0dRw== +"@vue/babel-sugar-v-on@^1.0.0-beta.3": + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.0.0-beta.3.tgz#2f5fedb43883f603fe76010f253b85c7465855fe" + integrity sha512-F+GapxCiy50jf2Q2B4exw+KYBzlGdeKMAMW1Dbvb0Oa59SA0CH6tsUOIAsXb0A05jwwg/of0LaVeo+4aLefVxQ== dependencies: "@babel/plugin-syntax-jsx" "^7.2.0" - "@vue/babel-plugin-transform-vue-jsx" "^1.0.0-beta.2" + "@vue/babel-plugin-transform-vue-jsx" "^1.0.0-beta.3" camelcase "^5.0.0" -"@vue/cli-shared-utils@~3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-3.5.1.tgz#71d66f06fc619ba28df279bd7d37ba1ba29c9066" - integrity sha512-hCB7UbKeeC41w2Q8+Q7jmw3gHdq+ltRqp80S3uDRRGxwiOhxrSmdBHMzKUjh01L8bXOBRgvLey+BERi1Nj9n6Q== +"@vue/cli-shared-utils@~3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-3.7.0.tgz#957dd3c31a31208caf9f119cac6008fd4960d46e" + integrity sha512-+LPDAQ1CE3ci1ADOvNqJMPdqyxgJxOq5HUgGDSKCHwviXF6GtynfljZXiSzgWh5ueMFxJphCfeMsTZqFWwsHVg== dependencies: chalk "^2.4.1" execa "^1.0.0" @@ -1477,10 +1507,10 @@ lru-cache "^5.1.1" node-ipc "^9.1.1" opn "^5.3.0" - ora "^3.1.0" + ora "^3.4.0" request "^2.87.0" request-promise-native "^1.0.7" - semver "^5.5.0" + semver "^6.0.0" string.prototype.padstart "^3.0.0" "@vue/component-compiler-utils@^2.5.1": @@ -1719,12 +1749,12 @@ acorn-jsx@^5.0.0: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== -acorn-walk@^6.0.1: +acorn-walk@^6.0.1, acorn-walk@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" integrity sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw== -acorn@^5.5.3, acorn@^5.7.3: +acorn@^5.5.3: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== @@ -1783,11 +1813,18 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== -ansi-escapes@^3.0.0, ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: +ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-escapes@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.1.0.tgz#62a9e5fa78e99c5bb588b1796855f5d729231b53" + integrity sha512-2VY/iCUZTDLD/qxptS3Zn3c6k2MeIbYqjRXqM8T5oC7N2mMjh3xIU3oYru6cHGbldFa9h5i8N0fP65UaUqrMWA== + dependencies: + type-fest "^0.3.0" + ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" @@ -1808,6 +1845,11 @@ ansi-regex@^4.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -2217,13 +2259,13 @@ atob@^2.1.1: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@^9.4.2: - version "9.4.7" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.7.tgz#f997994f9a810eae47b38fa6d8a119772051c4ff" - integrity sha512-qS5wW6aXHkm53Y4z73tFGsUhmZu4aMPV9iHXYlF0c/wxjknXNHuj/1cIQb+6YH692DbJGGWcckAXX+VxKvahMA== +autoprefixer@^9.4.9: + version "9.5.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.5.1.tgz#243b1267b67e7e947f28919d786b50d3bb0fb357" + integrity sha512-KJSzkStUl3wP0D5sdMlP82Q52JLy5+atf2MHAre48+ckWkXgixmfHyWmA77wFDy6jTHU6mIgXv6hAQ2mf1PjJQ== dependencies: - browserslist "^4.4.1" - caniuse-lite "^1.0.30000932" + browserslist "^4.5.4" + caniuse-lite "^1.0.30000957" normalize-range "^0.1.2" num2fraction "^1.2.2" postcss "^7.0.14" @@ -2512,17 +2554,18 @@ boxen@^1.2.1: term-size "^1.2.0" widest-line "^2.0.0" -boxen@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-3.0.0.tgz#2e229f603c9c1da9d2966b7e9a5681eb692eca23" - integrity sha512-6BI51DCC62Ylgv78Kfn+MHkyPwSlhulks+b+wz7bK1vsTFgbSEy/E1DOxx1wjf/0YdkrfPUMh9NoaW419M7csQ== +boxen@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-3.1.0.tgz#0eced0ffde565c3d68cb7ba0bbae51d8c2eed95c" + integrity sha512-WiP53arM6cU2STTBYQ2we3viJkDqkthMYaTFnmXPZ/v3S4h43H5MHWpw5d85SgmHiYO/Y+2PoyXO8nTEURXNJA== dependencies: ansi-align "^3.0.0" - camelcase "^5.0.0" + camelcase "^5.3.1" chalk "^2.4.2" - cli-boxes "^2.0.0" + cli-boxes "^2.1.0" string-width "^3.0.0" term-size "^1.2.0" + type-fest "^0.3.0" widest-line "^2.0.0" brace-expansion@^1.1.7: @@ -2625,7 +2668,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.0.0, browserslist@^4.3.5, browserslist@^4.4.1, browserslist@^4.5.1, browserslist@^4.5.2: +browserslist@^4.0.0, browserslist@^4.4.2, browserslist@^4.5.1, browserslist@^4.5.2, browserslist@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.5.4.tgz#166c4ecef3b51737a42436ea8002aeea466ea2c7" integrity sha512-rAjx494LMjqKnMPhFkuLmLp8JWEX0o8ADTGeAbOqaF+XCvYLreZrG5uVjnPBlAQ8REZK4pzXGvp0bWgrFtKaag== @@ -2752,7 +2795,7 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== -camel-case@3.0.x: +camel-case@3.0.x, camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= @@ -2788,6 +2831,11 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== +camelcase@^5.2.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -2798,16 +2846,26 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000918, caniuse-lite@^1.0.30000932: +caniuse-lite@^1.0.0: version "1.0.30000938" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000938.tgz#b64bf1427438df40183fce910fe24e34feda7a3f" integrity sha512-ekW8NQ3/FvokviDxhdKLZZAx7PptXNwxKgXtnR5y+PR3hckwuP3yJ1Ir+4/c97dsHNqtAyfKUGdw8P4EYzBNgw== +caniuse-lite@^1.0.30000939, caniuse-lite@^1.0.30000957: + version "1.0.30000957" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000957.tgz#fb1026bf184d7d62c685205358c3b24b9e29f7b3" + integrity sha512-8wxNrjAzyiHcLXN/iunskqQnJquQQ6VX8JHfW5kLgAPRSiSuKZiNfmIkP5j7jgyXqAQBSoXyJxfnbCFS0ThSiQ== + caniuse-lite@^1.0.30000955: version "1.0.30000956" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000956.tgz#fe56d8727fab96e0304ffbde6c4e538c9ad2a741" integrity sha512-3o7L6XkQ01Oney+x2fS5UVbQXJ7QQkYxrSfaLmFlgQabcKfploI8bhS2nmQ8Unh5MpMONAMeDEdEXG9t9AK6uA== +caniuse-lite@^1.0.30000959: + version "1.0.30000959" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000959.tgz#215d3455866da874179c6170202f0cc64f961cfd" + integrity sha512-6BvqmS0VLmY4sJCz6AbIJRQfcns8McDxi424y+3kmtisJeA9/5qslP+K8sqremDau7UU4WSsqdRP032JrqZY8Q== + capture-exit@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" @@ -2867,7 +2925,7 @@ cheerio@^1.0.0-rc.2: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@^2.0.2, chokidar@^2.0.4, chokidar@^2.1.5: +chokidar@^2.0.2, chokidar@^2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== @@ -2926,7 +2984,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -clean-css@4.2.x: +clean-css@4.2.x, clean-css@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== @@ -2938,10 +2996,10 @@ cli-boxes@^1.0.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= -cli-boxes@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.0.0.tgz#de5eb5ce7462833133e85f5710fabb38377e9333" - integrity sha512-P46J1Wf3BVD0E5plybtf6g/NtHYAUlOIt7w3ou/Ova/p7dJPdukPV4yp+BF8dpmnnk45XlMzn+x9kfzyucKzrg== +cli-boxes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.1.0.tgz#e77b63d111cfd7be927bc417b794c798f81027a0" + integrity sha512-V9gkudTUk+iZGUYvI6qNwD9XbEc0mJiQEjYT5/+RLhN/3GgSTjIAsltAIA+idbCEAdAQw//uaXRHBp+CETPjuA== cli-cursor@^2.1.0: version "2.1.0" @@ -3095,6 +3153,11 @@ commander@^2.18.0, commander@^2.19.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -3110,23 +3173,23 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -compressible@~2.0.14: - version "2.0.15" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.15.tgz#857a9ab0a7e5a07d8d837ed43fe2defff64fe212" - integrity sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw== +compressible@~2.0.16: + version "2.0.16" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.16.tgz#a49bf9858f3821b64ce1be0296afc7380466a77f" + integrity sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA== dependencies: - mime-db ">= 1.36.0 < 2" + mime-db ">= 1.38.0 < 2" -compression@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" - integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== dependencies: accepts "~1.3.5" bytes "3.0.0" - compressible "~2.0.14" + compressible "~2.0.16" debug "2.6.9" - on-headers "~1.0.1" + on-headers "~1.0.2" safe-buffer "5.1.2" vary "~1.1.2" @@ -3175,11 +3238,16 @@ connect@^3.6.6: parseurl "~1.3.2" utils-merge "1.0.1" -consola@^2.0.0-1, consola@^2.3.0, consola@^2.3.2, consola@^2.4.0, consola@^2.5.6: +consola@^2.0.0-1, consola@^2.3.0, consola@^2.4.0, consola@^2.5.6: version "2.5.6" resolved "https://registry.yarnpkg.com/consola/-/consola-2.5.6.tgz#5ce14dbaf6f5b589c8a258ef80ed97b752fa57d5" integrity sha512-DN0j6ewiNWkT09G3ZoyyzN3pSYrjxWcx49+mHu+oDI5dvW5vzmyuzYsqGS79+yQserH9ymJQbGzeqUejfssr8w== +consola@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/consola/-/consola-2.6.0.tgz#ddf4e2a4361f67c120aa8bb41a0bd3cdbb58636e" + integrity sha512-jge0Ip1NVoOafxZq1zxG1sLYVBtKV45BF39VV6YKSWb45nyLOHY51YP0+cBQ2DyOTKhCjtF0XrRJkjTvX4wzgQ== + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -3289,7 +3357,7 @@ core-js@3.0.0-beta.13: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.0.0-beta.13.tgz#7732c69be5e4758887917235fe7c0352c4cb42a1" integrity sha512-16Q43c/3LT9NyePUJKL8nRIQgYWjcBhjJSMWg96PVSxoS0PeE0NHitPI3opBrs9MGGHjte1KoEVr9W63YKlTXQ== -core-js@^2.4.0, core-js@^2.5.7: +core-js@^2.4.0, core-js@^2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== @@ -3451,18 +3519,19 @@ css-has-pseudo@^0.10.0: postcss "^7.0.6" postcss-selector-parser "^5.0.0-rc.4" -css-loader@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.0.tgz#42952ac22bca5d076978638e9813abce49b8f0cc" - integrity sha512-MoOu+CStsGrSt5K2OeZ89q3Snf+IkxRfAIt9aAKg4piioTrhtP1iEFPu+OVn3Ohz24FO6L+rw9UJxBILiSBw5Q== +css-loader@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" + integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== dependencies: - icss-utils "^4.0.0" - loader-utils "^1.2.1" - lodash "^4.17.11" - postcss "^7.0.6" + camelcase "^5.2.0" + icss-utils "^4.1.0" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.14" postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^2.0.3" - postcss-modules-scope "^2.0.0" + postcss-modules-local-by-default "^2.0.6" + postcss-modules-scope "^2.1.0" postcss-modules-values "^2.0.0" postcss-value-parser "^3.3.0" schema-utils "^1.0.0" @@ -3499,15 +3568,6 @@ css-select@^2.0.0: domutils "^1.7.0" nth-check "^1.0.2" -css-selector-tokenizer@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d" - integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA== - dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" - css-tree@1.0.0-alpha.28: version "1.0.0-alpha.28" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.28.tgz#8e8968190d886c9477bc8d61e96f61af3f7ffa7f" @@ -3554,16 +3614,16 @@ cssdb@^4.3.0: resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.3.0.tgz#2e1229900616f80c66ff2d568ea2b4f92db1c78c" integrity sha512-VHPES/+c9s+I0ryNj+PXvp84nz+ms843z/efpaEINwP/QfGsINL3gpLp5qjapzDNzNzbXxur8uxKxSXImrg4ag== -cssesc@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" - integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q= - cssesc@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + cssnano-preset-default@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" @@ -3622,7 +3682,7 @@ cssnano-util-same-parent@^4.0.0: resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== -cssnano@^4.1.0, cssnano@^4.1.8: +cssnano@^4.1.0, cssnano@^4.1.10: version "4.1.10" resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== @@ -3745,6 +3805,11 @@ deepmerge@^3.0.0: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.1.0.tgz#a612626ce4803da410d77554bfd80361599c034d" integrity sha512-/TnecbwXEdycfbsM2++O3eGiatEFHjjNciHEwJclM+T5Kd94qD1AP+2elP/Mq0L5b9VZJao5znR01Mz6eX8Seg== +deepmerge@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.2.0.tgz#58ef463a57c08d376547f8869fdc5bcee957f44e" + integrity sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow== + default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -4164,10 +4229,10 @@ eslint-config-prettier@^3.3.0: dependencies: get-stdin "^6.0.0" -eslint-config-prettier@~4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.1.0.tgz#181364895899fff9fd3605fecb5c4f20e7d5f395" - integrity sha512-zILwX9/Ocz4SV2vX7ox85AsrAgXV3f2o2gpIicdMIOra48WYqgUnWNH/cR/iHtmD2Vb3dLSC3LiEJnS05Gkw7w== +eslint-config-prettier@~4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.2.0.tgz#70b946b629cd0e3e98233fd9ecde4cb9778de96c" + integrity sha512-y0uWc/FRfrHhpPZCYflWC8aE0KRJRY04rdZVfl8cL3sEZmOYyaBdhdlQPjKZBnuRMyLVK+JUZr7HaZFClQiH4w== dependencies: get-stdin "^6.0.0" @@ -4264,16 +4329,16 @@ eslint@~5.16.0: table "^5.2.3" text-table "^0.2.0" +esm@3.2.20: + version "3.2.20" + resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.20.tgz#44f125117863427cdece7223baa411fc739c1939" + integrity sha512-NA92qDA8C/qGX/xMinDGa3+cSPs4wQoFxskRrSnDo/9UloifhONFm4sl4G+JsyCqM007z2K+BfQlH5rMta4K1Q== + esm@^3.0.84: version "3.2.4" resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.4.tgz#0b728b5d6043061bf552197407bf2c630717812b" integrity sha512-wOuWtQCkkwD1WKQN/k3RsyGSSN+AmiUzdKftn8vaC+uV9JesYmQlODJxgXaaRz0LaaFIlUxZaUu5NPiUAjKAAA== -esm@^3.2.3: - version "3.2.16" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.16.tgz#e48f887c29a4a981a4da0baa2ae2bf20e30b5614" - integrity sha512-iACZMQvYFc66Y7QC+vD3oGA/fFsPA/IQwewRJ3K0gbMV52E59pdko02kF2TfVdtp5aHO62PHxL6fxtHJmhm3NQ== - espree@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/espree/-/espree-4.1.0.tgz#728d5451e0fd156c04384a7ad89ed51ff54eb25f" @@ -4499,14 +4564,14 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-css-chunks-webpack-plugin@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/extract-css-chunks-webpack-plugin/-/extract-css-chunks-webpack-plugin-3.3.2.tgz#c99ba78be7c670e1bbd1dcffe3e272ab5e88026d" - integrity sha512-7XNEW3AiFiWqOCxJyjNDMqk+PMwqSQhrAr/NobhlI1fxb0a4AqlgCn3+dxlcqTlD+MhRz0jI4u3bXmw3jyoBVQ== +extract-css-chunks-webpack-plugin@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/extract-css-chunks-webpack-plugin/-/extract-css-chunks-webpack-plugin-4.3.2.tgz#dab841c62c53b50ce331eb2442f9d6f2fdc19f28" + integrity sha512-dTL4rwoMIwItq8KRhhgdHPcgFf7DwFRRcQBLj5F3k/WL2pSkYN//rS/dNUuRhbNgTMOV0HT60WjCVd9UGDaSOQ== dependencies: loader-utils "^1.1.0" lodash "^4.17.11" - normalize-url "^4.1.0" + normalize-url "^2.0.1" schema-utils "^1.0.0" webpack-sources "^1.1.0" @@ -4552,11 +4617,6 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fastparse@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - fault@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.2.tgz#c3d0fec202f172a3a4d414042ad2bb5e2a3ffbaa" @@ -4583,6 +4643,13 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" +figures@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.0.0.tgz#756275c964646163cc6f9197c7a0295dbfd04de9" + integrity sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g== + dependencies: + escape-string-regexp "^1.0.5" + file-entry-cache@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" @@ -4847,6 +4914,11 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +fuse.js@^3.4.4: + version "3.4.4" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.4.tgz#f98f55fcb3b595cf6a3e629c5ffaf10982103e95" + integrity sha512-pyLQo/1oR5Ywf+a/tY8z4JygnIglmRxVUOiyFAbd11o9keUDpUJSMGRWJngcnkURj30kDHPmhoKY8ChJiz3EpQ== + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -5175,7 +5247,7 @@ hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -he@1.2.x, he@^1.1.0: +he@1.2.x, he@^1.1.0, he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== @@ -5241,7 +5313,7 @@ html-entities@^1.2.0: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= -html-minifier@^3.2.3, html-minifier@^3.5.21: +html-minifier@^3.2.3: version "3.5.21" resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== @@ -5254,6 +5326,19 @@ html-minifier@^3.2.3, html-minifier@^3.5.21: relateurl "0.2.x" uglify-js "3.4.x" +html-minifier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56" + integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig== + dependencies: + camel-case "^3.0.0" + clean-css "^4.2.1" + commander "^2.19.0" + he "^1.2.0" + param-case "^2.1.1" + relateurl "^0.2.7" + uglify-js "^3.5.1" + html-tags@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" @@ -5367,12 +5452,12 @@ icss-replace-symbols@^1.1.0: resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= -icss-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.0.0.tgz#d52cf4bcdcfa1c45c2dbefb4ffdf6b00ef608098" - integrity sha512-bA/xGiwWM17qjllIs9X/y0EjsB7e0AV08F3OL8UPsoNkNRibIuu8f1eKTnQ8QO1DteKKTxTUAn+IEWUToIwGOA== +icss-utils@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.0.tgz#339dbbffb9f8729a243b701e1c29d4cc58c52f0e" + integrity sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ== dependencies: - postcss "^7.0.5" + postcss "^7.0.14" ieee754@^1.1.4: version "1.1.12" @@ -5401,6 +5486,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.0.tgz#a949efb645e5d67fd78e46f470bee6b8c5d862f9" + integrity sha512-dJEmMwloo0gq40chdtDmE4tMp67ZGwN7MFTgjNqWi2VHEi5Ya6JkuvPWasjcAIm7lg+2if8xxn5R199wspcplg== + immutable-tuple@^0.4.9: version "0.4.10" resolved "https://registry.yarnpkg.com/immutable-tuple/-/immutable-tuple-0.4.10.tgz#e0b1625384f514084a7a84b749a3bb26e9179929" @@ -6648,7 +6738,7 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.0.4, loader-utils@^1.1.0, loader-utils@^1.2.1, loader-utils@^1.2.3: +loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.0.4, loader-utils@^1.1.0, loader-utils@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== @@ -6720,11 +6810,6 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.merge@^4.6.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" - integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ== - lodash.mergewith@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" @@ -6986,7 +7071,12 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.36.0 < 2", mime-db@~1.38.0: +"mime-db@>= 1.38.0 < 2": + version "1.39.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.39.0.tgz#f95a20275742f7d2ad0429acfe40f4233543780e" + integrity sha512-DTsrw/iWVvwHH+9Otxccdyy0Tgiil6TWK/xhfARJZF/QFhwOgZgOIvA2/VIGpM8U7Q8z5nDmdDWC6tuVMJNibw== + +mime-db@~1.38.0: version "1.38.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== @@ -7410,16 +7500,20 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= +normalize-url@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + normalize-url@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -normalize-url@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.1.0.tgz#307e74c87473efa81969ad1b4bb91f1990178904" - integrity sha512-X781mkWeK6PDMAZJfGn/wnwil4dV6pIdF9euiNqtA89uJvZuNDJO2YyJxiwpPhTQcF5pYUU1v+kcOxzYV6rZlA== - npm-bundled@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" @@ -7472,17 +7566,18 @@ nuxt-env@~0.1.0: resolved "https://registry.yarnpkg.com/nuxt-env/-/nuxt-env-0.1.0.tgz#8ac50b9ff45391ad3044ea932cbd05f06a585f87" integrity sha512-7mTao3qG0zfN0hahk3O6SuDy0KEwYmNojammWQsMwhqMn3aUjX4nMYnWDa0pua+2/rwAY9oG53jQtLgJdG7f9w== -nuxt@~2.4.5: - version "2.4.5" - resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-2.4.5.tgz#3f3256c47e78038ef8081e522181aa2578bddcea" - integrity sha512-y2p0q58C8yyNr8zg9wEx5ZNhAYe0sbMXHeproGiCKXc2GW7TR6KtZ9/9IBeVlz7HwvoZW+VXIt2m/oecI9IbqQ== +nuxt@~2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-2.6.3.tgz#4d9c26bade778f93c559cec354491a05b13a18ec" + integrity sha512-+Dw3ygYaVGp4XLOefCQd7JuNv4hxE1smw2ddo8E3uMuGAoeMGGEEHr8IDCu+0u6rtZC++mfEOnkzovHvGg8G2g== dependencies: - "@nuxt/builder" "2.4.5" - "@nuxt/cli" "2.4.5" - "@nuxt/core" "2.4.5" - "@nuxt/generator" "2.4.5" - "@nuxt/opencollective" "^0.2.1" - "@nuxt/webpack" "2.4.5" + "@nuxt/builder" "2.6.3" + "@nuxt/cli" "2.6.3" + "@nuxt/core" "2.6.3" + "@nuxt/generator" "2.6.3" + "@nuxt/loading-screen" "^0.5.0" + "@nuxt/opencollective" "^0.2.2" + "@nuxt/webpack" "2.6.3" nwsapi@^2.0.7: version "2.1.0" @@ -7562,10 +7657,10 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" -on-headers@^1.0.1, on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" - integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= +on-headers@^1.0.2, on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -7581,7 +7676,7 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -opener@^1.5.1: +opener@1.5.1, opener@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== @@ -7628,16 +7723,16 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -ora@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-3.2.0.tgz#67e98a7e11f7f0ac95deaaaf11bb04de3d09e481" - integrity sha512-XHMZA5WieCbtg+tu0uPF8CjvwQdNzKCX6BVh3N6GFsEXH40mTk5dsw/ya1lBTUGJslcEFJFQ8cBhOgkkZXQtMA== +ora@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" + integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== dependencies: chalk "^2.4.2" cli-cursor "^2.1.0" cli-spinners "^2.0.0" log-symbols "^2.2.0" - strip-ansi "^5.0.0" + strip-ansi "^5.2.0" wcwidth "^1.0.1" orderedmap@^1.0.0: @@ -7754,7 +7849,7 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" -param-case@2.1.x: +param-case@2.1.x, param-case@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= @@ -7949,17 +8044,17 @@ pn@^1.1.0: resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== -popper.js@^1.12.9: - version "1.14.7" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e" - integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ== +popper.js@^1.14.7, popper.js@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2" + integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA== posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -postcss-attribute-case-insensitive@^4.0.0: +postcss-attribute-case-insensitive@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.1.tgz#b2a721a0d279c2f9103a36331c88981526428cc7" integrity sha512-L2YKB3vF4PetdTIthQVeT+7YiSzMoNMLLYxPXXppOOP7NoazEAy45sh2LvJ8leCQjfBcfkYQs8TtCcQjeZTp8A== @@ -8149,10 +8244,10 @@ postcss-image-set-function@^3.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-import-resolver@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-import-resolver/-/postcss-import-resolver-1.1.0.tgz#08a1a9811da625d28317abc31565a8408ff28cd2" - integrity sha512-GPIrMNh1ySSdA+BhTyWEv247KIW7WmPRWzvVMgGYR5YBWXAkj+iCdETmdyVQxakQRSLVTwfUibrOejxegka/OQ== +postcss-import-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-import-resolver/-/postcss-import-resolver-1.2.2.tgz#4d21536a3dd6103d71cca8122a6714b51491e6f5" + integrity sha512-8YVRutQbYvQvuQxZHQaRm3/vi/UvYIGH4HxPvgW0zs4MSWC6rjM77qC6sYP/h8Pzj1j7H8GUOSFHRBZ+umI2ig== dependencies: enhanced-resolve "^3.4.1" @@ -8284,22 +8379,22 @@ postcss-modules-extract-imports@^2.0.0: dependencies: postcss "^7.0.5" -postcss-modules-local-by-default@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.5.tgz#7f387f68f5555598068e4d6d1ea0b7d6fa984272" - integrity sha512-iFgxlCAVLno5wIJq+4hyuOmc4VjZEZxzpdeuZcBytLNWEK5Bx2oRF9PPcAz5TALbaFvrZm8sJYtJ3hV+tMSEIg== +postcss-modules-local-by-default@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" + integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== dependencies: - css-selector-tokenizer "^0.7.0" postcss "^7.0.6" + postcss-selector-parser "^6.0.0" postcss-value-parser "^3.3.1" -postcss-modules-scope@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.0.1.tgz#2c0f2394cde4cd09147db054c68917e38f6d43a4" - integrity sha512-7+6k9c3/AuZ5c596LJx9n923A/j3nF3ormewYBF1RrIQvjvjXe1xE8V8A1KFyFwXbvnshT6FBZFX0k/F1igneg== +postcss-modules-scope@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" + integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== dependencies: - css-selector-tokenizer "^0.7.0" postcss "^7.0.6" + postcss-selector-parser "^6.0.0" postcss-modules-values@^2.0.0: version "2.0.0" @@ -8428,20 +8523,20 @@ postcss-place@^4.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-preset-env@^6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.5.0.tgz#a14b8f6e748b2a3a4a02a56f36c390f30073b9e1" - integrity sha512-RdsIrYJd9p9AouQoJ8dFP5ksBJEIegA4q4WzJDih8nevz3cZyIP/q1Eaw3pTVpUAu3n7Y32YmvAW3X07mSRGkw== +postcss-preset-env@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.6.0.tgz#642e7d962e2bdc2e355db117c1eb63952690ed5b" + integrity sha512-I3zAiycfqXpPIFD6HXhLfWXIewAWO8emOKz+QSsxaUZb9Dp8HbF5kUf+4Wy/AxR33o+LRoO8blEWCHth0ZsCLA== dependencies: - autoprefixer "^9.4.2" - browserslist "^4.3.5" - caniuse-lite "^1.0.30000918" + autoprefixer "^9.4.9" + browserslist "^4.4.2" + caniuse-lite "^1.0.30000939" css-blank-pseudo "^0.1.4" css-has-pseudo "^0.10.0" css-prefers-color-scheme "^3.1.1" cssdb "^4.3.0" - postcss "^7.0.6" - postcss-attribute-case-insensitive "^4.0.0" + postcss "^7.0.14" + postcss-attribute-case-insensitive "^4.0.1" postcss-color-functional-notation "^2.0.1" postcss-color-gray "^5.0.0" postcss-color-hex-alpha "^5.0.2" @@ -8540,6 +8635,15 @@ postcss-selector-parser@^5.0.0, postcss-selector-parser@^5.0.0-rc.3, postcss-sel indexes-of "^1.0.1" uniq "^1.0.1" +postcss-selector-parser@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + postcss-svgo@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" @@ -8603,6 +8707,11 @@ prepend-http@^1.0.1: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" @@ -8686,6 +8795,15 @@ prompts@^2.0.1: kleur "^3.0.2" sisteransi "^1.0.0" +proper-lockfile@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.1.tgz#284cf9db9e30a90e647afad69deb7cb06881262c" + integrity sha512-1w6rxXodisVpn7QYvLk706mzprPTAPCYAqxMvctmPN3ekuRk/kuGkGc82pangZiAt4R3lwSuUzheTTn0/Yb7Zg== + dependencies: + graceful-fs "^4.1.11" + retry "^0.12.0" + signal-exit "^3.0.2" + prosemirror-commands@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.0.7.tgz#e5a2ba821e29ea7065c88277fe2c3d7f6b0b9d37" @@ -8746,10 +8864,10 @@ prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.7.0: dependencies: orderedmap "^1.0.0" -prosemirror-schema-list@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.0.2.tgz#8381fb0c1eaf439d848059f62e2fac517033c2ef" - integrity sha512-IJ4DEpUEymfO+NNA4DAgCMF39XiQqpmCoPYY3SXa1jYcVgObGpGfJlSjZYVFEpimoLI7/mLoOLDhCtpGCRhTfg== +prosemirror-schema-list@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz#539caafa4f9314000943bd783be4017165ec0bd6" + integrity sha512-+zzSawVds8LsZpl/bLTCYk2lYactF93W219Czh81zBILikCRDOHjp1CQ1os4ZXBp6LlD+JnBqF1h59Q+hilOoQ== dependencies: prosemirror-model "^1.0.0" prosemirror-transform "^1.0.0" @@ -8762,10 +8880,10 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.1, prosemirror-state@^1.2.2: prosemirror-model "^1.0.0" prosemirror-transform "^1.0.0" -prosemirror-tables@^0.7.10, prosemirror-tables@^0.7.9: - version "0.7.10" - resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-0.7.10.tgz#4b0f623422b4b8f84cdc9c559f8a87579846b3ba" - integrity sha512-VIu7UGS9keYEHs0Y6AEOTGbNE9QI2rL1OKng4vV6yoTshW/lYcb+s3hGXI12i+WLMjDVm7ujhfdWrpKpvFZOkQ== +prosemirror-tables@^0.7.11: + version "0.7.11" + resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-0.7.11.tgz#400317df5898473f8c33eef8f8016451d0d1ceed" + integrity sha512-IOvz4sE4RgEeI8aKbis6ADqXEZlqnU1aZ/hdZLj6F74HeCGv5cC/hnOkhlip+4IaQvqn1u3oyBWKMzjGlUJuww== dependencies: prosemirror-keymap "^1.0.0" prosemirror-model "^1.0.0" @@ -8785,10 +8903,10 @@ prosemirror-utils@^0.7.6: resolved "https://registry.yarnpkg.com/prosemirror-utils/-/prosemirror-utils-0.7.6.tgz#c462ddfbf2452e56e4b25d1f02b34caccddb0f33" integrity sha512-vzsCBTiJ56R3nRDpIJnKOJzsZP7KFO8BkXk7zvQgQiXpml2o/djPCRhuyaFc7VTqSHlLPQHVI1feTLAwHp+prQ== -prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.8.3: - version "1.8.3" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.8.3.tgz#f8deff22c7d371f63db2686ac6f3661ded1b3ae3" - integrity sha512-CAW3SycaJgfPlWwYcDGiwNaCwcikBLSFAgLF+H+bTn0aCAUzcl2DXQdU9dMvK3HeWG+6Xn/QPQbhyyqCcV3ZBw== +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.8.9: + version "1.8.9" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.8.9.tgz#9303def925eba0a8ce4589e64b4a011eaccfc1e0" + integrity sha512-K3/z7qDR6rEMH/gKXqu5pmjmtyhtuTWeQyselK6HMp3jbn1UANU4CfdU/awQT+zbRjv4ZJXGb9lxnuNmdUQS3Q== dependencies: prosemirror-model "^1.1.0" prosemirror-state "^1.0.0" @@ -8908,6 +9026,15 @@ qs@6.5.2, qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -9067,7 +9194,7 @@ regenerate-unicode-properties@^8.0.2: dependencies: regenerate "^1.4.0" -regenerate@^1.2.1, regenerate@^1.4.0: +regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== @@ -9077,10 +9204,10 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.12.0: - version "0.12.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" - integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== +regenerator-runtime@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" + integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== regenerator-transform@^0.13.4: version "0.13.4" @@ -9111,15 +9238,6 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -regexpu-core@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" - integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs= - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - regexpu-core@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae" @@ -9147,23 +9265,11 @@ registry-url@^3.0.3: dependencies: rc "^1.0.1" -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= - regjsgen@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= - dependencies: - jsesc "~0.5.0" - regjsparser@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" @@ -9171,7 +9277,7 @@ regjsparser@^0.6.0: dependencies: jsesc "~0.5.0" -relateurl@0.2.x: +relateurl@0.2.x, relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= @@ -9318,7 +9424,7 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry@0.12.0: +retry@0.12.0, retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= @@ -9477,6 +9583,11 @@ semver-diff@^2.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65" + integrity sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ== + semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -9506,10 +9617,10 @@ serialize-javascript@^1.3.0, serialize-javascript@^1.4.0, serialize-javascript@^ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879" integrity sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw== -serve-placeholder@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/serve-placeholder/-/serve-placeholder-1.2.0.tgz#83e1d78cb11f477636d0a09a87b1f3bfeda2a19d" - integrity sha512-Na9YWY0yUzODF7jPW1ldReZG+cG2ChMTSgQfczx3lbtz1AXlYqP+BtbXaNLRi4xlNwTPcFmJmeK9WyH/ZCTzOg== +serve-placeholder@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/serve-placeholder/-/serve-placeholder-1.2.1.tgz#3659fca99b0f15fb3bdf0a72917a6d1848786e9c" + integrity sha512-qyVsP+xA/Sh4cWB/QJzz0tTD52AWIXqxAs/ceEu4HwDnAWXWIYuhwesr1/KPD1GWdE9y7xN8eUI9nW8hfpUniA== dependencies: defu "^0.0.1" @@ -9801,7 +9912,7 @@ stack-trace@0.0.10: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= -stack-utils@^1.0.1: +stack-utils@^1.0.1, stack-utils@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== @@ -9890,6 +10001,11 @@ streamsearch@0.1.2: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + string-hash@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" @@ -9978,6 +10094,13 @@ strip-ansi@^5.0.0: dependencies: ansi-regex "^4.0.0" +strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -10162,7 +10285,7 @@ terser-webpack-plugin@^1.1.0: webpack-sources "^1.1.0" worker-farm "^1.5.2" -terser-webpack-plugin@^1.2.2: +terser-webpack-plugin@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz#3f98bc902fac3e5d0de730869f50668561262ec8" integrity sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA== @@ -10254,45 +10377,52 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -tiptap-commands@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.7.0.tgz#d15cec2cb09264b5c1f6f712dab8819bb9ab7e13" - integrity sha512-JhgvBPIhGnisEdxD6gmM3U76BUlKF9n1LW1X/dO1AUOsm3Xc9tQB5BIOV/DpZTvrjntLP3AUTfd+yJeRIz5CPA== +tippy.js@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-4.3.0.tgz#5f661fed7fa30c90609eb87f6657005dd041ede3" + integrity sha512-SjctzIfkx3+waue+Ew58MMTuzYD4SK9wJOnCEdrCmwZiKJ7chZSxOguFmBm11tmTlZuGbxncUC/5Qu6GqzD2qQ== + dependencies: + popper.js "^1.14.7" + +tiptap-commands@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.8.0.tgz#416942b60005fc23fc44ce7fdf4d2fe428b0d4c7" + integrity sha512-1/pOhQvCGDsoCFkOrAtoC7PBoXVEpRr8bYitPwZSNvxtqBdn+FaIfGJTHxYlxcY6skcHtlbeh9msb/W9lrz8eg== dependencies: prosemirror-commands "^1.0.7" prosemirror-inputrules "^1.0.1" - prosemirror-schema-list "^1.0.2" + prosemirror-schema-list "^1.0.3" prosemirror-state "^1.2.2" - tiptap-utils "^1.3.0" + tiptap-utils "^1.4.0" -tiptap-extensions@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/tiptap-extensions/-/tiptap-extensions-1.14.0.tgz#5517afd1ca556715a8cce6c022c88584a762004a" - integrity sha512-WzYukrUHGGjCi3+F156LEVn5R58Pw1F6zKHT2o4SMHuv0LrWTIJK1XsDv8uwi/szfTlXm9BJ4MKmRbDulBeioQ== +tiptap-extensions@^1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/tiptap-extensions/-/tiptap-extensions-1.17.0.tgz#caa5ea47623f2c13b15b449001a061fbd96eeb32" + integrity sha512-ljlNG5rIpbggSO5FU27NAjfeDN3Kz18GqfNGoEOHHgvC5JDIj6x5QyiPOvCRNpuWN4t4XEMUkq+F8KjI5jceKw== dependencies: lowlight "^1.11.0" prosemirror-history "^1.0.4" prosemirror-state "^1.2.2" - prosemirror-tables "^0.7.10" + prosemirror-tables "^0.7.11" prosemirror-utils "^0.7.6" - prosemirror-view "^1.8.3" - tiptap "^1.14.0" - tiptap-commands "^1.7.0" + prosemirror-view "^1.8.9" + tiptap "^1.17.0" + tiptap-commands "^1.8.0" -tiptap-utils@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.3.0.tgz#bfc77cf57c07cd5c1f1d33f65ef94c4190506b77" - integrity sha512-b9GRQB3Kilu9Yq6hwjjzQgZtQDXDOrB/vZPV5OzwcKRN5a9PfLGrTLJ5LbU414Vcy9HTXiqX2pq0o5FslJhHpg== +tiptap-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.4.0.tgz#5449bc80afcc54730bd3010b6d5fd8cd6e62160c" + integrity sha512-uPG6LRzFUhkHl3UUYhXj1vA17c43ttZPKwkSkpzbrLBBl661UAAv7Z8grvOFBY9gVjzKeg1uIncRH2al2A3SQg== dependencies: prosemirror-model "^1.7.0" prosemirror-state "^1.2.2" - prosemirror-tables "^0.7.9" + prosemirror-tables "^0.7.11" prosemirror-utils "^0.7.6" -tiptap@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.14.0.tgz#8dd84b199533e08f0dcc34b39d517ea73e20fb95" - integrity sha512-38gCYeJx5O83oTnpfgMGGrjem1ZNDK2waaUMq+bkYPaQwvvtyMDGffvEIT9/jcLvA+WYfaNp8BWnn1rqNpYKxA== +tiptap@^1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.17.0.tgz#0dd7c8551378d43efbe1755504ba91d43ccb101d" + integrity sha512-8Qd/lkdgju2d7RdF5Ek6fzMpbPKGIt5YaFkRY0El2GMxt/4QcjX+6HWtcNl05fgIwF8uuPNy0CtSoeUi5KZGsQ== dependencies: prosemirror-commands "^1.0.7" prosemirror-dropcursor "^1.1.1" @@ -10301,9 +10431,9 @@ tiptap@^1.14.0: prosemirror-keymap "^1.0.1" prosemirror-model "^1.7.0" prosemirror-state "^1.2.1" - prosemirror-view "^1.8.3" - tiptap-commands "^1.7.0" - tiptap-utils "^1.3.0" + prosemirror-view "^1.8.9" + tiptap-commands "^1.8.0" + tiptap-utils "^1.4.0" tmp@^0.0.33: version "0.0.33" @@ -10486,6 +10616,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-fest@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" + integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== + type-is@^1.6.16, type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" @@ -10517,6 +10652,14 @@ uglify-js@3.4.x, uglify-js@^3.1.4: commander "~2.17.1" source-map "~0.6.1" +uglify-js@^3.5.1: + version "3.5.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.4.tgz#4a64d57f590e20a898ba057f838dcdfb67a939b9" + integrity sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA== + dependencies: + commander "~2.20.0" + source-map "~0.6.1" + undefsafe@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" @@ -10524,6 +10667,11 @@ undefsafe@^2.0.2: dependencies: debug "^2.2.0" +unfetch@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.1.0.tgz#6ec2dd0de887e58a4dee83a050ded80ffc4137db" + integrity sha512-crP/n3eAPUJxZXM9T80/yv0YhkTEx2K1D3h7D1AJM6fzsWZrxdyRuLN0JH/dkZh1LNH8LxCnBzoPFCPbb2iGpg== + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -10616,12 +10764,7 @@ unzip-response@^2.0.1: resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= -upath@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" - integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== - -upath@^1.1.1: +upath@^1.1.1, upath@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== @@ -10730,14 +10873,14 @@ uuid@^3.1.0, uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== -v-tooltip@~2.0.0-rc.33: - version "2.0.0-rc.33" - resolved "https://registry.yarnpkg.com/v-tooltip/-/v-tooltip-2.0.0-rc.33.tgz#78f7d8e9c34265622be65ba9dc78c67f1dc02b73" - integrity sha1-ePfY6cNCZWIr5lup3HjGfx3AK3M= +v-tooltip@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/v-tooltip/-/v-tooltip-2.0.2.tgz#8610d9eece2cc44fd66c12ef2f12eec6435cab9b" + integrity sha512-xQ+qzOFfywkLdjHknRPgMMupQNS8yJtf9Utd5Dxiu/0n4HtrxqsgDtN2MLZ0LKbburtSAQgyypuE/snM8bBZhw== dependencies: - lodash.merge "^4.6.0" - popper.js "^1.12.9" - vue-resize "^0.4.3" + lodash "^4.17.11" + popper.js "^1.15.0" + vue-resize "^0.4.5" validate-npm-package-license@^3.0.1: version "3.0.4" @@ -10852,10 +10995,10 @@ vue-jest@~3.0.4: tsconfig "^7.0.0" vue-template-es2015-compiler "^1.6.0" -vue-loader@^15.6.2: - version "15.6.2" - resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.6.2.tgz#892741d96260936ff69e892f72ec361ba4d100d2" - integrity sha512-T6fONodj861M3PqZ1jlbUFjeezbUnPRY2bd+3eZuDvYADgkN3VFU2H5feqySNg9XBt8rcbyBGmFWTZtrOX+v5w== +vue-loader@^15.7.0: + version "15.7.0" + resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.0.tgz#27275aa5a3ef4958c5379c006dd1436ad04b25b3" + integrity sha512-x+NZ4RIthQOxcFclEcs8sXGEWqnZHodL2J9Vq+hUz+TDZzBaDIh1j3d9M2IUlTjtrHTZy4uMuRdTi8BGws7jLA== dependencies: "@vue/component-compiler-utils" "^2.5.1" hash-sum "^1.0.2" @@ -10863,12 +11006,12 @@ vue-loader@^15.6.2: vue-hot-reload-api "^2.3.0" vue-style-loader "^4.1.0" -vue-meta@^1.5.8: - version "1.5.8" - resolved "https://registry.yarnpkg.com/vue-meta/-/vue-meta-1.5.8.tgz#1088d50cdf770525e37430186781bede929370a4" - integrity sha512-cF/ADL1kA8Gn6wfSx0+kYIPAmJ49y9R0QlMS9tg5ddDDZWaZMZ0rveFWaTOKr0eabUV/H3D9ip68Xt9f5SFbyA== +vue-meta@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/vue-meta/-/vue-meta-1.6.0.tgz#89b664f6011a207e098e8ba3b9d32e29c819b65d" + integrity sha512-LLHejsOYbJiSEDSgZvjHB3fFY7lUxsDFLkuSqf5eBohEvhhddBTOHa3heoFTcI5sxsZSZt26uUzoLVe4CT6Y4A== dependencies: - deepmerge "^3.0.0" + deepmerge "^3.2.0" lodash.isplainobject "^4.0.6" lodash.uniqueid "^4.0.1" object-assign "^4.1.1" @@ -10878,20 +11021,20 @@ vue-no-ssr@^1.1.1: resolved "https://registry.yarnpkg.com/vue-no-ssr/-/vue-no-ssr-1.1.1.tgz#875f3be6fb0ae41568a837f3ac1a80eaa137b998" integrity sha512-ZMjqRpWabMPqPc7gIrG0Nw6vRf1+itwf0Itft7LbMXs2g3Zs/NFmevjZGN1x7K3Q95GmIjWbQZTVerxiBxI+0g== -vue-resize@^0.4.3: +vue-resize@^0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-0.4.5.tgz#4777a23042e3c05620d9cbda01c0b3cc5e32dcea" integrity sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg== -vue-router@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.2.tgz#dedc67afe6c4e2bc25682c8b1c2a8c0d7c7e56be" - integrity sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg== +vue-router@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.6.tgz#2e4f0f9cbb0b96d0205ab2690cfe588935136ac3" + integrity sha512-Ox0ciFLswtSGRTHYhGvx2L44sVbTPNS+uD2kRISuo8B39Y79rOo0Kw0hzupTmiVtftQYCZl87mwldhh2L9Aquw== -vue-server-renderer@^2.5.22: - version "2.6.6" - resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.6.6.tgz#a2b1174cf1914817147b34789cc1a6baa0672aa1" - integrity sha512-dJ4IrIilS3nhxpOrR12+IKGu9Meg8L0t/W/e/UNSXKyh9EkwDqFPK0nZTfGPudXzr9FMQfg2hK6p2RMydPRU2Q== +vue-server-renderer@^2.6.10: + version "2.6.10" + resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz#cb2558842ead360ae2ec1f3719b75564a805b375" + integrity sha512-UYoCEutBpKzL2fKCwx8zlRtRtwxbPZXKTqbl2iIF4yRZUNO/ovrHyDAJDljft0kd+K0tZhN53XRHkgvCZoIhug== dependencies: chalk "^1.1.3" hash-sum "^1.0.2" @@ -10923,10 +11066,10 @@ vue-sweetalert-icons@~3.2.0: resolved "https://registry.yarnpkg.com/vue-sweetalert-icons/-/vue-sweetalert-icons-3.2.0.tgz#2926d3af5590b81c0ba3b104212922fc1709396d" integrity sha512-N18uG8++ZfdCnXO0gHNTmwpB2mAE8WWrwjGeWGa8CnHu6l1emn4RG6E8r1P9crVJ+fx3R9gTUezC+cdVu0mN7w== -vue-template-compiler@^2.5.22: - version "2.6.6" - resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.6.tgz#a807acbf3d51971d3721d75ecb1b927b517c1a02" - integrity sha512-OakxDGyrmMQViCjkakQFbDZlG0NibiOzpLauOfyCUVRQc9yPmTqpiz9nF0VeA+dFkXegetw0E5x65BFhhLXO0A== +vue-template-compiler@^2.6.10: + version "2.6.10" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz#323b4f3495f04faa3503337a82f5d6507799c9cc" + integrity sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg== dependencies: de-indent "^1.0.2" he "^1.1.0" @@ -10936,10 +11079,10 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.8.2: resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.8.2.tgz#dd73e80ba58bb65dd7a8aa2aeef6089cf6116f2a" integrity sha512-cliV19VHLJqFUYbz/XeWXe5CO6guzwd0yrrqqp0bmjlMP3ZZULY7fu8RTC4+3lmHwo6ESVDHFDsvjB15hcR5IA== -vue@^2.5.22: - version "2.6.6" - resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.6.tgz#dde41e483c11c46a7bf523909f4f2f816ab60d25" - integrity sha512-Y2DdOZD8sxApS+iUlwv1v8U1qN41kq6Kw45lM6nVZKhygeWA49q7VCCXkjXqeDBXgurrKWkYQ9cJeEJwAq0b9Q== +vue@^2.6.10: + version "2.6.10" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" + integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== vue@^2.6.6: version "2.6.8" @@ -10996,12 +11139,13 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-bundle-analyzer@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.0.4.tgz#095638487a664162f19e3b2fb7e621b7002af4b8" - integrity sha512-ggDUgtKuQki4vmc93Ej65GlYxeCUR/0THa7gA+iqAGC2FFAxO+r+RM9sAUa8HWdw4gJ3/NZHX/QUcVgRjdIsDg== +webpack-bundle-analyzer@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.3.2.tgz#3da733a900f515914e729fcebcd4c40dde71fc6f" + integrity sha512-7qvJLPKB4rRWZGjVp5U1KEjwutbDHSKboAl0IfafnrdXMrgC0tOtZbQD6Rw0u4cmpgRN4O02Fc0t8eAT+FgGzA== dependencies: - acorn "^5.7.3" + acorn "^6.0.7" + acorn-walk "^6.1.1" bfj "^6.1.1" chalk "^2.4.1" commander "^2.18.0" @@ -11014,12 +11158,12 @@ webpack-bundle-analyzer@^3.0.3: opener "^1.5.1" ws "^6.0.0" -webpack-dev-middleware@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.5.2.tgz#d768b6194f3fe8d72d51feded49de359e8d96ffb" - integrity sha512-nPmshdt1ckcwWjI0Ubrdp8KroeuprW6xFKYqk0u3MflNMBXvHPnMATsC7/L/enwav2zvLCfj/Usr47qnF3KQyA== +webpack-dev-middleware@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.6.2.tgz#f37a27ad7c09cd7dc67cd97655413abaa1f55942" + integrity sha512-A47I5SX60IkHrMmZUlB0ZKSWi29TZTcPz7cha1Z75yYOsgWh/1AcPmQEbC8ZIbU3A1ytSv1PMU0PyPz2Lmz2jg== dependencies: - memory-fs "~0.4.1" + memory-fs "^0.4.1" mime "^2.3.1" range-parser "^1.0.3" webpack-log "^2.0.0" @@ -11055,10 +11199,10 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.3.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.29.2: - version "4.29.6" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.6.tgz#66bf0ec8beee4d469f8b598d3988ff9d8d90e955" - integrity sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw== +webpack@^4.30.0: + version "4.30.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.30.0.tgz#aca76ef75630a22c49fcc235b39b4c57591d33a9" + integrity sha512-4hgvO2YbAFUhyTdlR4FNyt2+YaYBYHavyzjCMbZzgglo02rlKi/pcsEzwCuCpsn1ryzIl1cq/u8ArIKu8JBYMg== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -11085,19 +11229,19 @@ webpack@^4.29.2: watchpack "^1.5.0" webpack-sources "^1.3.0" -webpackbar@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-3.1.5.tgz#71f9de2d8b897785a3b3291cb6c8beecdf06542b" - integrity sha512-ayCxwj0m3lw8TMkbBBRl3XNiCIHqXYaQus8sNL+jX0lsp4LrYO9OmijsPeuu91cd/oUgK66c0AKQovPtJ1qDsA== +webpackbar@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-3.2.0.tgz#bdaad103fad11a4e612500e72aaae98b08ba493f" + integrity sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw== dependencies: - ansi-escapes "^3.1.0" + ansi-escapes "^4.1.0" chalk "^2.4.1" - consola "^2.3.0" - figures "^2.0.0" + consola "^2.6.0" + figures "^3.0.0" pretty-time "^1.1.0" std-env "^2.2.1" text-table "^0.2.0" - wrap-ansi "^4.0.0" + wrap-ansi "^5.1.0" whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.5" @@ -11190,14 +11334,14 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" -wrap-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-4.0.0.tgz#b3570d7c70156159a2d42be5cc942e957f7b1131" - integrity sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg== +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== dependencies: ansi-styles "^3.2.0" - string-width "^2.1.1" - strip-ansi "^4.0.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" wrappy@1: version "1.0.2" @@ -11255,6 +11399,13 @@ ws@^6.0.0: dependencies: async-limiter "~1.0.0" +ws@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"