From db29a0e90ad0320b37968df202704a570dba57c7 Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Thu, 21 Nov 2019 12:32:52 +0100 Subject: [PATCH 01/11] Update README: sequelize -> typeorm --- README.md | 137 +++++++++++++++++++++++------------------------------- 1 file changed, 59 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 88bb2bcfa8..aefde01bfb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # Welcome to Chapter -[![All Contributors](https://img.shields.io/badge/all_contributors-40-orange.svg?style=flat-square)](#contributors) After several years of being dissatisfied with existing group event tools (Meetup, Facebook events) we decided to build our own. @@ -31,7 +30,8 @@ To better communicate and more easily build an API and UI, we've decided on a co We are planning to use the following tools: * [Node.js](https://nodejs.org) / [Express](https://expressjs.com) for our backend using JavaScript/TypeScript -* [Postgres](https://www.postgresql.org) with [Sequelize ORM](https://sequelize.org) +* [Postgres](https://www.postgresql.org) with [TypeORM](https://typeorm.io/) +* [Elasticsearch](https://www.elastic.co/what-is/elasticsearch) * [Next.js](https://nextjs.org/) for both client and server-side rendering of the frontend (NextJS is based on [React](https://reactjs.org)) * [JavaScript/TypeScript](https://www.typescriptlang.org/index.html#download-links) * [Styled Components](https://www.styled-components.com) for styling. @@ -54,7 +54,7 @@ Ensure you are installing Node 10 or greater and npm 6 or greater. ### Installing Docker -See the [Docker installation "Supported platforms"](https://docs.docker.com/install/#supported-platforms) section and follow the instructions to download & install Docker Desktop for your operating system (or Docker CE for Linux). +Click [here](https://docs.docker.com/v17.12/install/) for the Docker installation site. Scroll down to "Supported Platforms" and follow the instructions to download & install Docker Desktop for your operating system (or Docker CE for linux). You can find more resources on Docker here: - [Docker: What and Why](https://stackoverflow.com/questions/28089344/docker-what-is-it-and-what-is-the-purpose) @@ -110,95 +110,76 @@ npm run test:watch ![a diagram illustrating the proposed schema for Chapter](data/schema.png) -## User Stories +## User stories so far -### MVP -The [MVP user stories are shown in the MVP Project](https://github.com/freeCodeCamp/chapter/projects/1) kanban / cards and as [issues marked with "MVP"](https://github.com/freeCodeCamp/chapter/labels/MVP). +Our goal is to keep things simple and not reinvent wheels. So far we have only two user roles: participants and chapter organizers, both of which are users. -### Post-MVP -We are maintaining a list of [post-MVP user stories](https://github.com/freeCodeCamp/chapter/issues/84). +### As a user + +- I can open a registration page where I can sign up with email and password. + +- I can log in with my email and password or I can log in with social login via Google. + +- I can see my account page where I can reset my password if I've registered with email and password. Otherwise I'll see a link to my Google profile. + +- I can log out. + +### As a future participant + +- I can use a search box on the landing page to input a city, state, or country name and it will autocomplete. I can click one of those locations. + +- When I click one of those locations, I can see the "show view" for that event's chapter, with details about the upcoming event, along with a button to RSVP. + +- I can click the "RSVP" button. When I do, I will be prompted to sign in. Then I will receive an email with a ticket and I will be added to the public list of event attendees. + +- I will receive a second email the day before the event to remind me. + +- After the event, I will automatically get emails notifying me of subsequent events. + +- I can filter all events in my location by tag/interests. + +### As an organizer + +- I can create a chapter. + +- I can edit details about the chapter, including a Slack/Discord/Facebook/WeChat/WhatsApp link participants can join to discuss and coordinate events. + +- I can create events, and set their location and capacity. + +- I can cancel events. + +- I can email the entire list of participants. + +- I can ban a participant whom I believe is toxic or who has previously broken my organization's code of conduct. + +- I can add a venue sponsor to the event with a link to their website as a way of thanking them for hosting. + +- I can add a food sponsor to the event with a link to their website as a way of thanking them for food. + +- I can see how many times a participant has come to the event as well as their attendance rate. + +- I can check-in attendees on the event registration desk with their `email_id` or `chapter_id`. ## Roadmap -The on-going [project Roadmap conversation](https://github.com/freeCodeCamp/chapter/issues/47) is regularly updated to reflect the overall progress and for higher-level discussions. +1. Design the schema. +2. Set up the API endpoints. +3. Build the web client and let other developers use the API to build mobile clients and voice interface clients. -Quincy Larson is the project lead. [FreeCodeCamp](https://www.freecodecamp.org) will start "dogfooding" the MVP with several of its local study groups. +Quincy Larson is the project lead. [FreeCodeCamp](https://www.freecodecamp.org) will start "dogfooding" this as soon as possible with several of its local study groups. Here's an out-dated example of an app with similar functionality: [The freeCodeCamp Study Group Directory](https://study-group-directory.freecodecamp.org). +You should [join our Discord server](https://discord.gg/vbRUYWS) to get connected with people interested in this project and to be aware of our future announcements. ## Contributing -* You should [join our Discord server](https://discord.gg/PXqYtEh) to get connected with people interested in this project and to be aware of our future announcements. -* Please read the [**suggested steps to contribute code to the Chapter project**](CONTRIBUTING.md) before creating issues, forking, or submitting any pull requests. +[**Take part in discussions or contribute code to this opensource codebase.**](CONTRIBUTING.md) ## License Copyright © 2019 freeCodeCamp.org -The computer software is licensed under the [BSD-3-Clause](LICENSE) license. - -## Contributors ✨ - -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Quincy Larson
Quincy Larson

💻 📖 🤔
Tim Chen
Tim Chen

💻 🚧 🔧
nikjohn
nikjohn

💻 📖 🔧
Matteo Giaccone
Matteo Giaccone

📦 💻 📖
Ian Littman
Ian Littman

💻
Abrar Rauf
Abrar Rauf

📖
Jonathan Chhabra
Jonathan Chhabra

🚧 💻
Thomas Roest
Thomas Roest

💻
Scott Brenner
Scott Brenner

📖
Jim Ciallella
Jim Ciallella

📖
Joel Rozen
Joel Rozen

💻
yitzhak-bloy
yitzhak-bloy

📖
Rob Bertram
Rob Bertram

💻
Fran Zekan
Fran Zekan

💻 🔧
Jesuloba Egunjobi
Jesuloba Egunjobi

📦
Lakshmipriya
Lakshmipriya

📖
Ronald van der Bergh
Ronald van der Bergh

📖
Rodolfo Mendes
Rodolfo Mendes

📖
Chris Gonzalez
Chris Gonzalez

📖
Gonzalo Gras Cantou
Gonzalo Gras Cantou

📖
Vivek Agrawal
Vivek Agrawal

📖 🔧 🎨
Kognise
Kognise

💻
Wendel Nascimento
Wendel Nascimento

💻
Praveen Durairaju
Praveen Durairaju

💻
Shangeeth Sivan
Shangeeth Sivan

📖
Conor Broderick
Conor Broderick

💻
PrestonElliott
PrestonElliott

📖 💻
VimalRaj Selvam
VimalRaj Selvam

💻
Franco Correa
Franco Correa

💻
Manoel
Manoel

📖
Dillon Mulroy
Dillon Mulroy

📖
Mirza Chilman
Mirza Chilman

📖
Cecilia
Cecilia

🤔
Sean
Sean

🎨
Madalena
Madalena

🎨
Ariel Barboza
Ariel Barboza

📖
Jonathan Seubert
Jonathan Seubert

🎨 📖
Juli Odomo
Juli Odomo

🎨
Vaibhav Singh
Vaibhav Singh

💻
Subroto
Subroto

💻
- - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! \ No newline at end of file +The content of this repository is bound by the following license(s): + +- The computer software is licensed under the [BSD-3-Clause](LICENSE) license. From 975b21f12bc51a2f672acda8ef10cb11b270ce4f Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Thu, 21 Nov 2019 14:23:16 +0100 Subject: [PATCH 02/11] Remove sequelize and add typeORM --- .sequelizerc | 8 - package-lock.json | 825 ++++++++++++++++++++-------------------------- package.json | 6 +- 3 files changed, 356 insertions(+), 483 deletions(-) delete mode 100644 .sequelizerc diff --git a/.sequelizerc b/.sequelizerc deleted file mode 100644 index 9da3a530ab..0000000000 --- a/.sequelizerc +++ /dev/null @@ -1,8 +0,0 @@ -const path = require('path'); - -module.exports = { - config: path.resolve('./config', 'db.json'), - 'models-path': path.resolve('./server/models'), - 'seeders-path': path.resolve('./server/seeders'), - 'migrations-path': path.resolve('./server/migrations'), -}; diff --git a/package-lock.json b/package-lock.json index 039401d681..6caaaf13a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1421,12 +1421,6 @@ "@babel/types": "^7.3.0" } }, - "@types/bluebird": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.28.tgz", - "integrity": "sha512-0Vk/kqkukxPKSzP9c8WJgisgGDx5oZDbsLLWIP5t70yThO/YleE+GEm2S1GlRALTaack3O7U5OS5qEm7q2kciA==", - "dev": true - }, "@types/body-parser": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz", @@ -1437,6 +1431,11 @@ "@types/node": "*" } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, "@types/connect": { "version": "3.4.32", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", @@ -1584,7 +1583,8 @@ "@types/node": { "version": "12.11.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.2.tgz", - "integrity": "sha512-dsfE4BHJkLQW+reOS6b17xhZ/6FB1rB8eRRvO08nn5o+voxf3i74tuyFWNH6djdfgX7Sm5s6LD8t6mJug4dpDw==" + "integrity": "sha512-dsfE4BHJkLQW+reOS6b17xhZ/6FB1rB8eRRvO08nn5o+voxf3i74tuyFWNH6djdfgX7Sm5s6LD8t6mJug4dpDw==", + "dev": true }, "@types/node-fetch": { "version": "2.5.2", @@ -2220,6 +2220,11 @@ } } }, + "app-root-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz", + "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==" + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -3323,20 +3328,6 @@ "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", "dev": true }, - "cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "dev": true, - "requires": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -3345,6 +3336,201 @@ "restore-cursor": "^2.0.0" } }, + "cli-highlight": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.4.tgz", + "integrity": "sha512-s7Zofobm20qriqDoU9sXptQx0t2R9PEgac92mENNm7xaEe1hn71IIMsXMK+6encA6WRCWWxIGQbipr3q998tlQ==", + "requires": { + "chalk": "^3.0.0", + "highlight.js": "^9.6.0", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^5.1.1", + "yargs": "^15.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz", + "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "parse5-htmlparser2-tree-adapter": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-5.1.1.tgz", + "integrity": "sha512-CF+TKjXqoqyDwHqBhFQ+3l5t83xYi6fVT1tQNg+Ye0JRLnTxWvIroCjEp1A0k4lneHNBGnICUf0cfYVYGEazqw==", + "requires": { + "parse5": "^5.1.1" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz", + "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^16.1.0" + } + }, + "yargs-parser": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "cli-spinners": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", @@ -3410,7 +3596,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -3420,14 +3605,12 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -3438,7 +3621,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -3450,15 +3632,6 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" }, - "cls-bluebird": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", - "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", - "requires": { - "is-bluebird": "^1.0.2", - "shimmer": "^1.1.0" - } - }, "clsx": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.0.4.tgz", @@ -3656,16 +3829,6 @@ } } }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "configstore": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", @@ -4127,16 +4290,6 @@ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -4192,8 +4345,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "decko": { "version": "1.2.0", @@ -4433,10 +4585,10 @@ "is-obj": "^2.0.0" } }, - "dottie": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.1.tgz", - "integrity": "sha512-ch5OQgvGDK2u8pSZeSYAQaV/lczImd7pMJ7BcEPXmnFVjy4yJIzP6CsODJUTH8mg1tyH1Z2abOiuJO3DjZ/GBw==" + "dotenv": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" }, "duplexer3": { "version": "0.1.4", @@ -4465,42 +4617,6 @@ "safer-buffer": "^2.1.0" } }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4540,8 +4656,7 @@ "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, "emojis-list": { "version": "2.1.0", @@ -4615,7 +4730,6 @@ "version": "1.16.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", - "dev": true, "requires": { "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", @@ -4633,63 +4747,18 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", "is-symbol": "^1.0.2" } }, - "es5-ext": { - "version": "0.10.51", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", - "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "^1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, "es6-promise": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", "dev": true }, - "es6-symbol": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", - "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", - "dev": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.51" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -5016,16 +5085,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "eventemitter3": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", @@ -5390,6 +5449,11 @@ "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" }, + "figlet": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.2.4.tgz", + "integrity": "sha512-mv8YA9RruB4C5QawPaD29rEVx3N97ZTyNrE4DAfbhuo6tpcMdKnPVo8MlyT3RP5uPcg5M14bEJBq7kjFf4kAWg==" + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -5597,17 +5661,6 @@ "readable-stream": "^2.0.0" } }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, "fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", @@ -6119,8 +6172,7 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-own-enumerable-property-symbols": { "version": "3.0.1", @@ -6405,6 +6457,11 @@ "minimalistic-assert": "^1.0.1" } }, + "highlight.js": { + "version": "9.16.2", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.16.2.tgz", + "integrity": "sha512-feMUrVLZvjy0oC7FVJQcSQRqbBq9kwqnYE4+Kj9ZjbHh3g+BisiPgF49NyQbVLNdrL/qqZr3Ca9yOKwgn2i/tw==" + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -6756,11 +6813,6 @@ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, - "inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6869,11 +6921,6 @@ "binary-extensions": "^1.0.0" } }, - "is-bluebird": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", - "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" - }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -6882,8 +6929,7 @@ "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, "is-ci": { "version": "2.0.0", @@ -6915,8 +6961,7 @@ "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-descriptor": { "version": "0.1.6", @@ -6958,8 +7003,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-generator-fn": { "version": "2.1.0", @@ -7078,7 +7122,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, "requires": { "has": "^1.0.1" } @@ -7104,7 +7147,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, "requires": { "has-symbols": "^1.0.0" } @@ -7759,31 +7801,6 @@ } } }, - "js-beautify": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.10.2.tgz", - "integrity": "sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ==", - "dev": true, - "requires": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "~0.5.1", - "nopt": "~4.0.1" - }, - "dependencies": { - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "dev": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - } - } - }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -7939,15 +7956,6 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, "jsonpointer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", @@ -8651,15 +8659,6 @@ "yallist": "^3.0.2" } }, - "lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dev": true, - "requires": { - "es5-ext": "~0.10.2" - } - }, "lunr": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.6.tgz", @@ -8766,22 +8765,6 @@ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" }, - "memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" - } - }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -9001,15 +8984,8 @@ "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "moment-timezone": { - "version": "0.5.27", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.27.tgz", - "integrity": "sha512-EIKQs7h5sAsjhPCqN6ggx6cEbs94GK050254TIJySD1bzoM5JTYDwAU1IoVOeTOL6Gm27kYJ51/uuvq1kIlrbw==", - "requires": { - "moment": ">= 2.9.0" - } + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "dev": true }, "morgan": { "version": "1.9.1", @@ -9047,6 +9023,16 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", @@ -9331,12 +9317,6 @@ } } }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true - }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -9869,8 +9849,7 @@ "object-inspect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==" }, "object-keys": { "version": "1.1.1", @@ -9924,7 +9903,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" @@ -10074,12 +10052,6 @@ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -10095,16 +10067,6 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -10213,6 +10175,11 @@ } } }, + "parent-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", + "integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=" + }, "parse-asn1": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", @@ -11135,12 +11102,6 @@ "reflect.ownkeys": "^0.2.0" } }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, "proxy-addr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", @@ -11774,14 +11735,12 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "reselect": { "version": "3.0.1", @@ -11834,14 +11793,6 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, - "retry-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", - "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", - "requires": { - "any-promise": "^1.3.0" - } - }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -11953,8 +11904,7 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "scheduler": { "version": "0.17.0", @@ -12034,92 +11984,6 @@ } } }, - "sequelize": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.1.tgz", - "integrity": "sha512-JI+53MwcClfCFUPJT/l2dDzSpEzWAueyCZus33L/yhJxKTisfdd9OHrUPQ6/dI5nR5eIYT/EafrjkqTAlEQS2w==", - "requires": { - "bluebird": "^3.5.0", - "cls-bluebird": "^2.1.0", - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.24.0", - "moment-timezone": "^0.5.21", - "retry-as-promised": "^3.2.0", - "semver": "^6.3.0", - "sequelize-pool": "^2.3.0", - "toposort-class": "^1.0.1", - "uuid": "^3.3.3", - "validator": "^10.11.0", - "wkx": "^0.4.8" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "sequelize-cli": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-5.5.1.tgz", - "integrity": "sha512-ZM4kUZvY3y14y+Rq3cYxGH7YDJz11jWHcN2p2x7rhAIemouu4CEXr5ebw30lzTBtyXV4j2kTO+nUjZOqzG7k+Q==", - "dev": true, - "requires": { - "bluebird": "^3.5.3", - "cli-color": "^1.4.0", - "fs-extra": "^7.0.1", - "js-beautify": "^1.8.8", - "lodash": "^4.17.5", - "resolve": "^1.5.0", - "umzug": "^2.1.0", - "yargs": "^13.1.0" - } - }, - "sequelize-pool": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-2.3.0.tgz", - "integrity": "sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA==" - }, - "sequelize-typescript": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sequelize-typescript/-/sequelize-typescript-1.0.0.tgz", - "integrity": "sha512-oXyvHRTOyI8sJettpISL5LO30GaMMrLqzxiLCy6MjUmBJdaQDpdjn7ofge4J87MSdw+YPzkjrJLogMc9ONY2Tg==", - "requires": { - "glob": "7.1.2" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, "serialize-javascript": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", @@ -12139,8 +12003,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-value": { "version": "2.0.1", @@ -12214,11 +12077,6 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, - "shimmer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", - "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" - }, "should": { "version": "13.2.3", "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", @@ -12273,12 +12131,6 @@ "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", "dev": true }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -12726,7 +12578,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -12736,7 +12587,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "dev": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -13376,6 +13226,22 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, "throat": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", @@ -13410,16 +13276,6 @@ "setimmediate": "^1.0.4" } }, - "timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dev": true, - "requires": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", @@ -13500,11 +13356,6 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, - "toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -13589,12 +13440,6 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -13632,6 +13477,51 @@ "is-typedarray": "^1.0.0" } }, + "typeorm": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.20.tgz", + "integrity": "sha512-VxB+9qH8D+PM19MIx18Zs3Fqv/ZINnnQvUGmBEiLYDrB9etdSdamgSTCIhWdFNndeJ6ldH4jbD0Z6HWsepMPlA==", + "requires": { + "app-root-path": "^2.0.1", + "buffer": "^5.1.0", + "chalk": "^2.4.2", + "cli-highlight": "^2.0.0", + "debug": "^4.1.1", + "dotenv": "^6.2.0", + "glob": "^7.1.2", + "js-yaml": "^3.13.1", + "mkdirp": "^0.5.1", + "reflect-metadata": "^0.1.13", + "tslib": "^1.9.0", + "xml2js": "^0.4.17", + "yargonaut": "^1.1.2", + "yargs": "^13.2.1" + }, + "dependencies": { + "buffer": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "typescript": { "version": "3.6.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", @@ -13664,16 +13554,6 @@ } } }, - "umzug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.2.0.tgz", - "integrity": "sha512-xZLW76ax70pND9bx3wqwb8zqkFGzZIK8dIHD9WdNy/CrNfjWcwQgQkGCuUqcuwEBvUm+g07z+qWvY+pxDmMEEw==", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "bluebird": "^3.5.3" - } - }, "undefsafe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", @@ -13758,12 +13638,6 @@ "crypto-random-string": "^1.0.0" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -13918,7 +13792,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, "requires": { "define-properties": "^1.1.2", "object.getownpropertydescriptors": "^2.0.3" @@ -13949,11 +13822,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" - }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -14180,8 +14048,7 @@ "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, "widest-line": { "version": "2.0.1", @@ -14198,14 +14065,6 @@ "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", "dev": true }, - "wkx": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.8.tgz", - "integrity": "sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==", - "requires": { - "@types/node": "*" - } - }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -14232,7 +14091,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -14242,14 +14100,12 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -14258,7 +14114,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -14269,7 +14124,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -14322,6 +14176,21 @@ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, + "xml2js": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", + "requires": { + "sax": ">=0.6.0", + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -14357,11 +14226,34 @@ } } }, + "yargonaut": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/yargonaut/-/yargonaut-1.1.4.tgz", + "integrity": "sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==", + "requires": { + "chalk": "^1.1.1", + "figlet": "^1.1.1", + "parent-require": "^1.0.0" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + } + } + }, "yargs": { "version": "13.3.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", @@ -14378,14 +14270,12 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, "requires": { "locate-path": "^3.0.0" } @@ -14394,7 +14284,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -14404,7 +14293,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, "requires": { "p-try": "^2.0.0" } @@ -14413,7 +14301,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, "requires": { "p-limit": "^2.0.0" } @@ -14421,14 +14308,12 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -14439,7 +14324,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -14450,7 +14334,6 @@ "version": "13.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" diff --git a/package.json b/package.json index cbacca0c6b..6226b6847b 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "lint:fix": "eslint './**/*.{ts,tsx,js,jsx}' --fix", "next:build": "next build", "nodemon": "npx nodemon", + "typeorm": "ts-node -P tsconfig.server.json node_modules/typeorm/cli.js", "pretty": "prettier --write client/**/*.ts* server/**/*.ts", "prod:server": "NODE_ENV=production ts-node --files --transpile-only ./server/index.ts", "speccy:watch": "npx nodemon --watch 'api/swagger.json' --exec 'npm run speccy'", @@ -55,15 +56,13 @@ "react-dom": "^16.10.2", "react-hook-form": "^3.28.1", "reflect-metadata": "^0.1.13", - "sequelize": "^5.21.1", - "sequelize-typescript": "^1.0.0", "styled-components": "^4.4.0", "ts-node": "^8.4.1", + "typeorm": "^0.2.20", "typescript": "^3.6.4" }, "devDependencies": { "@testing-library/react": "^9.3.0", - "@types/bluebird": "^3.5.28", "@types/express": "^4.17.1", "@types/jest": "^24.0.19", "@types/morgan": "^1.7.37", @@ -88,7 +87,6 @@ "lint-staged": "^9.4.2", "nodemon": "^1.19.4", "prettier": "^1.18.2", - "sequelize-cli": "^5.5.1", "speccy": "^0.11.0" }, "lint-staged": { From 844eef9c19a608f2a6b57d06f5f5823d23a477f7 Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Thu, 21 Nov 2019 14:23:41 +0100 Subject: [PATCH 03/11] init typeorm --- ormconfig.json | 18 ++++++++++++++++++ server/db.ts | 11 +++++++---- server/index.ts | 5 +++-- 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 ormconfig.json diff --git a/ormconfig.json b/ormconfig.json new file mode 100644 index 0000000000..00a0ab83ba --- /dev/null +++ b/ormconfig.json @@ -0,0 +1,18 @@ +{ + "type": "postgres", + "host": "localhost", + "port": 54320, + "username": "postgres", + "password": "password", + "database": "chapter", + "synchronize": false, + "logging": false, + "entities": ["server/models/**/*.ts"], + "migrations": ["server/migrations/**/*.ts"], + "subscribers": ["src/subscriber/**/*.ts"], + "cli": { + "entitiesDir": "server/models", + "migrationsDir": "server/migrations", + "subscribersDir": "server/subscriber" + } +} diff --git a/server/db.ts b/server/db.ts index c4321cffa5..6c37da0fd9 100644 --- a/server/db.ts +++ b/server/db.ts @@ -1,11 +1,14 @@ -import { Sequelize } from 'sequelize-typescript'; +import 'reflect-metadata'; +import { createConnection } from 'typeorm'; -export const initSequelize = new Sequelize({ - dialect: 'postgres', +export const initDB = createConnection({ + type: 'postgres', username: process.env.DB_USER || 'postgres', password: process.env.DB_PASSWORD || 'password', database: process.env.DB_NAME || 'chapter', host: process.env.DB_URL || 'db', port: 5432, - models: [__dirname + '/models/*.ts'], + entities: [__dirname + '/models/*.ts'], + synchronize: false, + logging: false, }); diff --git a/server/index.ts b/server/index.ts index 860c507757..29e93ce6cd 100644 --- a/server/index.ts +++ b/server/index.ts @@ -6,14 +6,15 @@ import { responseErrorHandler } from 'express-response-errors'; import exampleRouter from 'server/routers/exampleRouter'; import chapterRouter from 'server/routers/chapter'; -import { initSequelize } from 'server/db'; +import { initDB } from 'server/db'; const app: express.Application = express(); nextjs.nextApp.prepare().then(async () => { const port = process.env.PORT || 8000; - await initSequelize.authenticate(); + await initDB; + // await connection.runMigrations(); app.use( morgan(':method :url :status', { From c9066cf5a81e4ddb1980927d767006a45c97e6e1 Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Thu, 21 Nov 2019 14:24:03 +0100 Subject: [PATCH 04/11] Migrate Chapter model and migration to typeORM --- server/migrations/1574341690449-Chapter.ts | 24 ++++++++++++ .../20191025082945-create-chapter.js | 39 ------------------- server/models/Chapter.ts | 33 ++++++++-------- server/routers/chapter/routes/list.ts | 2 +- 4 files changed, 42 insertions(+), 56 deletions(-) create mode 100644 server/migrations/1574341690449-Chapter.ts delete mode 100644 server/migrations/20191025082945-create-chapter.js diff --git a/server/migrations/1574341690449-Chapter.ts b/server/migrations/1574341690449-Chapter.ts new file mode 100644 index 0000000000..e7ddcf9dbb --- /dev/null +++ b/server/migrations/1574341690449-Chapter.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class Chapter1574341690449 implements MigrationInterface { + name = 'Chapter1574341690449'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "chapters" ( + "id" SERIAL NOT NULL, + "name" character varying NOT NULL, + "description" character varying NOT NULL, + "category" character varying NOT NULL, + "details" json NOT NULL, + "created_at" TIMESTAMP NOT NULL DEFAULT now(), + "updated_at" TIMESTAMP NOT NULL DEFAULT now(), + CONSTRAINT "PK_a2bbdbb4bdc786fe0cb0fcfc4a0" PRIMARY KEY ("id"))`, + undefined, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "chapters"`, undefined); + } +} diff --git a/server/migrations/20191025082945-create-chapter.js b/server/migrations/20191025082945-create-chapter.js deleted file mode 100644 index d340ca04c2..0000000000 --- a/server/migrations/20191025082945-create-chapter.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; -module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.createTable('chapters', { - id: { - allowNull: false, - autoIncrement: true, - primaryKey: true, - type: Sequelize.INTEGER, - }, - name: { - type: Sequelize.STRING, - allowNull: false, - }, - description: { - type: Sequelize.STRING, - allowNull: false, - }, - category: { - type: Sequelize.STRING, - allowNull: false, - }, - details: { - type: Sequelize.JSON, - }, - created_at: { - allowNull: false, - type: Sequelize.DATE, - }, - updated_at: { - allowNull: false, - type: Sequelize.DATE, - }, - }); - }, - down: (queryInterface, _sequelize) => { - return queryInterface.dropTable('Chapters'); - }, -}; diff --git a/server/models/Chapter.ts b/server/models/Chapter.ts index 584409a3c1..263e381385 100644 --- a/server/models/Chapter.ts +++ b/server/models/Chapter.ts @@ -1,31 +1,32 @@ import { + PrimaryGeneratedColumn, + BaseEntity, + CreateDateColumn, + UpdateDateColumn, Column, - CreatedAt, - Model, - Table, - UpdatedAt, - DataType, -} from 'sequelize-typescript'; + Entity, +} from 'typeorm'; -@Table -export class Chapter extends Model { - @Column +@Entity({ name: 'chapters' }) +export class Chapter extends BaseEntity { + @PrimaryGeneratedColumn() + id: number; + + @Column({ nullable: false }) name!: string; - @Column + @Column({ nullable: false }) description!: string; - @Column + @Column({ nullable: false }) category!: string; - @Column(DataType.JSON) + @Column({ type: 'json' }) details!: any; - @CreatedAt - @Column + @CreateDateColumn({ type: 'timestamp' }) created_at!: Date; - @UpdatedAt - @Column + @UpdateDateColumn({ type: 'timestamp' }) updated_at!: Date; } diff --git a/server/routers/chapter/routes/list.ts b/server/routers/chapter/routes/list.ts index 49209ad1d9..98fc507c7e 100644 --- a/server/routers/chapter/routes/list.ts +++ b/server/routers/chapter/routes/list.ts @@ -3,7 +3,7 @@ import asyncHandler from 'express-async-handler'; import { Chapter } from 'server/models/Chapter'; export default asyncHandler(async (_req, res) => { - const chapters = await Chapter.findAll(); + const chapters = await Chapter.find(); res.json(chapters); }); From 67da36e0fbea37b8f5685aabe2f7cd12176d904d Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Thu, 21 Nov 2019 14:25:18 +0100 Subject: [PATCH 05/11] Remove old sequelize config --- config/db.json | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 config/db.json diff --git a/config/db.json b/config/db.json deleted file mode 100644 index 631f1b59ad..0000000000 --- a/config/db.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "development": { - "username": "postgres", - "password": "password", - "database": "chapter", - "host": "127.0.0.1", - "dialect": "postgres", - "port": 54320 - }, - "test": { - "username": "postgres", - "password": "password", - "database": "chapter", - "host": "127.0.0.1", - "dialect": "postgres", - "port": 54320 - }, - "production": { - "username": "postgres", - "password": "password", - "database": "chapter", - "host": "127.0.0.1", - "dialect": "postgres", - "port": 54320 - } -} From 5ed94e8702e7f6fca028e8597c9f39ccf2b508e9 Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Sat, 23 Nov 2019 00:46:40 +0100 Subject: [PATCH 06/11] WIP: Add beginning of docs --- server/docs/README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 server/docs/README.md diff --git a/server/docs/README.md b/server/docs/README.md new file mode 100644 index 0000000000..7e77bc9ad7 --- /dev/null +++ b/server/docs/README.md @@ -0,0 +1,25 @@ +# Server side technical documentation + +## Database + +for any problems ping @Zeko369 + +We're using Postgres for our database and TypeORM for our ORM (mapping database tables to js objects). Here are a few examples on how to use our TypeORM setup. + +To make it since the port from docker postgres service is exposed to the host (54320) you dont have to run `docker-compose exec...`, and can just run db commands from the host + +### Create a new model / entity + +`npm run typeorm entity:create -- --name=ModelName` + +This would create `ModelName.ts` in `server/models` + +You could also run `npx typeorm` since here you're not actually loading any ts files, but because regular `npx typeorm` runs inside of node it import from `.ts` files, so we run it with `ts-node` and our custom server config (check package.json) + +### Create a migration + +`npm run typeorm entity:create -- --name=ModelName` + +`npm run typeorm migration:generate -- --name=MigrationName` + +`npm run typeorm migration:show` From 51b27c555506f96ea08905a9ac385e1186adcdbd Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Tue, 26 Nov 2019 21:41:14 +0100 Subject: [PATCH 07/11] WIP: Add simple example with repo vs ActiveRecord pattern --- server/controllers/chapterController.ts | 84 +++++++++++++++++++++++++ server/db.ts | 1 + server/index.ts | 6 +- server/models/Chapter.ts | 17 +++++ server/models/ChapterRepo.ts | 47 ++++++++++++++ server/routers/chapter.ts | 16 +++++ server/routers/chapter/index.ts | 9 --- server/routers/chapter/routes/list.ts | 9 --- 8 files changed, 168 insertions(+), 21 deletions(-) create mode 100644 server/controllers/chapterController.ts create mode 100644 server/models/ChapterRepo.ts create mode 100644 server/routers/chapter.ts delete mode 100644 server/routers/chapter/index.ts delete mode 100644 server/routers/chapter/routes/list.ts diff --git a/server/controllers/chapterController.ts b/server/controllers/chapterController.ts new file mode 100644 index 0000000000..db54477ac1 --- /dev/null +++ b/server/controllers/chapterController.ts @@ -0,0 +1,84 @@ +import { getConnection } from 'typeorm'; +import { Request, Response } from 'express'; + +import { Chapter } from 'server/models/Chapter'; +import { ChapterRepo } from 'server/models/ChapterRepo'; + +export default { + async index(_req: Request, res: Response) { + const chapters = await Chapter.find(); + + res.json(chapters); + }, + + async index_repo(_req: Request, res: Response) { + const chapters = await getConnection() + .getRepository(ChapterRepo) + .find(); + + res.json(chapters); + }, + + async show(req: Request, res: Response) { + const { id } = req.params; + + const chapter = await Chapter.findOne({ id: parseInt(id) }); + + if (chapter) { + res.json(chapter); + } else { + res.status(404).json({ error: 'Cant find chapter' }); + } + }, + + async create(req: Request, res: Response) { + const { name, description, category, details } = req.body; + const chapter = new Chapter({ name, description, category, details }); + + try { + await chapter.save(); + res.status(201).json(chapter); + } catch (e) { + res.status(500).json({ error: e }); + } + }, + + async update(req: Request, res: Response) { + const { id } = req.params; + const { name, description, category, details } = req.body; + + const chapter = await Chapter.findOne({ id: parseInt(id) }); + + if (chapter) { + name && (chapter.name = name); + description && (chapter.description = description); + category && (chapter.category = category); + details && (chapter.details = details); + + try { + await chapter.save(); + res.json(chapter); + } catch (e) { + res.status(500).json({ error: e }); + } + } else { + res.status(404).json({ error: 'Cant find chapter' }); + } + }, + async remove(req: Request, res: Response) { + const { id } = req.params; + + const chapter = await Chapter.findOne({ id: parseInt(id) }); + + if (chapter) { + try { + await chapter.remove(); + res.json({ id }); + } catch (e) { + res.status(500).json({ error: e }); + } + } else { + res.status(404).json({ error: 'Cant find chapter' }); + } + }, +}; diff --git a/server/db.ts b/server/db.ts index 6c37da0fd9..843bad4745 100644 --- a/server/db.ts +++ b/server/db.ts @@ -11,4 +11,5 @@ export const initDB = createConnection({ entities: [__dirname + '/models/*.ts'], synchronize: false, logging: false, + name: 'default', }); diff --git a/server/index.ts b/server/index.ts index 29e93ce6cd..68c99f9fa4 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1,11 +1,11 @@ import 'module-alias/register'; import express from 'express'; import morgan from 'morgan'; + import nextjs from 'server/lib/next'; import { responseErrorHandler } from 'express-response-errors'; import exampleRouter from 'server/routers/exampleRouter'; import chapterRouter from 'server/routers/chapter'; - import { initDB } from 'server/db'; const app: express.Application = express(); @@ -13,8 +13,8 @@ const app: express.Application = express(); nextjs.nextApp.prepare().then(async () => { const port = process.env.PORT || 8000; - await initDB; - // await connection.runMigrations(); + const connection = await initDB; + await connection.runMigrations(); app.use( morgan(':method :url :status', { diff --git a/server/models/Chapter.ts b/server/models/Chapter.ts index 263e381385..1081a0c0d0 100644 --- a/server/models/Chapter.ts +++ b/server/models/Chapter.ts @@ -29,4 +29,21 @@ export class Chapter extends BaseEntity { @UpdateDateColumn({ type: 'timestamp' }) updated_at!: Date; + + constructor(params: { + name: string; + description: string; + category: string; + details: any; + }) { + super(); + if (params) { + const { name, description, category, details } = params; + + this.name = name; + this.description = description; + this.category = category; + this.details = details; + } + } } diff --git a/server/models/ChapterRepo.ts b/server/models/ChapterRepo.ts new file mode 100644 index 0000000000..8c1b605519 --- /dev/null +++ b/server/models/ChapterRepo.ts @@ -0,0 +1,47 @@ +import { + PrimaryGeneratedColumn, + CreateDateColumn, + UpdateDateColumn, + Column, + Entity, +} from 'typeorm'; + +@Entity({ name: 'chapters' }) +export class ChapterRepo { + @PrimaryGeneratedColumn() + id: number; + + @Column({ nullable: false }) + name!: string; + + @Column({ nullable: false }) + description!: string; + + @Column({ nullable: false }) + category!: string; + + @Column({ type: 'json' }) + details!: any; + + @CreateDateColumn({ type: 'timestamp' }) + created_at!: Date; + + @UpdateDateColumn({ type: 'timestamp' }) + updated_at!: Date; + + constructor(params: { + name: string; + description: string; + category: string; + details: any; + }) { + if (params) { + const { name, description, category, details } = params; + + this.name = name; + this.description = description; + this.category = category; + this.details = details; + } + } +} diff --git a/server/routers/chapter.ts b/server/routers/chapter.ts new file mode 100644 index 0000000000..eed2734614 --- /dev/null +++ b/server/routers/chapter.ts @@ -0,0 +1,16 @@ +import express from 'express'; +import asyncHandler from 'express-async-handler'; + +import chapterController from 'server/controllers/chapterController'; + +const router = express.Router(); + +router.get('/api/chapters', asyncHandler(chapterController.index)); +router.get('/api/chapters_repo', asyncHandler(chapterController.index_repo)); //TODO: REMOVE THIS IS AN EXAMPLE + +router.post('/api/chapters', asyncHandler(chapterController.create)); +router.get('/api/chapters/:id', asyncHandler(chapterController.show)); +router.patch('/api/chapters/:id', asyncHandler(chapterController.update)); +router.delete('/api/chapters/:id', asyncHandler(chapterController.remove)); + +export default router; diff --git a/server/routers/chapter/index.ts b/server/routers/chapter/index.ts deleted file mode 100644 index fc02c36607..0000000000 --- a/server/routers/chapter/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import express from 'express'; - -import list from './routes/list'; - -const router = express.Router(); - -router.get('/api/chapters', list); - -export default router; diff --git a/server/routers/chapter/routes/list.ts b/server/routers/chapter/routes/list.ts deleted file mode 100644 index 98fc507c7e..0000000000 --- a/server/routers/chapter/routes/list.ts +++ /dev/null @@ -1,9 +0,0 @@ -import asyncHandler from 'express-async-handler'; - -import { Chapter } from 'server/models/Chapter'; - -export default asyncHandler(async (_req, res) => { - const chapters = await Chapter.find(); - - res.json(chapters); -}); From a31ceadc48ba1ed0b95b642be3b572d6b386e6d7 Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Fri, 6 Dec 2019 12:34:41 +0100 Subject: [PATCH 08/11] Remove example, refactor --- server/controllers/chapterController.ts | 11 ----- server/index.ts | 6 +-- server/models/ChapterRepo.ts | 47 ------------------- server/routers/chapter.ts | 2 - .../{ => exampleRoutes}/exampleRouter.ts | 6 +-- .../routes/sampleAsyncRoute.ts | 0 .../routes/sampleErroredRoute.ts | 0 .../{ => exampleRoutes}/routes/sampleRoute.ts | 0 8 files changed, 6 insertions(+), 66 deletions(-) delete mode 100644 server/models/ChapterRepo.ts rename server/routers/{ => exampleRoutes}/exampleRouter.ts (55%) rename server/routers/{ => exampleRoutes}/routes/sampleAsyncRoute.ts (100%) rename server/routers/{ => exampleRoutes}/routes/sampleErroredRoute.ts (100%) rename server/routers/{ => exampleRoutes}/routes/sampleRoute.ts (100%) diff --git a/server/controllers/chapterController.ts b/server/controllers/chapterController.ts index db54477ac1..3ec3ed30e9 100644 --- a/server/controllers/chapterController.ts +++ b/server/controllers/chapterController.ts @@ -1,8 +1,5 @@ -import { getConnection } from 'typeorm'; import { Request, Response } from 'express'; - import { Chapter } from 'server/models/Chapter'; -import { ChapterRepo } from 'server/models/ChapterRepo'; export default { async index(_req: Request, res: Response) { @@ -11,14 +8,6 @@ export default { res.json(chapters); }, - async index_repo(_req: Request, res: Response) { - const chapters = await getConnection() - .getRepository(ChapterRepo) - .find(); - - res.json(chapters); - }, - async show(req: Request, res: Response) { const { id } = req.params; diff --git a/server/index.ts b/server/index.ts index 68c99f9fa4..383f1ac4bc 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1,11 +1,11 @@ import 'module-alias/register'; import express from 'express'; import morgan from 'morgan'; - -import nextjs from 'server/lib/next'; import { responseErrorHandler } from 'express-response-errors'; -import exampleRouter from 'server/routers/exampleRouter'; + +import exampleRouter from 'server/routers/exampleRoutes/exampleRouter'; import chapterRouter from 'server/routers/chapter'; +import nextjs from 'server/lib/next'; import { initDB } from 'server/db'; const app: express.Application = express(); diff --git a/server/models/ChapterRepo.ts b/server/models/ChapterRepo.ts deleted file mode 100644 index 8c1b605519..0000000000 --- a/server/models/ChapterRepo.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - PrimaryGeneratedColumn, - CreateDateColumn, - UpdateDateColumn, - Column, - Entity, -} from 'typeorm'; - -@Entity({ name: 'chapters' }) -export class ChapterRepo { - @PrimaryGeneratedColumn() - id: number; - - @Column({ nullable: false }) - name!: string; - - @Column({ nullable: false }) - description!: string; - - @Column({ nullable: false }) - category!: string; - - @Column({ type: 'json' }) - details!: any; - - @CreateDateColumn({ type: 'timestamp' }) - created_at!: Date; - - @UpdateDateColumn({ type: 'timestamp' }) - updated_at!: Date; - - constructor(params: { - name: string; - description: string; - category: string; - details: any; - }) { - if (params) { - const { name, description, category, details } = params; - - this.name = name; - this.description = description; - this.category = category; - this.details = details; - } - } -} diff --git a/server/routers/chapter.ts b/server/routers/chapter.ts index eed2734614..ab66bd38d3 100644 --- a/server/routers/chapter.ts +++ b/server/routers/chapter.ts @@ -6,8 +6,6 @@ import chapterController from 'server/controllers/chapterController'; const router = express.Router(); router.get('/api/chapters', asyncHandler(chapterController.index)); -router.get('/api/chapters_repo', asyncHandler(chapterController.index_repo)); //TODO: REMOVE THIS IS AN EXAMPLE - router.post('/api/chapters', asyncHandler(chapterController.create)); router.get('/api/chapters/:id', asyncHandler(chapterController.show)); router.patch('/api/chapters/:id', asyncHandler(chapterController.update)); diff --git a/server/routers/exampleRouter.ts b/server/routers/exampleRoutes/exampleRouter.ts similarity index 55% rename from server/routers/exampleRouter.ts rename to server/routers/exampleRoutes/exampleRouter.ts index 86820c6534..069d90d65c 100644 --- a/server/routers/exampleRouter.ts +++ b/server/routers/exampleRoutes/exampleRouter.ts @@ -1,8 +1,8 @@ import express from 'express'; -import sampleRoute from 'server/routers/routes/sampleRoute'; -import sampleAsyncRoute from 'server/routers/routes/sampleAsyncRoute'; -import sampleErroredRoute from 'server/routers/routes/sampleErroredRoute'; +import sampleRoute from './routes/sampleRoute'; +import sampleAsyncRoute from './routes/sampleAsyncRoute'; +import sampleErroredRoute from './routes/sampleErroredRoute'; const router = express.Router(); diff --git a/server/routers/routes/sampleAsyncRoute.ts b/server/routers/exampleRoutes/routes/sampleAsyncRoute.ts similarity index 100% rename from server/routers/routes/sampleAsyncRoute.ts rename to server/routers/exampleRoutes/routes/sampleAsyncRoute.ts diff --git a/server/routers/routes/sampleErroredRoute.ts b/server/routers/exampleRoutes/routes/sampleErroredRoute.ts similarity index 100% rename from server/routers/routes/sampleErroredRoute.ts rename to server/routers/exampleRoutes/routes/sampleErroredRoute.ts diff --git a/server/routers/routes/sampleRoute.ts b/server/routers/exampleRoutes/routes/sampleRoute.ts similarity index 100% rename from server/routers/routes/sampleRoute.ts rename to server/routers/exampleRoutes/routes/sampleRoute.ts From 7808ca36e945cb70060b5334641ba6b470242850 Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Fri, 6 Dec 2019 12:58:36 +0100 Subject: [PATCH 09/11] Update docs, reorganize example files --- server/docs/README.md | 23 +++++++++++++++++-- server/index.ts | 4 ++-- server/{routers => routes}/chapter.ts | 0 .../exampleRoutes/exampleRouter.ts | 0 .../exampleRoutes/routes/sampleAsyncRoute.ts | 0 .../routes/sampleErroredRoute.ts | 0 .../exampleRoutes/routes/sampleRoute.ts | 0 7 files changed, 23 insertions(+), 4 deletions(-) rename server/{routers => routes}/chapter.ts (100%) rename server/{routers => routes}/exampleRoutes/exampleRouter.ts (100%) rename server/{routers => routes}/exampleRoutes/routes/sampleAsyncRoute.ts (100%) rename server/{routers => routes}/exampleRoutes/routes/sampleErroredRoute.ts (100%) rename server/{routers => routes}/exampleRoutes/routes/sampleRoute.ts (100%) diff --git a/server/docs/README.md b/server/docs/README.md index 7e77bc9ad7..dca55e04ac 100644 --- a/server/docs/README.md +++ b/server/docs/README.md @@ -6,7 +6,7 @@ for any problems ping @Zeko369 We're using Postgres for our database and TypeORM for our ORM (mapping database tables to js objects). Here are a few examples on how to use our TypeORM setup. -To make it since the port from docker postgres service is exposed to the host (54320) you dont have to run `docker-compose exec...`, and can just run db commands from the host +To make it since the port from docker postgres service is exposed to the host (54320) you dont have to run `docker-compose exec...`, and can just run db commands from the host. This also makes it a lot easier to access the db from the ourside if you're running a local db on the system. ### Create a new model / entity @@ -18,8 +18,27 @@ You could also run `npx typeorm` since here you're not actually loading any ts f ### Create a migration -`npm run typeorm entity:create -- --name=ModelName` +After you created a new model or updated an existing one, you need to generate a migration for those changes. To do so run: `npm run typeorm migration:generate -- --name=MigrationName` +Since this runs a compare agains the current db schema, you need to have the app running. + +After that, check the generated SQL in `server/migrations/date-MigrationName.ts` + +### Running migrations and checking if migrations were run + +You can manualy run them by doing +`npm run typeorm migration:run` + +and then check if it happened correctly + `npm run typeorm migration:show` + +it should ouput something like + +``` + [X] Chapter1574341690449 + ... + [X] MigrationName1575633316367 +``` diff --git a/server/index.ts b/server/index.ts index 383f1ac4bc..07d45a8ac2 100644 --- a/server/index.ts +++ b/server/index.ts @@ -3,8 +3,8 @@ import express from 'express'; import morgan from 'morgan'; import { responseErrorHandler } from 'express-response-errors'; -import exampleRouter from 'server/routers/exampleRoutes/exampleRouter'; -import chapterRouter from 'server/routers/chapter'; +import exampleRouter from 'server/routes/exampleRoutes/exampleRouter'; +import chapterRouter from 'server/routes/chapter'; import nextjs from 'server/lib/next'; import { initDB } from 'server/db'; diff --git a/server/routers/chapter.ts b/server/routes/chapter.ts similarity index 100% rename from server/routers/chapter.ts rename to server/routes/chapter.ts diff --git a/server/routers/exampleRoutes/exampleRouter.ts b/server/routes/exampleRoutes/exampleRouter.ts similarity index 100% rename from server/routers/exampleRoutes/exampleRouter.ts rename to server/routes/exampleRoutes/exampleRouter.ts diff --git a/server/routers/exampleRoutes/routes/sampleAsyncRoute.ts b/server/routes/exampleRoutes/routes/sampleAsyncRoute.ts similarity index 100% rename from server/routers/exampleRoutes/routes/sampleAsyncRoute.ts rename to server/routes/exampleRoutes/routes/sampleAsyncRoute.ts diff --git a/server/routers/exampleRoutes/routes/sampleErroredRoute.ts b/server/routes/exampleRoutes/routes/sampleErroredRoute.ts similarity index 100% rename from server/routers/exampleRoutes/routes/sampleErroredRoute.ts rename to server/routes/exampleRoutes/routes/sampleErroredRoute.ts diff --git a/server/routers/exampleRoutes/routes/sampleRoute.ts b/server/routes/exampleRoutes/routes/sampleRoute.ts similarity index 100% rename from server/routers/exampleRoutes/routes/sampleRoute.ts rename to server/routes/exampleRoutes/routes/sampleRoute.ts From c1c9ecf47c3e7a57cf5a838345406dc1aa6d1ebe Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Fri, 6 Dec 2019 13:01:25 +0100 Subject: [PATCH 10/11] Extract id and date columns into BaseModel to keep models DRY --- server/docs/README.md | 2 ++ server/models/BaseModel.ts | 17 +++++++++++++++++ server/models/Chapter.ts | 21 +++------------------ 3 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 server/models/BaseModel.ts diff --git a/server/docs/README.md b/server/docs/README.md index dca55e04ac..6329c016f2 100644 --- a/server/docs/README.md +++ b/server/docs/README.md @@ -14,6 +14,8 @@ To make it since the port from docker postgres service is exposed to the host (5 This would create `ModelName.ts` in `server/models` +To keep everything DRY, add `extends BaseModel` to the class and import it from 'server/models/BaseModel' to no repeat id, createdAt, and updatedAt fields on every single model + You could also run `npx typeorm` since here you're not actually loading any ts files, but because regular `npx typeorm` runs inside of node it import from `.ts` files, so we run it with `ts-node` and our custom server config (check package.json) ### Create a migration diff --git a/server/models/BaseModel.ts b/server/models/BaseModel.ts new file mode 100644 index 0000000000..e9251dc239 --- /dev/null +++ b/server/models/BaseModel.ts @@ -0,0 +1,17 @@ +import { + PrimaryGeneratedColumn, + BaseEntity, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +export class BaseModel extends BaseEntity { + @PrimaryGeneratedColumn() + id: number; + + @CreateDateColumn({ type: 'timestamp' }) + created_at!: Date; + + @UpdateDateColumn({ type: 'timestamp' }) + updated_at!: Date; +} diff --git a/server/models/Chapter.ts b/server/models/Chapter.ts index 1081a0c0d0..476490eaaa 100644 --- a/server/models/Chapter.ts +++ b/server/models/Chapter.ts @@ -1,17 +1,8 @@ -import { - PrimaryGeneratedColumn, - BaseEntity, - CreateDateColumn, - UpdateDateColumn, - Column, - Entity, -} from 'typeorm'; +import { Column, Entity } from 'typeorm'; +import { BaseModel } from './BaseModel'; @Entity({ name: 'chapters' }) -export class Chapter extends BaseEntity { - @PrimaryGeneratedColumn() - id: number; - +export class Chapter extends BaseModel { @Column({ nullable: false }) name!: string; @@ -24,12 +15,6 @@ export class Chapter extends BaseEntity { @Column({ type: 'json' }) details!: any; - @CreateDateColumn({ type: 'timestamp' }) - created_at!: Date; - - @UpdateDateColumn({ type: 'timestamp' }) - updated_at!: Date; - constructor(params: { name: string; description: string; From 6ede7f7f5be8a0bf539585b4a8a60269a9a3971c Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Fri, 6 Dec 2019 19:34:19 +0100 Subject: [PATCH 11/11] Fix borked README.md --- README.md | 67 ++++++++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 0a819f4b2a..e035a5243f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Welcome to Chapter +[![All Contributors](https://img.shields.io/badge/all_contributors-40-orange.svg?style=flat-square)](#contributors) After several years of being dissatisfied with existing group event tools (Meetup, Facebook events) we decided to build our own. @@ -8,33 +9,33 @@ Your organization can host an instance of _Chapter_ under a sub-domain of your w You can use your own authentication tools. And all your user data will stay on your own server. -Our [Vision statement](https://github.com/freeCodeCamp/chapter/wiki/Vision) provides more details on the reasons for _Chapter_. +Our [Vision statement](https://github.com/freeCodeCamp/chapter/wiki/Vision) provides more details on the reasons for _Chapter_. ## Terminology - To better communicate and more easily build an API and UI, the current contributors have decided on a collection of terminology to clarify discussions surrounding the Chapter project: -| Term | Definition | Example | -| ------------ | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | -| instance | a web server deployment of this _Chapter_ application, managed by an organization. | none | -| organization | a non-profit with multiple chapters | Women Who Code at the sub-domain: `chapter.womenwhocode.org` | -| chapter | a container for events, with a description and subscribers, and one or more admins who can manage it | Women Who Code New York City | -| event | a single meetup that users can RSVP to, has a specific location and time, and has organizers | Coffee And Code - BistroOne, New York City, NY - April 9, 2020 | -| user | a person who has signed up and been authorized as a subscriber to a chapter | Sally Gold - SallyG@example.com | +| Term | Definition | Example | +| ------------- | ------------- | ----- | +| instance | a web server deployment of this _Chapter_ application, managed by an organization. | none | +| organization | a non-profit with multiple chapters | Women Who Code at the sub-domain: `chapter.womenwhocode.org` | +| chapter | a container for events, with a description and subscribers, and one or more admins who can manage it | Women Who Code New York City | +| event | a single meetup that users can RSVP to, has a specific location and time, and has organizers | Coffee And Code - BistroOne, New York City, NY - April 9, 2020 | +| user | a person who has signed up and been authorized as a subscriber to a chapter | Sally Gold - SallyG@example.com | ## Tech Stack We are planning to use the following tools: -- [Node.js](https://nodejs.org) / [Express](https://expressjs.com) for our backend using JavaScript/TypeScript -- [Postgres](https://www.postgresql.org) with [TypeORM](https://typeorm.io/#/) -- [Next.js](https://nextjs.org/) for both client and server-side rendering of the frontend (NextJS is based on [React](https://reactjs.org)) - - [JavaScript/TypeScript](https://www.typescriptlang.org/index.html#download-links) - - [Styled Components](https://www.styled-components.com) for styling. - - Functional Components with [Hooks](https://reactjs.org/docs/hooks-intro.html) -- [chai](https://www.chaijs.com/) for writing unit tests. - - [sinon](https://sinonjs.org/) - - [sinon-chai](https://github.com/domenic/sinon-chai) +* [Node.js](https://nodejs.org) / [Express](https://expressjs.com) for our backend using JavaScript/TypeScript +* [Postgres](https://www.postgresql.org) with [TypeORM](https://typeorm.io/#/) +* [Next.js](https://nextjs.org/) for both client and server-side rendering of the frontend (NextJS is based on [React](https://reactjs.org)) + * [JavaScript/TypeScript](https://www.typescriptlang.org/index.html#download-links) + * [Styled Components](https://www.styled-components.com) for styling. + * Functional Components with [Hooks](https://reactjs.org/docs/hooks-intro.html) +* [chai](https://www.chaijs.com/) for writing unit tests. + * [sinon](https://sinonjs.org/) + * [sinon-chai](https://github.com/domenic/sinon-chai) + A lot of people know these tools, and they're proven to work well at scale. @@ -52,10 +53,9 @@ Ensure you are installing Node 10 or greater and npm 6 or greater. ### Installing Docker -Click [here](https://docs.docker.com/v17.12/install/) for the Docker installation site. Scroll down to "Supported Platforms" and follow the instructions to download & install Docker Desktop for your operating system (or Docker CE for linux). +See the [Docker installation "Supported platforms"](https://docs.docker.com/install/#supported-platforms) section and follow the instructions to download & install Docker Desktop for your operating system (or Docker CE for Linux). You can find more resources on Docker here: - - [Docker: What and Why](https://stackoverflow.com/questions/28089344/docker-what-is-it-and-what-is-the-purpose) - [Docker Lessons on KataCoda](https://www.katacoda.com/learn?q=docker) - [Play with Docker Classroom](https://training.play-with-docker.com/) @@ -65,19 +65,16 @@ You can find more resources on Docker here: Open up Terminal/Powershell/bash and navigate to the directory where you want the project to live. Clone this repository: - ``` git clone https://github.com/freeCodeCamp/chapter ``` Navigate to the newly cloned repo: - ``` cd chapter ``` Install dependencies: - ``` npm install ``` @@ -86,7 +83,6 @@ Setup Environment Variables: Copy and paste env.sample into your .env file Ensure that Docker Desktop is up and running, then run the following command: - ``` docker-compose up ``` @@ -97,16 +93,15 @@ The server will automatically restart anytime you save a `.ts` or `.js` file wit You can run any command within the container by prefixing it with `docker-compose exec app`, e.g. `docker-compose exec app npm install express` -## Testing +## Additional DB docs can be found in server/docs/README.md +## Testing Run tests - ``` npm run test ``` Run tests in watch mode - ``` npm run test:watch ``` @@ -118,38 +113,34 @@ We use [Open API 3.0](https://www.openapis.org/about) to define the API structur ```bash npm run speccy ``` - Navigate to http://localhost:8001 to see API docs ## Schema -
Expand to view a diagram illustrating the proposed schema for Chapter.
![a diagram illustrating the proposed schema for Chapter](data/schema.png) - > created with [DBeaver.io](https://dbeaver.com/docs/wiki/ER-Diagrams/) -
-## User stories so far +## User Stories -Our goal is to keep things simple and not reinvent wheels. So far we have only two user roles: participants and chapter organizers, both of which are users. +### MVP +The [MVP user stories are shown in the MVP Project](https://github.com/freeCodeCamp/chapter/projects/1) kanban / cards and as [issues marked with "MVP"](https://github.com/freeCodeCamp/chapter/labels/MVP). ### Post-MVP - We are maintaining a list of post-MVP conversations and user stories using the ["Roadmap" tag](https://github.com/freeCodeCamp/chapter/issues?utf8=%E2%9C%93&q=is%3Aopen+or+is%3Aclosed+label%3ARoadmap+). -Quincy Larson is the project lead. [FreeCodeCamp](https://www.freecodecamp.org) will start "dogfooding" this as soon as possible with several of its local study groups. +Quincy Larson is the project lead. [FreeCodeCamp](https://www.freecodecamp.org) will start "dogfooding" the MVP with several of its local study groups. Here's an out-dated example of an app with similar functionality: [The freeCodeCamp Study Group Directory](https://study-group-directory.freecodecamp.org). -You should [join our Discord server](https://discord.gg/vbRUYWS) to get connected with people interested in this project and to be aware of our future announcements. ## Contributing -[**Take part in discussions or contribute code to this opensource codebase.**](CONTRIBUTING.md) +* You should [join our Discord server](https://discord.gg/PXqYtEh) to get connected with people interested in this project and to be aware of our future announcements. +* Please read the [**suggested steps to contribute code to the Chapter project**](CONTRIBUTING.md) before creating issues, forking, or submitting any pull requests. ## License @@ -222,7 +213,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +