├── flask-api
├── __init__.py
├── .gitignore
├── Procfile
├── swaggerui
│ ├── images
│ │ ├── expand.gif
│ │ ├── collapse.gif
│ │ ├── favicon.ico
│ │ ├── throbber.gif
│ │ ├── logo_small.png
│ │ ├── wordnik_api.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── pet_store_api.png
│ │ └── explorer_icons.png
│ ├── fonts
│ │ ├── DroidSans.ttf
│ │ └── DroidSans-Bold.ttf
│ ├── lib
│ │ ├── jquery.slideto.min.js
│ │ ├── jquery.wiggle.min.js
│ │ ├── object-assign-pollyfill.js
│ │ └── highlight.9.1.0.pack_extended.js
│ ├── css
│ │ ├── typography.css
│ │ └── reset.css
│ ├── o2c.html
│ └── lang
│ │ ├── translator.js
│ │ ├── zh-cn.js
│ │ ├── ko-kr.js
│ │ ├── ja.js
│ │ ├── tr.js
│ │ ├── pl.js
│ │ ├── pt.js
│ │ ├── en.js
│ │ ├── ru.js
│ │ ├── ca.js
│ │ ├── geo.js
│ │ ├── it.js
│ │ ├── es.js
│ │ └── fr.js
├── .env
└── requirements.txt
├── api
├── .nvmrc
├── Procfile
├── swaggerui
│ ├── images
│ │ ├── expand.gif
│ │ ├── favicon.ico
│ │ ├── collapse.gif
│ │ ├── throbber.gif
│ │ ├── logo_small.png
│ │ ├── wordnik_api.png
│ │ ├── explorer_icons.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ └── pet_store_api.png
│ ├── fonts
│ │ ├── DroidSans.ttf
│ │ └── DroidSans-Bold.ttf
│ ├── lib
│ │ ├── jquery.slideto.min.js
│ │ ├── jquery.wiggle.min.js
│ │ ├── object-assign-pollyfill.js
│ │ └── highlight.9.1.0.pack_extended.js
│ ├── css
│ │ ├── typography.css
│ │ └── reset.css
│ ├── o2c.html
│ └── lang
│ │ ├── translator.js
│ │ ├── zh-cn.js
│ │ ├── ko-kr.js
│ │ ├── ja.js
│ │ ├── tr.js
│ │ ├── pl.js
│ │ ├── pt.js
│ │ ├── en.js
│ │ ├── ru.js
│ │ ├── ca.js
│ │ ├── geo.js
│ │ ├── it.js
│ │ ├── es.js
│ │ └── fr.js
├── views
│ ├── img
│ │ └── neo4j-swagger.jpg
│ ├── layout.jade
│ ├── users.jade
│ ├── index.jade
│ └── user.jade
├── routes
│ ├── site.js
│ ├── index.js
│ ├── genres.js
│ └── people.js
├── .env
├── middlewares
│ ├── neo4jSessionCleanup.js
│ ├── loginRequired.js
│ └── setAuthUser.js
├── models
│ ├── neo4j
│ │ ├── person.js
│ │ ├── genre.js
│ │ ├── user.js
│ │ └── movie.js
│ ├── genres.js
│ ├── users.js
│ └── people.js
├── helpers
│ └── response.js
├── config.js
├── neo4j
│ └── dbUtils.js
├── LICENSE
└── package.json
├── web
├── .nvmrc
├── src
│ ├── styles
│ │ ├── _variables.scss
│ │ ├── components
│ │ │ ├── _breadcrumbs.scss
│ │ │ ├── _footer.scss
│ │ │ ├── _notificationContainer.scss
│ │ │ ├── _buttonLink.scss
│ │ │ ├── _userRating.scss
│ │ │ ├── _validation.scss
│ │ │ ├── _header.scss
│ │ │ ├── _loading.scss
│ │ │ └── _carousel.scss
│ │ ├── views
│ │ │ ├── _profile.scss
│ │ │ ├── _person.scss
│ │ │ ├── _movie.scss
│ │ │ └── _home.scss
│ │ ├── foundation
│ │ │ ├── scss
│ │ │ │ ├── foundation
│ │ │ │ │ └── components
│ │ │ │ │ │ ├── _magellan.scss
│ │ │ │ │ │ ├── _flex-video.scss
│ │ │ │ │ │ ├── _inline-lists.scss
│ │ │ │ │ │ ├── _thumbs.scss
│ │ │ │ │ │ ├── _keystrokes.scss
│ │ │ │ │ │ └── _progress-bars.scss
│ │ │ │ └── foundation.scss
│ │ │ ├── .bower.json
│ │ │ ├── LICENSE
│ │ │ └── README.md
│ │ └── main.scss
│ ├── assets
│ │ ├── logo.png
│ │ ├── favicon.ico
│ │ └── neo4j_background3.gif
│ ├── redux
│ │ ├── actions
│ │ │ ├── AuthActionTypes.js
│ │ │ ├── NotificationActionTypes.js
│ │ │ ├── AuthActions.js
│ │ │ ├── PersonActionTypes.js
│ │ │ ├── PersonActions.js
│ │ │ ├── NotificationActions.js
│ │ │ ├── MovieActionTypes.js
│ │ │ ├── ProfileActionTypes.js
│ │ │ ├── MovieActions.js
│ │ │ └── ProfileActions.js
│ │ ├── sagas
│ │ │ ├── index.js
│ │ │ ├── signupFlow.js
│ │ │ ├── authFlow.js
│ │ │ ├── personFlow.js
│ │ │ ├── errorFlow.js
│ │ │ ├── profileFlow.js
│ │ │ └── movieFlow.js
│ │ └── reducers
│ │ │ ├── notifications.js
│ │ │ ├── index.js
│ │ │ ├── genres.js
│ │ │ ├── signup.js
│ │ │ ├── auth.js
│ │ │ ├── person.js
│ │ │ ├── profile.js
│ │ │ └── movies.js
│ ├── config
│ │ ├── settings.example.js
│ │ └── settings.js
│ ├── utils
│ │ ├── ErrorUtils.js
│ │ └── ValidationUtils.js
│ ├── setupTests.js
│ ├── api
│ │ ├── PersonApi.js
│ │ ├── AuthApi.js
│ │ ├── ProfileApi.js
│ │ ├── axios.js
│ │ └── MoviesApi.js
│ ├── components
│ │ ├── Footer.jsx
│ │ ├── Loading.jsx
│ │ ├── Breadcrumbs.jsx
│ │ ├── common
│ │ │ ├── NotificationContainer.jsx
│ │ │ └── Notification.jsx
│ │ ├── UserRating.jsx
│ │ ├── Header.jsx
│ │ ├── Carousel.jsx
│ │ └── validation
│ │ │ └── ValidatedComponent.jsx
│ ├── UserSession.js
│ ├── pages
│ │ ├── index.hbs
│ │ ├── App.jsx
│ │ ├── AuthenticatedPage.jsx
│ │ ├── SignupStatus.jsx
│ │ └── Home.jsx
│ ├── routes
│ │ └── Routes.jsx
│ └── index.js
├── public
│ ├── robots.txt
│ ├── favicon.ico
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── index.html
├── .env
├── static.json
├── app.json
├── .gitignore
└── package.json
├── add_constraint_neo4j.sh
├── img
├── model.png
├── webUX.png
├── ratings_csv.png
├── verifyCloudAtlasMovie.png
└── neo4jBrowser_CypherCmd.png
├── adoc
└── img
│ ├── image02.png
│ ├── image00_model.png
│ ├── image07_login.png
│ ├── image04_homepage.png
│ ├── image02_user_graph.png
│ ├── image00_empty_profile.png
│ ├── image03_person_detail.png
│ ├── image07_movie_detail.png
│ ├── image01_api_directories.png
│ ├── image01_rating_example.png
│ ├── image03_create_account.png
│ ├── image04_my_rated_movie.png
│ ├── image05_web_directories.png
│ ├── image06_swagger_genres.png
│ ├── image05_example_rating_graph.png
│ └── image06_profile_with_ratings.png
├── Makefile
├── import_neo4j.sh
├── setup.cql
└── .gitignore
/flask-api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/api/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/erbium
2 |
--------------------------------------------------------------------------------
/api/Procfile:
--------------------------------------------------------------------------------
1 | web: node app.js
--------------------------------------------------------------------------------
/web/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/erbium
2 |
--------------------------------------------------------------------------------
/web/src/styles/_variables.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/flask-api/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 |
--------------------------------------------------------------------------------
/flask-api/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn app:app
2 |
--------------------------------------------------------------------------------
/add_constraint_neo4j.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | $NEO4J_HOME/bin/neo4j-shell < setup.cql
--------------------------------------------------------------------------------
/web/src/styles/components/_breadcrumbs.scss:
--------------------------------------------------------------------------------
1 | .breadcrumbs{
2 | width: 100%;
3 | }
--------------------------------------------------------------------------------
/img/model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/img/model.png
--------------------------------------------------------------------------------
/img/webUX.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/img/webUX.png
--------------------------------------------------------------------------------
/web/src/styles/components/_footer.scss:
--------------------------------------------------------------------------------
1 | .nt-app-footer {
2 | background: lightgrey;
3 | }
--------------------------------------------------------------------------------
/img/ratings_csv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/img/ratings_csv.png
--------------------------------------------------------------------------------
/web/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/adoc/img/image02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image02.png
--------------------------------------------------------------------------------
/web/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/web/public/favicon.ico
--------------------------------------------------------------------------------
/web/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/web/public/logo192.png
--------------------------------------------------------------------------------
/web/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/web/public/logo512.png
--------------------------------------------------------------------------------
/web/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/web/src/assets/logo.png
--------------------------------------------------------------------------------
/adoc/img/image00_model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image00_model.png
--------------------------------------------------------------------------------
/adoc/img/image07_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image07_login.png
--------------------------------------------------------------------------------
/web/src/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/web/src/assets/favicon.ico
--------------------------------------------------------------------------------
/adoc/img/image04_homepage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image04_homepage.png
--------------------------------------------------------------------------------
/img/verifyCloudAtlasMovie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/img/verifyCloudAtlasMovie.png
--------------------------------------------------------------------------------
/adoc/img/image02_user_graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image02_user_graph.png
--------------------------------------------------------------------------------
/api/swaggerui/images/expand.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/expand.gif
--------------------------------------------------------------------------------
/api/swaggerui/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/favicon.ico
--------------------------------------------------------------------------------
/api/views/img/neo4j-swagger.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/views/img/neo4j-swagger.jpg
--------------------------------------------------------------------------------
/img/neo4jBrowser_CypherCmd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/img/neo4jBrowser_CypherCmd.png
--------------------------------------------------------------------------------
/adoc/img/image00_empty_profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image00_empty_profile.png
--------------------------------------------------------------------------------
/adoc/img/image03_person_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image03_person_detail.png
--------------------------------------------------------------------------------
/adoc/img/image07_movie_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image07_movie_detail.png
--------------------------------------------------------------------------------
/api/routes/site.js:
--------------------------------------------------------------------------------
1 | /*
2 | * GET home page.
3 | */
4 |
5 | exports.index = function(req, res){
6 | res.render('index');
7 | };
--------------------------------------------------------------------------------
/api/swaggerui/fonts/DroidSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/fonts/DroidSans.ttf
--------------------------------------------------------------------------------
/api/swaggerui/images/collapse.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/collapse.gif
--------------------------------------------------------------------------------
/api/swaggerui/images/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/throbber.gif
--------------------------------------------------------------------------------
/adoc/img/image01_api_directories.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image01_api_directories.png
--------------------------------------------------------------------------------
/adoc/img/image01_rating_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image01_rating_example.png
--------------------------------------------------------------------------------
/adoc/img/image03_create_account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image03_create_account.png
--------------------------------------------------------------------------------
/adoc/img/image04_my_rated_movie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image04_my_rated_movie.png
--------------------------------------------------------------------------------
/adoc/img/image05_web_directories.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image05_web_directories.png
--------------------------------------------------------------------------------
/adoc/img/image06_swagger_genres.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image06_swagger_genres.png
--------------------------------------------------------------------------------
/api/swaggerui/images/logo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/logo_small.png
--------------------------------------------------------------------------------
/api/swaggerui/images/wordnik_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/wordnik_api.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/expand.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/expand.gif
--------------------------------------------------------------------------------
/web/src/assets/neo4j_background3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/web/src/assets/neo4j_background3.gif
--------------------------------------------------------------------------------
/api/swaggerui/fonts/DroidSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/fonts/DroidSans-Bold.ttf
--------------------------------------------------------------------------------
/api/swaggerui/images/explorer_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/explorer_icons.png
--------------------------------------------------------------------------------
/api/swaggerui/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/favicon-16x16.png
--------------------------------------------------------------------------------
/api/swaggerui/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/favicon-32x32.png
--------------------------------------------------------------------------------
/api/swaggerui/images/pet_store_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/api/swaggerui/images/pet_store_api.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/fonts/DroidSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/fonts/DroidSans.ttf
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/collapse.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/collapse.gif
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/favicon.ico
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/throbber.gif
--------------------------------------------------------------------------------
/adoc/img/image05_example_rating_graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image05_example_rating_graph.png
--------------------------------------------------------------------------------
/adoc/img/image06_profile_with_ratings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/adoc/img/image06_profile_with_ratings.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/logo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/logo_small.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/wordnik_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/wordnik_api.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/fonts/DroidSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/fonts/DroidSans-Bold.ttf
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/favicon-16x16.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/favicon-32x32.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/pet_store_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/pet_store_api.png
--------------------------------------------------------------------------------
/flask-api/swaggerui/images/explorer_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MiyamotoSatoshi/react-python/HEAD/flask-api/swaggerui/images/explorer_icons.png
--------------------------------------------------------------------------------
/web/.env:
--------------------------------------------------------------------------------
1 | # Express: http://localhost:3000/api/v0
2 | # Flask: http://localhost:5000/api/v0
3 |
4 | REACT_APP_API_BASE_URL=http://localhost:5000/api/v0
5 |
--------------------------------------------------------------------------------
/flask-api/.env:
--------------------------------------------------------------------------------
1 | SECRET_KEY="super secret guy"
2 | MOVIE_DATABASE_USERNAME="neo4j"
3 | MOVIE_DATABASE_PASSWORD="pan-track-orders"
4 | MOVIE_DATABASE_URL="bolt://localhost"
5 |
--------------------------------------------------------------------------------
/api/.env:
--------------------------------------------------------------------------------
1 | SECRET_KEY="super secret guy"
2 | MOVIE_DATABASE_USERNAME="neo4j"
3 | MOVIE_DATABASE_PASSWORD="height-restrictions-calculators"
4 | MOVIE_DATABASE_URL="bolt://52.91.202.103:32814"
5 |
--------------------------------------------------------------------------------
/web/src/redux/actions/AuthActionTypes.js:
--------------------------------------------------------------------------------
1 | export const LOGIN = 'LOGIN';
2 | export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
3 | export const LOGIN_FAILURE = 'LOGIN_FAILURE';
4 | export const LOGOUT = 'LOGOUT';
5 |
--------------------------------------------------------------------------------
/web/src/config/settings.example.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // Express: http://localhost:3000/api/v0
3 | // Flask: http://localhost:5000/api/v0
4 |
5 | module.exports = {
6 | apiBaseURL: process.env.REACT_APP_API_BASE_URL
7 | };
8 |
--------------------------------------------------------------------------------
/web/src/styles/views/_profile.scss:
--------------------------------------------------------------------------------
1 | .nt-profile {
2 | .nt-box {
3 | margin: .5rem 0;
4 | }
5 |
6 | &-movie {
7 | padding-top: 1rem;
8 |
9 | &-title {
10 | font-size: .8rem;
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/flask-api/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==1.1.2
2 | blinker==1.4
3 | Flask-RESTful==0.3.8
4 | Flask-Cors==3.0.9
5 | flask-restful-swagger-2==0.35
6 | Flask-JSON==0.3.4
7 | neo4j==4.1.1
8 | gunicorn==19.10.0
9 | python-dotenv==0.14.0
10 |
--------------------------------------------------------------------------------
/web/src/config/settings.js:
--------------------------------------------------------------------------------
1 | // Express: http://localhost:3000/api/v0
2 | // Flask: http://localhost:5000/api/v0
3 |
4 | module.exports = {
5 | apiBaseURL: process.env.REACT_APP_API_BASE_URL || "http://localhost:5000/api/v0"
6 | };
7 |
--------------------------------------------------------------------------------
/web/src/utils/ErrorUtils.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import humps from 'humps';
3 |
4 | export default class ErrorUtils {
5 | static getApiErrors(apiError) {
6 | return humps.camelizeKeys(_.get(apiError, 'data', {}));
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/web/static.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": "build/",
3 | "routes": {
4 | "/**": "index.html"
5 | },
6 | "proxies": {
7 | "/api/v0": {
8 | "origin": "${REACT_APP_PROXY_URL}"
9 | }
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/api/routes/index.js:
--------------------------------------------------------------------------------
1 | // convenience wrapper around all other files:
2 | exports.users = require('./users');
3 | exports.site = require('./site');
4 | exports.people = require('./people');
5 | exports.movies = require('./movies');
6 | exports.genres = require('./genres');
--------------------------------------------------------------------------------
/api/middlewares/neo4jSessionCleanup.js:
--------------------------------------------------------------------------------
1 | module.exports = function neo4jSessionCleanup(req, res, next) {
2 | res.on('finish', function () {
3 | if(req.neo4jSession) {
4 | req.neo4jSession.close();
5 | delete req.neo4jSession;
6 | }
7 | });
8 | next();
9 | };
--------------------------------------------------------------------------------
/web/src/styles/components/_notificationContainer.scss:
--------------------------------------------------------------------------------
1 | .notification-container{
2 | position: fixed;
3 | right: 8em;
4 | top:2em;
5 | width: 15em;
6 | text-align: center;
7 | z-index: 999999999;
8 |
9 | .alert-box {
10 | opacity: 0.75;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/web/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/api/models/neo4j/person.js:
--------------------------------------------------------------------------------
1 | // extracts just the data from the query results
2 |
3 | const _ = require('lodash');
4 |
5 | const Person = module.exports = function (_node) {
6 | _.extend(this, _node.properties);
7 | this.id = this.tmdbId;
8 | this.poster_image = this.poster;
9 | };
10 |
--------------------------------------------------------------------------------
/web/src/api/PersonApi.js:
--------------------------------------------------------------------------------
1 | import settings from '../config/settings';
2 | import axios from './axios';
3 |
4 | const {apiBaseURL} = settings;
5 |
6 | export default class PersonApi {
7 | static getPerson(id) {
8 | return axios.get(`${apiBaseURL}/people/${id}`);
9 | }
10 | }
11 |
12 |
13 |
--------------------------------------------------------------------------------
/web/src/styles/components/_buttonLink.scss:
--------------------------------------------------------------------------------
1 | .buttonLink {
2 | background-color: transparent;
3 | border: none;
4 | padding: 0;
5 | margin: 0;
6 | display: inline;
7 | cursor: pointer;
8 | color: #008CBA;
9 |
10 | &:hover {
11 | color: #0078a0;
12 | background-color: inherit;
13 | }
14 | }
--------------------------------------------------------------------------------
/web/src/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Footer extends React.Component {
4 | render() {
5 | return (
6 |
9 | );
10 | }
11 | }
12 |
13 | Footer.displayName = 'Footer';
14 |
--------------------------------------------------------------------------------
/web/src/styles/views/_person.scss:
--------------------------------------------------------------------------------
1 | .nt-person {
2 | .nt-box {
3 | margin-bottom: 1rem;
4 | }
5 |
6 | &-poster {
7 | width: 100%;
8 | }
9 |
10 | &-header {
11 | text-align: center;
12 | }
13 |
14 | &-movies {
15 |
16 | &-movie-role {
17 | font-style: italic;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/web/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "NT Movie APP",
3 | "env": {
4 | "API_URL": {
5 | "description": "URL of the API endpoint",
6 | "required": true
7 | }
8 | },
9 | "buildpacks": [
10 | {
11 | "url": "mars/create-react-app"
12 | }
13 | ]
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/web/src/styles/components/_userRating.scss:
--------------------------------------------------------------------------------
1 | .nt-user-rating {
2 | &-star {
3 | font-size: 1.5rem;
4 | line-height: 1.5rem;
5 | float: left;
6 | }
7 |
8 | &-delete {
9 | float: left;
10 | font-size: .8rem;
11 | line-height: 1.5rem;
12 | padding-left: .5rem;
13 | text-decoration: underline;
14 | }
15 | }
--------------------------------------------------------------------------------
/api/models/neo4j/genre.js:
--------------------------------------------------------------------------------
1 | // extracts just the data from the query results
2 |
3 | const _ = require('lodash');
4 |
5 | const Genre = module.exports = function (_node) {
6 | _.extend(this, _node.properties);
7 | if (this.id) {
8 | this.id = this.id.toNumber();
9 | } else {
10 | this.id = _node.identity.low;
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/api/middlewares/loginRequired.js:
--------------------------------------------------------------------------------
1 | var writeError = require('../helpers/response').writeResponse;
2 |
3 | module.exports = function loginRequired(req, res, next) {
4 | var authHeader = req.headers['authorization'];
5 | if (!authHeader) {
6 | return writeError(res, {detail: 'no authorization provided'}, 401);
7 | }
8 | next();
9 | };
10 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | deploy-api:
2 | git branch -f heroku-api
3 | git branch -D heroku-api
4 | git subtree split --prefix flask-api -b heroku-api
5 | git push heroku-api heroku-api:master --force
6 |
7 | deploy-web:
8 | git branch -f heroku-web
9 | git branch -D heroku-web
10 | git subtree split --prefix web -b heroku-web
11 | git push heroku-web heroku-web:master --force
12 |
--------------------------------------------------------------------------------
/web/src/UserSession.js:
--------------------------------------------------------------------------------
1 | class UserSession {
2 | static setToken(token) {
3 | if (token) {
4 | window.localStorage.setItem('token', token);
5 | } else {
6 | window.localStorage.removeItem('token');
7 | }
8 | }
9 |
10 | static getToken() {
11 | return window.localStorage.getItem('token');
12 | }
13 | }
14 |
15 | export default UserSession;
16 |
--------------------------------------------------------------------------------
/web/src/redux/actions/NotificationActionTypes.js:
--------------------------------------------------------------------------------
1 | export const NotificationActionTypes = {
2 | CREATE_NOTIFICATION: 'CREATE_NOTIFICATION',
3 | DISMISS_NOTIFICATION: 'DISMISS_NOTIFICATION'
4 | };
5 |
6 | export const NotificationType = {
7 | error: 'alert round',
8 | success: 'success round',
9 | information: 'info',
10 | warning: 'warning',
11 | secondary: 'secondary'
12 | };
13 |
--------------------------------------------------------------------------------
/api/swaggerui/lib/jquery.slideto.min.js:
--------------------------------------------------------------------------------
1 | (function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery);
2 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lib/jquery.slideto.min.js:
--------------------------------------------------------------------------------
1 | (function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery);
2 |
--------------------------------------------------------------------------------
/web/src/components/Loading.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Loading extends React.Component {
4 |
5 | render() {
6 | return (
7 |
11 | );
12 | }
13 |
14 | }
15 |
16 | Loading.displayName = 'Loading';
17 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/web/src/styles/views/_movie.scss:
--------------------------------------------------------------------------------
1 | .nt-movie {
2 |
3 | .nt-box {
4 | margin-bottom: 1rem;
5 | }
6 |
7 | &-title {
8 | text-align: center;
9 | }
10 |
11 | &-rating {
12 | overflow: hidden;
13 |
14 | strong {
15 | float: left;
16 | }
17 | }
18 |
19 | &-poster {
20 | width: 100%;
21 | }
22 |
23 | &-aside {
24 | .nt-box {
25 | margin-top: 1rem;
26 | }
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/api/models/genres.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 | const Genre = require('../models/neo4j/genre');
3 |
4 | const getAll = function(session) {
5 | return session.readTransaction(txc =>
6 | txc.run('MATCH (genre:Genre) RETURN genre')
7 | ).then(_manyGenres);
8 | };
9 |
10 | const _manyGenres = function (result) {
11 | return result.records.map(r => new Genre(r.get('genre')));
12 | };
13 |
14 | module.exports = {
15 | getAll: getAll
16 | };
17 |
--------------------------------------------------------------------------------
/web/src/api/AuthApi.js:
--------------------------------------------------------------------------------
1 | import settings from '../config/settings';
2 | import axios from './axios';
3 |
4 | const {apiBaseURL} = settings;
5 |
6 | export default class AuthApi {
7 | static login(username, password) {
8 | return axios.post(`${apiBaseURL}/login`,
9 | {
10 | username, password
11 | }
12 | );
13 | }
14 |
15 | static register(profile) {
16 | return axios.post(`${apiBaseURL}/register`, profile);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/redux/actions/AuthActions.js:
--------------------------------------------------------------------------------
1 | import * as Types from './AuthActionTypes';
2 |
3 | export function login(username, password) {
4 | return {type: Types.LOGIN, username, password};
5 | }
6 |
7 | export function loginSuccess(token) {
8 | return {type: Types.LOGIN_SUCCESS, token};
9 | }
10 |
11 | export function loginFailure(error) {
12 | return {type: Types.LOGIN_FAILURE, error};
13 | }
14 |
15 | export function logout() {
16 | return {type: Types.LOGOUT};
17 | }
18 |
--------------------------------------------------------------------------------
/api/models/neo4j/user.js:
--------------------------------------------------------------------------------
1 | // extracts just the data from the query results
2 |
3 | const _ = require('lodash');
4 | const md5 = require('md5');
5 |
6 | const User = module.exports = function (_node) {
7 | const username = _node.properties['username'];
8 |
9 | _.extend(this, {
10 | 'id': _node.properties['id'],
11 | 'username': username,
12 | 'avatar': {
13 | 'full_size': 'https://www.gravatar.com/avatar/' + md5(username) + '?d=retro'
14 | }
15 | });
16 | };
--------------------------------------------------------------------------------
/api/helpers/response.js:
--------------------------------------------------------------------------------
1 | // var sw = require("swagger-node-express");
2 | var _ = require("lodash");
3 |
4 | exports.writeResponse = function writeResponse(res, response, status) {
5 | // sw.setHeaders(res);
6 | res.status(status || 200).send(JSON.stringify(response));
7 | };
8 |
9 | exports.writeError = function writeError(res, error, status) {
10 | // sw.setHeaders(res);
11 | res
12 | .status(error.status || status || 400)
13 | .send(JSON.stringify(_.omit(error, ["status"])));
14 | };
15 |
16 |
--------------------------------------------------------------------------------
/web/src/api/ProfileApi.js:
--------------------------------------------------------------------------------
1 | import settings from '../config/settings';
2 | import axios from './axios';
3 |
4 | const {apiBaseURL} = settings;
5 |
6 | export default class ProfileApi {
7 |
8 | static getProfile() {
9 | return axios.get(`${apiBaseURL}/users/me`);
10 | }
11 |
12 | static getProfileRatings() {
13 | return axios.get(`${apiBaseURL}/movies/rated`);
14 | }
15 |
16 | static getProfileRecommendations() {
17 | return axios.get(`${apiBaseURL}/movies/recommended`);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/api/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype 5
2 | html
3 | head
4 | title= title
5 | link(rel='stylesheet', href='/stylesheets/style.css')
6 | body
7 | block content
8 |
9 | // GitHub ribbon! via https://github.com/blog/273-github-ribbons
10 | a(href='https://github.com/aseemk/node-neo4j-template')
11 | img(
12 | style='position: absolute; top: 0; right: 0; border: 0;'
13 | src='https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png'
14 | alt='Fork me on GitHub'
15 | )
--------------------------------------------------------------------------------
/web/src/redux/actions/PersonActionTypes.js:
--------------------------------------------------------------------------------
1 | export const PERSON_DETAIL_CLEAR = 'PERSON_DETAIL_CLEAR';
2 | export const PERSON_DETAIL_GET_REQUEST = 'PERSON_DETAIL_GET_REQUEST';
3 | export const PERSON_DETAIL_GET_SUCCESS = 'PERSON_DETAIL_GET_SUCCESS';
4 | export const PERSON_DETAIL_GET_FAILURE = 'PERSON_DETAIL_GET_FAILURE';
5 | export const PERSON_RELATED_GET_REQUEST = 'PERSON_RELATED_GET_REQUEST';
6 | export const PERSON_RELATED_GET_SUCCESS = 'PERSON_RELATED_GET_SUCCESS';
7 | export const PERSON_RELATED_GET_FAILURE = 'PERSON_RELATED_GET_FAILURE';
--------------------------------------------------------------------------------
/api/swaggerui/css/typography.css:
--------------------------------------------------------------------------------
1 | /* Google Font's Droid Sans */
2 | @font-face {
3 | font-family: 'Droid Sans';
4 | font-style: normal;
5 | font-weight: 400;
6 | src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf'), format('truetype');
7 | }
8 | /* Google Font's Droid Sans Bold */
9 | @font-face {
10 | font-family: 'Droid Sans';
11 | font-style: normal;
12 | font-weight: 700;
13 | src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf'), format('truetype');
14 | }
15 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/css/typography.css:
--------------------------------------------------------------------------------
1 | /* Google Font's Droid Sans */
2 | @font-face {
3 | font-family: 'Droid Sans';
4 | font-style: normal;
5 | font-weight: 400;
6 | src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf'), format('truetype');
7 | }
8 | /* Google Font's Droid Sans Bold */
9 | @font-face {
10 | font-family: 'Droid Sans';
11 | font-style: normal;
12 | font-weight: 700;
13 | src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf'), format('truetype');
14 | }
15 |
--------------------------------------------------------------------------------
/api/swaggerui/o2c.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/styles/components/_validation.scss:
--------------------------------------------------------------------------------
1 | .validation {
2 | input {
3 | margin-bottom: 0.1em;
4 | }
5 | }
6 |
7 | .validation-summary {
8 | padding: .8rem 0;
9 | }
10 |
11 | .validation-msg {
12 | color: #C70000;
13 | height: 1.2em;
14 | line-height: 1em;
15 | @extend .mark-validation-msg;
16 | }
17 |
18 | .mark-validation-msg {
19 | &::before {
20 | content: "\26a0";
21 | font-size: 1em;
22 | margin-right: 0.5em;
23 | }
24 |
25 | &:empty {
26 | &::before {
27 | content: "";
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/flask-api/swaggerui/o2c.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/api/views/users.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1 Users
5 |
6 | if users.length
7 | p Here are the current users:
8 | ul.users
9 | for user in users
10 | li.user
11 | a(href='/users/#{user.id}') #{user.name}
12 | else
13 | p There are no users currently.
14 |
15 | form(action='', method='POST')
16 | p Create a new user:
17 | input(type='text', name='name', placeholder='Name', required)
18 | input(type='submit', value='Create')
19 |
--------------------------------------------------------------------------------
/web/src/redux/sagas/index.js:
--------------------------------------------------------------------------------
1 | import {all, fork} from 'redux-saga/effects';
2 | import errorFlow from './errorFlow';
3 | import authFlow from './authFlow';
4 | import profileFlow from './profileFlow';
5 | import signupFlow from './signupFlow';
6 | import movieFlow from './movieFlow';
7 | import personFlow from './personFlow';
8 |
9 | export default function* root() {
10 | yield all([
11 | fork(errorFlow),
12 | fork(authFlow),
13 | fork(profileFlow),
14 | fork(signupFlow),
15 | fork(movieFlow),
16 | fork(personFlow)
17 | ]);
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/notifications.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import { NotificationActionTypes } from '../actions/NotificationActionTypes';
3 |
4 | export default function notifications(state = [], action) {
5 | switch (action.type) {
6 | case NotificationActionTypes.CREATE_NOTIFICATION:
7 | return [
8 | ...state,
9 | {...action.notification}
10 | ];
11 | case NotificationActionTypes.DISMISS_NOTIFICATION:
12 | return _.without(state, action.notification);
13 | default:
14 | return state;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/import_neo4j.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | $NEO4J_HOME/bin/neo4j-import --into $NEO4J_HOME/data/databases/graph.db --nodes:Person csv/person_node.csv --nodes:Movie csv/movie_node.csv --nodes:Genre csv/genre_node.csv --nodes:Keyword csv/keyword_node.csv --relationships:ACTED_IN csv/acted_in_rels.csv --relationships:DIRECTED csv/directed_rels.csv --relationships:HAS_GENRE csv/has_genre_rels.csv --relationships:HAS_KEYWORD csv/has_keyword_rels.csv --relationships:PRODUCED csv/produced_rels.csv --relationships:WRITER_OF csv/writer_of_rels.csv --delimiter ";" --array-delimiter "|" --id-type INTEGER
--------------------------------------------------------------------------------
/api/models/neo4j/movie.js:
--------------------------------------------------------------------------------
1 | // extracts just the data from the query results
2 |
3 | const _ = require('lodash');
4 |
5 | const Movie = module.exports = function (_node, myRating) {
6 | _.extend(this, _node.properties);
7 |
8 | this.id = this.tmdbId;
9 | this.poster_image = this.poster;
10 | this.tagline = this.plot;
11 |
12 | if (this.duration) {
13 | this.duration = this.duration.toNumber();
14 | } else if (this.runtime) {
15 | this.duration = this.runtime.low;
16 | }
17 |
18 | if(myRating || myRating === 0) {
19 | this['my_rating'] = myRating;
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/web/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/web/src/utils/ValidationUtils.js:
--------------------------------------------------------------------------------
1 | export default class ValidationUtils {
2 | static checkEmail(email, message) {
3 | var regex = /[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}/igm;
4 | if (email && !regex.test(email)) {
5 | return message || 'Please enter a valid email address.';
6 | }
7 | }
8 |
9 | static checkUrl(url, message) {
10 | var regex = /^(http)s?(:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/igm; // eslint-disable-line no-useless-escape
11 | if (url && !regex.test(url)) {
12 | return message || 'Please enter a valid URL. (ex. http(s)://domain.com)';
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from 'redux';
2 | import { connectRouter } from 'connected-react-router'
3 | import notifications from './notifications';
4 | import auth from './auth';
5 | import signup from './signup';
6 | import profile from './profile';
7 | import genres from './genres';
8 | import movies from './movies';
9 | import person from './person';
10 |
11 | const createRootReducer = (history) => combineReducers({
12 | router: connectRouter(history),
13 | notifications,
14 | auth,
15 | signup,
16 | profile,
17 | genres,
18 | movies,
19 | person
20 | });
21 |
22 | export default createRootReducer;
23 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/genres.js:
--------------------------------------------------------------------------------
1 | import { MOVIE_GENRES_GET_REQUEST, MOVIE_GENRES_GET_SUCCESS } from '../actions/MovieActionTypes';
2 |
3 | const initialState = {
4 | isFetching: false,
5 | items: []
6 | };
7 |
8 | export default function genres(state = initialState, action) {
9 | switch (action.type) {
10 | case MOVIE_GENRES_GET_REQUEST:
11 | return {
12 | ...state,
13 | isFetching: true
14 | };
15 | case MOVIE_GENRES_GET_SUCCESS:
16 | return {
17 | ...state,
18 | isFetching: false,
19 | items: action.genres
20 | };
21 | default:
22 | return state;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/web/src/styles/views/_home.scss:
--------------------------------------------------------------------------------
1 | .nt-home {
2 |
3 | &-header {
4 | text-align: center;
5 | }
6 |
7 | .nt-box {
8 | margin-bottom: 1rem;
9 | }
10 |
11 | &-featured {
12 | ul {
13 | list-style: none;
14 | display: -webkit-flex;
15 | display: flex;
16 | -webkit-justify-content: space-around;
17 | justify-content: space-around;
18 | li {
19 | padding: 1rem;
20 | }
21 | }
22 | }
23 |
24 | &-by-genre {
25 | ul {
26 | list-style: none;
27 | li {
28 | display: inline-block;
29 | width: auto;
30 | padding: .5rem;
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/api/views/index.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= title
5 |
6 | p
7 | | This is a template app showing the use of
8 | a(href='http://www.neo4j.org/', target='_blank') Neo4j
9 | | from Node.js. It uses the
10 | a(href='https://github.com/thingdom/node-neo4j', target='_blank') node-neo4j
11 | | library, available on npm as
12 | code neo4j
13 | .
14 |
15 | p.
16 | This app is a simple social network manager: it lets you add and remove
17 | users and "follows" relationships between them.
18 |
19 | p
20 | strong
21 | | Get started:
22 | a(href='/users') View all users
--------------------------------------------------------------------------------
/api/swaggerui/lib/jquery.wiggle.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | jQuery Wiggle
3 | Author: WonderGroup, Jordan Thomas
4 | URL: http://labs.wondergroup.com/demos/mini-ui/index.html
5 | License: MIT (http://en.wikipedia.org/wiki/MIT_License)
6 | */
7 | jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);}
8 | if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});};
--------------------------------------------------------------------------------
/api/middlewares/setAuthUser.js:
--------------------------------------------------------------------------------
1 | var writeError = require('../helpers/response').writeError;
2 | var Users = require('../models/users');
3 | var dbUtils = require('../neo4j/dbUtils');
4 |
5 | module.exports = function setAuthUser(req, res, next) {
6 | var authHeader = req.headers['authorization'];
7 | if (!authHeader) {
8 | req.user = {id: null};
9 | next();
10 | }
11 | else {
12 | var match = authHeader.match(/^Token (\S+)/);
13 | if (!match || !match[1]) {
14 | return writeError(res, {detail: 'invalid authorization format. Follow `Token `'}, 401);
15 | }
16 | var token = match[1];
17 |
18 | Users.me(dbUtils.getSession(req), token)
19 | .then(user => {
20 | req.user = user;
21 | next();
22 | })
23 | .catch(next);
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lib/jquery.wiggle.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | jQuery Wiggle
3 | Author: WonderGroup, Jordan Thomas
4 | URL: http://labs.wondergroup.com/demos/mini-ui/index.html
5 | License: MIT (http://en.wikipedia.org/wiki/MIT_License)
6 | */
7 | jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);}
8 | if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});};
--------------------------------------------------------------------------------
/api/swaggerui/lib/object-assign-pollyfill.js:
--------------------------------------------------------------------------------
1 | if (typeof Object.assign != 'function') {
2 | (function () {
3 | Object.assign = function (target) {
4 | 'use strict';
5 | if (target === undefined || target === null) {
6 | throw new TypeError('Cannot convert undefined or null to object');
7 | }
8 |
9 | var output = Object(target);
10 | for (var index = 1; index < arguments.length; index++) {
11 | var source = arguments[index];
12 | if (source !== undefined && source !== null) {
13 | for (var nextKey in source) {
14 | if (Object.prototype.hasOwnProperty.call(source, nextKey)) {
15 | output[nextKey] = source[nextKey];
16 | }
17 | }
18 | }
19 | }
20 | return output;
21 | };
22 | })();
23 | }
24 |
--------------------------------------------------------------------------------
/setup.cql:
--------------------------------------------------------------------------------
1 | // setup for movie template
2 |
3 | CREATE CONSTRAINT ON (n:Movie) ASSERT n.id IS UNIQUE;
4 |
5 | CREATE CONSTRAINT ON (n:Person) ASSERT n.id IS UNIQUE;
6 |
7 | CREATE CONSTRAINT ON (n:Keyword) ASSERT n.id IS UNIQUE;
8 |
9 | CREATE CONSTRAINT ON (n:User) ASSERT n.id IS UNIQUE;
10 |
11 | CREATE CONSTRAINT ON (n:User) ASSERT n.username IS UNIQUE;
12 |
13 | CREATE CONSTRAINT ON (n:Genre) ASSERT n.id IS UNIQUE;
14 |
15 | CREATE CONSTRAINT ON ()-[r:RATED]-() ASSERT exists(r.rating);
16 |
17 | // LOAD CSV WITH HEADERS FROM 'file:///ratings.csv' AS line
18 | // MATCH (m:Movie {id:toInt(line.movie_id)})
19 | // MERGE (u:User {id:line.user_id, username:line.user_username}) // user ids are strings
20 | // MERGE (u)-[r:RATED]->(m)
21 | // SET r.rating = toInt(line.rating)
22 | // RETURN m.title, r.rating, u.username;
23 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lib/object-assign-pollyfill.js:
--------------------------------------------------------------------------------
1 | if (typeof Object.assign != 'function') {
2 | (function () {
3 | Object.assign = function (target) {
4 | 'use strict';
5 | if (target === undefined || target === null) {
6 | throw new TypeError('Cannot convert undefined or null to object');
7 | }
8 |
9 | var output = Object(target);
10 | for (var index = 1; index < arguments.length; index++) {
11 | var source = arguments[index];
12 | if (source !== undefined && source !== null) {
13 | for (var nextKey in source) {
14 | if (Object.prototype.hasOwnProperty.call(source, nextKey)) {
15 | output[nextKey] = source[nextKey];
16 | }
17 | }
18 | }
19 | }
20 | return output;
21 | };
22 | })();
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/scss/foundation/components/_magellan.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | @import 'global';
6 |
7 | //
8 | // @variables
9 | //
10 | $include-html-magellan-classes: $include-html-classes !default;
11 |
12 | $magellan-bg: $white !default;
13 | $magellan-padding: 10px !default;
14 |
15 | @include exports("magellan") {
16 | @if $include-html-magellan-classes {
17 |
18 | #{data('magellan-expedition')}, #{data('magellan-expedition-clone')} {
19 | background: $magellan-bg;
20 | min-width: 100%;
21 | padding: $magellan-padding;
22 | z-index: 50;
23 |
24 | .sub-nav {
25 | margin-bottom: 0;
26 | dd { margin-bottom: 0; }
27 | a {
28 | line-height: 1.8em;
29 | }
30 | }
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/web/src/redux/actions/PersonActions.js:
--------------------------------------------------------------------------------
1 | import * as Types from './PersonActionTypes';
2 |
3 | export function clearPerson() {
4 | return {
5 | type: Types.PERSON_DETAIL_CLEAR
6 | };
7 | }
8 |
9 | export function getPerson(id) {
10 | return {type: Types.PERSON_DETAIL_GET_REQUEST, id};
11 | }
12 |
13 | export function getPersonSuccess(response) {
14 | return {type: Types.PERSON_DETAIL_GET_SUCCESS, response};
15 | }
16 |
17 | export function getPersonFailure(error) {
18 | return {type: Types.PERSON_DETAIL_GET_FAILURE, error};
19 | }
20 |
21 | export function getRelated(id) {
22 | return {type: Types.PERSON_RELATED_GET_REQUEST, id};
23 | }
24 |
25 | export function getRelatedSuccess(response) {
26 | return {type: Types.PERSON_RELATED_GET_SUCCESS, response};
27 | }
28 |
29 | export function getRelatedFailure(error) {
30 | return {type: Types.PERSON_RELATED_GET_FAILURE, error};
31 | }
32 |
--------------------------------------------------------------------------------
/web/src/pages/index.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Movie App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "foundation",
3 | "main": [
4 | "scss/foundation.scss",
5 | "js/foundation.js"
6 | ],
7 | "ignore": [],
8 | "dependencies": {
9 | "jquery": ">= 2.1.0",
10 | "modernizr": "2.8.3",
11 | "fastclick": ">=0.6.11",
12 | "jquery.cookie": "~1.4.0",
13 | "jquery-placeholder": "~2.0.7"
14 | },
15 | "devDependencies": {
16 | "jquery.autocomplete": "devbridge/jQuery-Autocomplete#1.2.9",
17 | "lodash": "~2.4.1"
18 | },
19 | "private": true,
20 | "homepage": "https://github.com/zurb/bower-foundation",
21 | "version": "5.5.3",
22 | "_release": "5.5.3",
23 | "_resolution": {
24 | "type": "version",
25 | "tag": "5.5.3",
26 | "commit": "b879716aa268e1f88fe43de98db2db4487af00ca"
27 | },
28 | "_source": "https://github.com/zurb/bower-foundation.git",
29 | "_target": "~5.5.3",
30 | "_originalSource": "foundation"
31 | }
--------------------------------------------------------------------------------
/web/src/redux/sagas/signupFlow.js:
--------------------------------------------------------------------------------
1 | import {all, call, put, takeEvery} from 'redux-saga/effects';
2 | import AuthApi from '../../api/AuthApi';
3 | import * as Actions from '../actions/ProfileActions';
4 | import * as Types from '../actions/ProfileActionTypes';
5 | import * as AuthActions from '../actions/AuthActions';
6 | import { push } from 'connected-react-router'
7 |
8 | export default function* signupFlow() {
9 | yield all([
10 | takeEvery(Types.PROFILE_CREATE, createProfile),
11 | ]);
12 | }
13 |
14 | function* createProfile(action) {
15 | var {payload} = action;
16 |
17 | try {
18 | const response = yield call(AuthApi.register, payload);
19 | yield put(Actions.createProfileSuccess(response));
20 | yield put(AuthActions.login(payload.username, payload.password));
21 | yield put(push('/signup-status'));
22 | }
23 | catch (error) {
24 | yield put(Actions.createProfileFailure(error));
25 | }
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/web/src/components/Breadcrumbs.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Link } from 'react-router-dom';
4 |
5 | export default class Breadcrumbs extends React.Component {
6 | render() {
7 | var {movie, person} = this.props;
8 |
9 | return (
10 |
11 | - Home
12 | {
13 | movie ?
14 | - {movie.title}
15 | : null
16 | }
17 | {
18 | person ?
19 | - {person.name}
20 | : null
21 | }
22 |
23 | );
24 | }
25 | }
26 |
27 | Breadcrumbs.displayName = 'Breadcrumbs';
28 | Breadcrumbs.propTypes = {
29 | movie: PropTypes.object,
30 | person: PropTypes.object
31 | };
32 |
--------------------------------------------------------------------------------
/api/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('dotenv').config();
4 |
5 | var nconf = require('nconf');
6 |
7 | nconf.env(['PORT', 'NODE_ENV'])
8 | .argv({
9 | 'e': {
10 | alias: 'NODE_ENV',
11 | describe: 'Set production or development mode.',
12 | demand: false,
13 | default: 'development'
14 | },
15 | 'p': {
16 | alias: 'PORT',
17 | describe: 'Port to run on.',
18 | demand: false,
19 | default: 3000
20 | },
21 | 'n': {
22 | alias: "neo4j",
23 | describe: "Use local or remote neo4j instance",
24 | demand: false,
25 | default: "local"
26 | }
27 | })
28 | .defaults({
29 | 'USERNAME': process.env.MOVIE_DATABASE_USERNAME,
30 | 'PASSWORD' : process.env.MOVIE_DATABASE_PASSWORD,
31 | 'neo4j': 'local',
32 | 'neo4j-local': process.env.MOVIE_DATABASE_URL || 'bolt://localhost:7687',
33 | 'base_url': 'http://localhost:3000',
34 | 'api_path': '/api/v0'
35 | });
36 |
37 | module.exports = nconf;
38 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/signup.js:
--------------------------------------------------------------------------------
1 | import * as Types from '../actions/ProfileActionTypes';
2 | import ErrorUtils from '../../utils/ErrorUtils';
3 |
4 | function getInitialState() {
5 | return {
6 | isSaving: false,
7 | savedProfile: null,
8 | errors: {}
9 | };
10 | }
11 |
12 | export default function createProfile(state = getInitialState(), action) {
13 | switch (action.type) {
14 | case Types.PROFILE_CREATE_INIT:
15 | return getInitialState();
16 | case Types.PROFILE_CREATE:
17 | return {
18 | ...state,
19 | isSaving: true
20 | };
21 | case Types.PROFILE_CREATE_SUCCESS:
22 | return {
23 | ...state,
24 | isSaving: false,
25 | savedProfile: action.payload
26 | };
27 | case Types.PROFILE_CREATE_FAILURE:
28 | return {
29 | isSaving: false,
30 | savedProfile: null,
31 | errors: ErrorUtils.getApiErrors(action.error)
32 | };
33 | default:
34 | return state;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/web/src/redux/sagas/authFlow.js:
--------------------------------------------------------------------------------
1 | import {all, call, put, takeEvery} from 'redux-saga/effects';
2 | import AuthApi from '../../api/AuthApi';
3 | import * as Actions from '../actions/AuthActions';
4 | import * as ProfileActions from '../actions/ProfileActions';
5 | import * as Types from '../actions/AuthActionTypes';
6 | import UserSession from '../../UserSession';
7 |
8 | export default function* authFlow() {
9 | yield all([
10 | takeEvery(Types.LOGIN, login),
11 | takeEvery(Types.LOGOUT, logout)
12 | ]);
13 | }
14 |
15 | function* login(action) {
16 | var {username, password} = action;
17 | try {
18 | const response = yield call(AuthApi.login, username, password);
19 | UserSession.setToken(response.token);
20 |
21 | yield put(Actions.loginSuccess(response.token));
22 | yield put(ProfileActions.getProfile());
23 | }
24 | catch (error) {
25 | yield put(Actions.loginFailure(error));
26 | }
27 | }
28 |
29 | function* logout() {
30 | yield UserSession.setToken(null);
31 | }
32 |
--------------------------------------------------------------------------------
/api/neo4j/dbUtils.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // neo4j cypher helper module
4 | const nconf = require('../config');
5 |
6 | const neo4j = require('neo4j-driver');
7 | const driver = neo4j.driver(nconf.get('neo4j-local'), neo4j.auth.basic(nconf.get('USERNAME'), nconf.get('PASSWORD')));
8 |
9 | exports.getSession = function (context) {
10 | if(context.neo4jSession) {
11 | return context.neo4jSession;
12 | }
13 | else {
14 | context.neo4jSession = driver.session();
15 | return context.neo4jSession;
16 | }
17 | };
18 |
19 | exports.dbWhere = function (name, keys) {
20 | if (_.isArray(name)) {
21 | _.map(name, (obj) => {
22 | return _whereTemplate(obj.name, obj.key, obj.paramKey);
23 | });
24 | } else if (keys && keys.length) {
25 | return 'WHERE ' + _.map(keys, (key) => {
26 | return _whereTemplate(name, key);
27 | }).join(' AND ');
28 | }
29 | };
30 |
31 | function whereTemplate(name, key, paramKey) {
32 | return name + '.' + key + '={' + (paramKey || key) + '}';
33 | }
34 |
--------------------------------------------------------------------------------
/web/src/api/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import humps from 'humps';
3 | import UserSession from '../UserSession';
4 |
5 | const instance = axios.create();
6 | instance.defaults.headers.post['Content-Type'] = 'application/json';
7 | instance.defaults.headers.patch['Content-Type'] = 'application/json';
8 |
9 | instance.interceptors.request.use(function (request) {
10 | const authToken = UserSession.getToken();
11 | if (authToken) {
12 | if (request.headers && !request.headers.Authorization) {
13 | request.headers['Authorization'] = `Token ${authToken}`;
14 | }
15 | }
16 |
17 | if (request.data) {
18 | const data = typeof request.data === "string" ? JSON.parse(request.data) : request.data
19 | request.data = JSON.stringify(humps.decamelizeKeys(data));
20 | }
21 | return request;
22 | });
23 |
24 | instance.interceptors.response.use(function (response) {
25 | if (response.data) {
26 | return humps.camelizeKeys(response.data);
27 | }
28 | });
29 |
30 | export default instance;
31 |
--------------------------------------------------------------------------------
/api/routes/genres.js:
--------------------------------------------------------------------------------
1 | const Genres = require("../models/genres")
2 | , writeResponse = require('../helpers/response').writeResponse
3 | , dbUtils = require('../neo4j/dbUtils');
4 |
5 | /**
6 | * @swagger
7 | * definition:
8 | * Genre:
9 | * type: object
10 | * properties:
11 | * id:
12 | * type: integer
13 | * name:
14 | * type: string
15 | */
16 |
17 | /**
18 | * @swagger
19 | * /api/v0/genres:
20 | * get:
21 | * tags:
22 | * - genres
23 | * description: Returns all genres
24 | * summary: Returns all genres
25 | * produces:
26 | * - application/json
27 | * responses:
28 | * 200:
29 | * description: A list of genres
30 | * schema:
31 | * type: array
32 | * items:
33 | * $ref: '#/definitions/Genre'
34 | */
35 | exports.list = function (req, res, next) {
36 | Genres.getAll(dbUtils.getSession(req))
37 | .then(response => writeResponse(res, response))
38 | .catch(next);
39 | };
--------------------------------------------------------------------------------
/web/src/redux/sagas/personFlow.js:
--------------------------------------------------------------------------------
1 | import {all, call, put, takeEvery} from 'redux-saga/effects';
2 | import PersonApi from '../../api/PersonApi';
3 | import * as Actions from '../actions/PersonActions';
4 | import * as Types from '../actions/PersonActionTypes';
5 |
6 | export default function* movieFlow() {
7 | yield all([
8 | takeEvery(Types.PERSON_DETAIL_GET_REQUEST, getPerson),
9 | takeEvery(Types.PERSON_RELATED_GET_REQUEST, getRelated)
10 | ]);
11 | }
12 |
13 | function* getPerson(action) {
14 | var {id} = action;
15 | try {
16 | const response = yield call(PersonApi.getPerson, id);
17 | yield put(Actions.getPersonSuccess(response));
18 | }
19 | catch (error) {
20 | yield put(Actions.getPersonFailure(error));
21 | }
22 | }
23 |
24 | function* getRelated(action) {
25 | var {id} = action;
26 | try {
27 | const response = yield call(PersonApi.getRelated, id);
28 | yield put(Actions.getRelatedSuccess(response));
29 | }
30 | catch (error) {
31 | yield put(Actions.getRelatedFailure(error));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/web/src/routes/Routes.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Route} from 'react-router';
3 | import App from '../pages/App.jsx';
4 | import Home from '../pages/Home.jsx';
5 | import Movie from '../pages/Movie.jsx';
6 | import Person from '../pages/Person.jsx';
7 | import Login from '../pages/Login.jsx';
8 | import Signup from '../pages/Signup.jsx';
9 | import SignupStatus from '../pages/SignupStatus.jsx';
10 | import Profile from '../pages/Profile.jsx';
11 |
12 | export default class Routes extends React.Component {
13 | render() {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | Routes.displayName = 'Routes';
29 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/auth.js:
--------------------------------------------------------------------------------
1 | import * as Types from '../actions/AuthActionTypes';
2 | import UserSession from '../../UserSession';
3 | import ErrorUtils from '../../utils/ErrorUtils';
4 |
5 | export default function auth(state = getInitialState(), action) {
6 | switch (action.type) {
7 | case Types.LOGIN:
8 | return {
9 | ...state,
10 | isFetching: true,
11 | errors: {}
12 | };
13 | case Types.LOGIN_SUCCESS:
14 | return {
15 | ...getInitialState(),
16 | token: action.token
17 | };
18 | case Types.LOGIN_FAILURE:
19 | return {
20 | ...state,
21 | isFetching: false,
22 | errors: ErrorUtils.getApiErrors(action.error),
23 | };
24 | case Types.LOGOUT:
25 | return {
26 | ...state,
27 | token: null
28 | };
29 | default:
30 | return state;
31 | }
32 | }
33 |
34 | function getInitialState() {
35 | return {
36 | isFetching: false,
37 | errors: {},
38 | token: UserSession.getToken()
39 | };
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/web/src/redux/actions/NotificationActions.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import {NotificationActionTypes, NotificationType} from './NotificationActionTypes';
3 |
4 | export function create(type, message) {
5 | return {
6 | type: NotificationActionTypes.CREATE_NOTIFICATION,
7 | notification: {
8 | id: _.uniqueId(),
9 | message,
10 | type
11 | }
12 | };
13 | }
14 |
15 | export function createError(message) {
16 | return {
17 | type: NotificationActionTypes.CREATE_NOTIFICATION,
18 | notification: {
19 | id: _.uniqueId(),
20 | message,
21 | type: NotificationType.error
22 | }
23 | };
24 | }
25 |
26 | export function createSuccess(message) {
27 | return {
28 | type: NotificationActionTypes.CREATE_NOTIFICATION,
29 | notification: {
30 | id: _.uniqueId(),
31 | message,
32 | type: NotificationType.success
33 | }
34 | };
35 | }
36 |
37 | export function dismiss(notification) {
38 | return {
39 | type: NotificationActionTypes.DISMISS_NOTIFICATION,
40 | notification
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/web/src/components/common/NotificationContainer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Notification from './Notification.jsx';
3 | import { connect } from 'react-redux';
4 | import { bindActionCreators } from 'redux';
5 | import * as NotificationActions from '../../redux/actions/NotificationActions';
6 |
7 | const NotificationContainer = ({dismiss, notifications}) => {
8 | return (
9 |
10 | {
11 | notifications.map((notification, index) => )
12 | }
13 |
14 | );
15 | };
16 |
17 | NotificationContainer.displayName = 'NotificationContainer';
18 |
19 | function mapStateToProps(state) {
20 | return {
21 | notifications: state.notifications
22 | };
23 | }
24 |
25 | function mapDispatchToProps(dispatch) {
26 | return bindActionCreators(NotificationActions, dispatch);
27 | }
28 |
29 | // Wrap the component to inject dispatch and state into it
30 | export default connect(mapStateToProps, mapDispatchToProps)(NotificationContainer);
31 |
32 |
--------------------------------------------------------------------------------
/web/src/styles/main.scss:
--------------------------------------------------------------------------------
1 | @import "components/buttonLink";
2 |
3 | @import '_variables.scss';
4 | @import './foundation/scss/normalize';
5 | @import './foundation/scss/foundation';
6 |
7 | @import "components/notificationContainer";
8 | @import "components/header";
9 | @import "components/breadcrumbs";
10 | @import "components/loading";
11 | @import "components/carousel";
12 | @import "components/userRating";
13 | @import "components/validation";
14 |
15 | @import "views/home";
16 | @import "views/movie";
17 | @import "views/person";
18 | @import "views/profile";
19 |
20 | .nt-app {
21 | background-image: url("/neo4j_background3.gif");
22 | }
23 |
24 | .nt-box {
25 | border: 1px solid lightgrey;
26 | border-radius: .5rem;
27 | padding: .2rem;
28 | background: #FFFFFF;
29 |
30 | &-title {
31 | padding: .5rem;
32 | color: saddlebrown;
33 | font-size: 1.2rem;
34 | }
35 |
36 | &-row {
37 | padding: .5rem;
38 | margin: 0;
39 | }
40 | }
41 |
42 | ul {
43 | list-style: none;
44 | li {
45 | display: inline-block;
46 | width: auto;
47 | padding: .5rem;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/person.js:
--------------------------------------------------------------------------------
1 | import * as Types from '../actions/PersonActionTypes';
2 |
3 | const initialState = {
4 | isFetching: false,
5 | isFetchingRelated: false,
6 | detail: null,
7 | related: []
8 | };
9 |
10 | export default function person(state = {...initialState}, action) {
11 | switch (action.type) {
12 | case Types.PERSON_DETAIL_GET_REQUEST:
13 | return {
14 | ...state,
15 | isFetching: true
16 | };
17 | case Types.PERSON_DETAIL_GET_SUCCESS:
18 | return {
19 | ...state,
20 | isFetching: false,
21 | detail: action.response
22 | };
23 | case Types.PERSON_DETAIL_CLEAR:
24 | return {
25 | ...initialState
26 | };
27 | case Types.PERSON_RELATED_GET_REQUEST:
28 | return {
29 | ...state,
30 | isFetchingRelated: true
31 | };
32 | case Types.PERSON_RELATED_GET_SUCCESS:
33 | return {
34 | ...state,
35 | isFetchingRelated: false,
36 | related: action.response.related
37 | };
38 |
39 | default:
40 | return state;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/api/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 tinj
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2015 ZURB, inc.
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/api/swaggerui/lib/highlight.9.1.0.pack_extended.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function () {
4 | var configure, highlightBlock;
5 |
6 | configure = hljs.configure;
7 | // "extending" hljs.configure method
8 | hljs.configure = function _configure (options) {
9 | var size = options.highlightSizeThreshold;
10 |
11 | // added highlightSizeThreshold option to set maximum size
12 | // of processed string. Set to null if not a number
13 | hljs.highlightSizeThreshold = size === +size ? size : null;
14 |
15 | configure.call(this, options);
16 | };
17 |
18 | highlightBlock = hljs.highlightBlock;
19 |
20 | // "extending" hljs.highlightBlock method
21 | hljs.highlightBlock = function _highlightBlock (el) {
22 | var innerHTML = el.innerHTML;
23 | var size = hljs.highlightSizeThreshold;
24 |
25 | // check if highlightSizeThreshold is not set or element innerHTML
26 | // is less than set option highlightSizeThreshold
27 | if (size == null || size > innerHTML.length) {
28 | // proceed with hljs.highlightBlock
29 | highlightBlock.call(hljs, el);
30 | }
31 | };
32 |
33 | })();
34 |
35 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lib/highlight.9.1.0.pack_extended.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function () {
4 | var configure, highlightBlock;
5 |
6 | configure = hljs.configure;
7 | // "extending" hljs.configure method
8 | hljs.configure = function _configure (options) {
9 | var size = options.highlightSizeThreshold;
10 |
11 | // added highlightSizeThreshold option to set maximum size
12 | // of processed string. Set to null if not a number
13 | hljs.highlightSizeThreshold = size === +size ? size : null;
14 |
15 | configure.call(this, options);
16 | };
17 |
18 | highlightBlock = hljs.highlightBlock;
19 |
20 | // "extending" hljs.highlightBlock method
21 | hljs.highlightBlock = function _highlightBlock (el) {
22 | var innerHTML = el.innerHTML;
23 | var size = hljs.highlightSizeThreshold;
24 |
25 | // check if highlightSizeThreshold is not set or element innerHTML
26 | // is less than set option highlightSizeThreshold
27 | if (size == null || size > innerHTML.length) {
28 | // proceed with hljs.highlightBlock
29 | highlightBlock.call(hljs, el);
30 | }
31 | };
32 |
33 | })();
34 |
35 |
--------------------------------------------------------------------------------
/web/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { createStore, applyMiddleware } from 'redux';
4 | import thunkMiddleware from 'redux-thunk';
5 | import { Provider } from 'react-redux';
6 | import { createLogger } from 'redux-logger';
7 | import createSagaMiddleware from 'redux-saga';
8 | import { ConnectedRouter, routerMiddleware } from 'connected-react-router';
9 | import { createBrowserHistory } from "history";
10 |
11 | import sagas from './redux/sagas';
12 | import createRootReducer from './redux/reducers';
13 | import Routes from './routes/Routes.jsx';
14 |
15 | const reduxLoggerMiddleware = createLogger();
16 | const sagaMiddleware = createSagaMiddleware();
17 | const history = createBrowserHistory();
18 |
19 | const store = createStore(
20 | createRootReducer(history),
21 | applyMiddleware(
22 | routerMiddleware(history),
23 | thunkMiddleware,
24 | sagaMiddleware,
25 | reduxLoggerMiddleware,
26 | ),
27 | )
28 |
29 | sagaMiddleware.run(sagas);
30 |
31 | ReactDOM.render(
32 |
33 |
34 |
35 |
36 | ,
37 | document.getElementById('root')
38 | );
39 |
--------------------------------------------------------------------------------
/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.3.2",
8 | "@testing-library/user-event": "^7.1.2",
9 | "axios": "^0.21.2",
10 | "connected-react-router": "^6.8.0",
11 | "humps": "^2.0.1",
12 | "node-sass": "^4.14.1",
13 | "prop-types": "^15.7.2",
14 | "react": "^16.13.1",
15 | "react-dom": "^16.13.1",
16 | "react-redux": "^7.2.0",
17 | "react-router": "^5.2.0",
18 | "react-router-dom": "^5.2.0",
19 | "react-scripts": "^3.4.3",
20 | "redux": "^4.0.5",
21 | "redux-logger": "^3.0.6",
22 | "redux-saga": "^1.1.3",
23 | "redux-thunk": "^2.3.0"
24 | },
25 | "scripts": {
26 | "start": "react-scripts start",
27 | "build": "react-scripts build",
28 | "test": "react-scripts test",
29 | "eject": "react-scripts eject"
30 | },
31 | "eslintConfig": {
32 | "extends": "react-app"
33 | },
34 | "browserslist": {
35 | "production": [
36 | ">0.2%",
37 | "not dead",
38 | "not op_mini all"
39 | ],
40 | "development": [
41 | "last 1 chrome version",
42 | "last 1 firefox version",
43 | "last 1 safari version"
44 | ]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "neo4j-movies-api",
3 | "version": "0.0.20",
4 | "author": {
5 | "name": "The SilveLogic",
6 | "email": "info@tsl.io",
7 | "url": "tsl.io"
8 | },
9 | "description": "API for a movie demo app using Neo4j",
10 | "repository": {
11 | "type": "git",
12 | "url": "tbd"
13 | },
14 | "keywords": [
15 | "node",
16 | "neo4j",
17 | "express",
18 | "api",
19 | "http",
20 | "rest",
21 | "swagger",
22 | "server"
23 | ],
24 | "engines": {
25 | "node": ">=0.11.x",
26 | "npm": "1.2.x"
27 | },
28 | "dependencies": {
29 | "body-parser": "^1.19.0",
30 | "dotenv": "^8.2.0",
31 | "errorhandler": "^1.5.1",
32 | "express": "^4.17.1",
33 | "hat": "0.0.3",
34 | "install": "^0.13.0",
35 | "lodash": "^4.17.21",
36 | "md5": "^2.2.1",
37 | "method-override": "^3.0.0",
38 | "mocha": "^7.2.0",
39 | "moment": "^2.26.0",
40 | "morgan": "^1.10.0",
41 | "nconf": "^0.10.0",
42 | "neo4j-driver": "^4.1.2",
43 | "node-uuid": "^1.4.8",
44 | "pug": "^3.0.1",
45 | "randomstring": "^1.1.5",
46 | "serve-favicon": "^2.5.0",
47 | "should": "^13.2.3",
48 | "swagger-jsdoc": "^4.0.0",
49 | "swagger-ui-express": "^4.1.4"
50 | },
51 | "license": "MIT"
52 | }
53 |
--------------------------------------------------------------------------------
/web/src/styles/components/_header.scss:
--------------------------------------------------------------------------------
1 | .nt-app-header {
2 | background: lightgrey;
3 | padding: .5rem 1rem;
4 | height: 104px;
5 | @media (max-width: 385px) {
6 | height: 145px;
7 | }
8 |
9 | &-logo {
10 | max-width: 5rem;
11 | display: inline-block;
12 | @media (min-width: 386px) {
13 | padding-top: 26px;
14 | }
15 | }
16 |
17 | &-links {
18 | list-style: none;
19 | display: inline-block;
20 | margin: 0;
21 | padding-right: 8px;
22 |
23 | li {
24 | display: inline-block;
25 | padding: .5rem 0 .5rem .5rem;
26 |
27 | @media #{$small-only} {
28 | &::before {
29 | display: none;
30 | }
31 | }
32 |
33 | &::before {
34 | color: #AAAAAA;
35 | content: "";
36 | border-right: 1px solid darkgray;
37 | margin: 0 1rem;
38 | position: relative;
39 | top: 1px;
40 | }
41 | }
42 | }
43 |
44 | &-avatar {
45 | width: 4rem;
46 | height: 4rem;
47 | border-radius: 2em;
48 | background-size: contain !important;
49 | a {
50 | display: block;
51 | width: 100%;
52 | height: 100%;
53 | }
54 | }
55 |
56 | &-link {
57 | }
58 |
59 | &-profile-links{
60 | float: right;
61 | text-align: center;
62 | width: 64px;
63 | }
64 | }
--------------------------------------------------------------------------------
/web/src/redux/actions/MovieActionTypes.js:
--------------------------------------------------------------------------------
1 | export const MOVIE_GENRES_GET_REQUEST = 'MOVIE_GENRES_GET_REQUEST';
2 | export const MOVIE_GENRES_GET_SUCCESS = 'MOVIE_GENRES_GET_SUCCESS';
3 | export const MOVIE_GENRES_GET_FAILURE = 'MOVIE_GENRES_GET_FAILURE';
4 |
5 | export const MOVIES_BY_GENRES_GET_REQUEST = 'MOVIES_BY_GENRES_GET_REQUEST';
6 | export const MOVIES_BY_GENRES_GET_SUCCESS = 'MOVIES_BY_GENRES_GET_SUCCESS';
7 | export const MOVIES_BY_GENRES_GET_FAILURE = 'MOVIES_BY_GENRES_GET_FAILURE';
8 |
9 | export const MOVIES_FEATURED_GET_REQUEST = 'MOVIES_FEATURED_GET_REQUEST';
10 | export const MOVIES_FEATURED_GET_SUCCESS = 'MOVIES_FEATURED_GET_SUCCESS';
11 | export const MOVIES_FEATURED_GET_FAILURE = 'MOVIES_FEATURED_GET_FAILURE';
12 |
13 | export const MOVIE_DETAIL_CLEAR = 'MOVIE_DETAIL_CLEAR';
14 | export const MOVIE_DETAIL_GET_REQUEST = 'MOVIE_DETAIL_GET_REQUEST';
15 | export const MOVIE_DETAIL_GET_SUCCESS = 'MOVIE_DETAIL_GET_SUCCESS';
16 | export const MOVIE_DETAIL_GET_FAILURE = 'MOVIE_DETAIL_GET_FAILURE';
17 |
18 | export const MOVIE_RATE = 'MOVIE_RATE';
19 | export const MOVIE_RATE_SUCCESS = 'MOVIE_RATE_SUCCESS';
20 | export const MOVIE_RATE_FAILURE = 'MOVIE_RATE_FAILURE';
21 |
22 | export const MOVIE_DELETE_RATING = 'MOVIE_DELETE_RATING';
23 | export const MOVIE_DELETE_RATING_SUCCESS = 'MOVIE_DELETE_RATING_SUCCESS';
24 | export const MOVIE_DELETE_RATING_FAILURE = 'MOVIE_DELETE_RATING_FAILURE';
--------------------------------------------------------------------------------
/web/src/styles/foundation/scss/foundation/components/_flex-video.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | @import 'global';
6 |
7 | //
8 | // @variables
9 | //
10 | $include-html-media-classes: $include-html-classes !default;
11 |
12 | // We use these to control video container padding and margins
13 | $flex-video-padding-top: rem-calc(25) !default;
14 | $flex-video-padding-bottom: 67.5% !default;
15 | $flex-video-margin-bottom: rem-calc(16) !default;
16 |
17 | // We use this to control widescreen bottom padding
18 | $flex-video-widescreen-padding-bottom: 56.34% !default;
19 |
20 | //
21 | // @mixins
22 | //
23 |
24 | @mixin flex-video-container {
25 | height: 0;
26 | margin-bottom: $flex-video-margin-bottom;
27 | overflow: hidden;
28 | padding-bottom: $flex-video-padding-bottom;
29 | padding-top: $flex-video-padding-top;
30 | position: relative;
31 |
32 | &.widescreen { padding-bottom: $flex-video-widescreen-padding-bottom; }
33 | &.vimeo { padding-top: 0; }
34 |
35 | iframe,
36 | object,
37 | embed,
38 | video {
39 | height: 100%;
40 | position: absolute;
41 | top: 0;
42 | width: 100%;
43 | #{$default-float}: 0;
44 | }
45 | }
46 |
47 | @include exports("flex-video") {
48 | @if $include-html-media-classes {
49 | .flex-video { @include flex-video-container; }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/web/src/redux/actions/ProfileActionTypes.js:
--------------------------------------------------------------------------------
1 | export const PROFILE_GET = 'PROFILE_GET';
2 | export const PROFILE_GET_SUCCESS = 'PROFILE_GET_SUCCESS';
3 | export const PROFILE_GET_FAILURE = 'PROFILE_GET_FAILURE';
4 |
5 | export const PROFILE_CREATE = 'PROFILE_CREATE';
6 | export const PROFILE_CREATE_SUCCESS = 'PROFILE_CREATE_SUCCESS';
7 | export const PROFILE_CREATE_FAILURE = 'PROFILE_CREATE_FAILURE';
8 | export const PROFILE_CREATE_INIT = 'PROFILE_CREATE_INIT';
9 |
10 | export const PROFILE_GET_RATINGS = 'PROFILE_GET_RATINGS';
11 | export const PROFILE_GET_RATINGS_SUCCESS = 'PROFILE_GET_RATINGS_SUCCESS';
12 | export const PROFILE_GET_RATINGS_FAILURE = 'PROFILE_GET_RATINGS_FAILURE';
13 |
14 | export const PROFILE_MOVIE_RATE = 'PROFILE_MOVIE_RATE';
15 | export const PROFILE_MOVIE_RATE_SUCCESS = 'PROFILE_MOVIE_RATE_SUCCESS';
16 | export const PROFILE_MOVIE_RATE_FAILURE = 'PROFILE_MOVIE_RATE_FAILURE';
17 |
18 | export const PROFILE_MOVIE_DELETE_RATING = 'PROFILE_MOVIE_DELETE_RATING';
19 | export const PROFILE_MOVIE_DELETE_RATING_SUCCESS = 'PROFILE_MOVIE_DELETE_RATING_SUCCESS';
20 | export const PROFILE_MOVIE_DELETE_RATING_FAILURE = 'PROFILE_MOVIE_DELETE_RATING_FAILURE';
21 |
22 | export const PROFILE_GET_RECOMMENDATIONS = 'PROFILE_GET_RECOMMENDATIONS';
23 | export const PROFILE_GET_RECOMMENDATIONS_SUCCESS = 'PROFILE_GET_RECOMMENDATIONS_SUCCESS';
24 | export const PROFILE_GET_RECOMMENDATIONS_FAILURE = 'PROFILE_GET_RECOMMENDATIONS_FAILURE';
--------------------------------------------------------------------------------
/web/src/redux/sagas/errorFlow.js:
--------------------------------------------------------------------------------
1 | import { takeEvery, put } from 'redux-saga/effects';
2 | import * as NotificationActions from '../actions/NotificationActions';
3 | import _ from 'lodash';
4 |
5 | export default function* watchErrors(getState) {
6 | yield takeEvery('*', function* logger(action) {
7 | if(action.error) {
8 | var errorAction = createErrorNotification(action.error);
9 | yield put(errorAction);
10 | }
11 | });
12 | }
13 |
14 | function createErrorNotification(err) {
15 | if(err.status === 500) {
16 | return NotificationActions.createError(err.statusText || 'Internal Server Error');
17 | }
18 |
19 | if (err.status !== 401) {
20 | var errMessages = [];
21 | if (err.data) {
22 | try {
23 | for (var prop in err.data) {
24 | var msg = err.data[prop];
25 | if (_.isArray(msg)) {
26 | msg = msg.join(' ');
27 | }
28 |
29 | errMessages.push(`${prop}: ${msg}`);
30 | }
31 | } catch (ex) {
32 | console.error(ex);
33 | }
34 | }
35 |
36 | var errMessage = '';
37 | if (errMessages.length === 1) {
38 | errMessage = errMessages[0];
39 | }
40 | else {
41 | errMessage = errMessages.join('\n\n');
42 | }
43 |
44 | var message = err.message || errMessage || (err.responseText ? ('Error: ' + err.responseText) : 'Error (see console logs)');
45 |
46 | return NotificationActions.createError(message);
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/profile.js:
--------------------------------------------------------------------------------
1 | import * as Types from '../actions/ProfileActionTypes';
2 | import {LOGOUT} from '../actions/AuthActionTypes';
3 |
4 | export default function profile(state = getInitialState(null), action) {
5 | switch (action.type) {
6 | case LOGOUT:
7 | return getInitialState();
8 | default:
9 | return state;
10 | case Types.PROFILE_GET:
11 | case Types.PROFILE_GET_RATINGS:
12 | case Types.PROFILE_GET_RECOMMENDATIONS:
13 | return {
14 | ...state,
15 | isFetching: true
16 | };
17 | case Types.PROFILE_GET_FAILURE:
18 | case Types.PROFILE_GET_RATINGS_FAILURE:
19 | case Types.PROFILE_GET_RECOMMENDATIONS_FAILURE:
20 | return {
21 | ...state,
22 | isFetching: false
23 | };
24 | case Types.PROFILE_GET_SUCCESS:
25 | return {
26 | ...state,
27 | isFetching: false,
28 | profile: action.payload
29 | };
30 | case Types.PROFILE_GET_RATINGS_SUCCESS:
31 | return {
32 | ...state,
33 | isFetching: false,
34 | ratedMovies: action.payload
35 | };
36 | case Types.PROFILE_GET_RECOMMENDATIONS_SUCCESS:
37 | return {
38 | ...state,
39 | isFetching: false,
40 | recommendedMovies: action.payload
41 | };
42 | }
43 | }
44 |
45 | function getInitialState() {
46 | return {
47 | isFetching: false,
48 | profile: null,
49 | ratedMovies: [],
50 | recommendedMovies: []
51 | };
52 | }
53 |
--------------------------------------------------------------------------------
/web/src/components/common/Notification.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {NotificationType} from '../../redux/actions/NotificationActionTypes';
4 |
5 | export default class Notification extends Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.dismiss = this.dismiss.bind(this);
10 | }
11 |
12 | componentDidMount() {
13 | var {notification, dismiss, timeout} = this.props;
14 |
15 | this.dismissNotification = setTimeout(function () {
16 | dismiss(notification);
17 | }, timeout);
18 | }
19 |
20 | dismiss() {
21 | this.props.dismiss(this.props.notification);
22 | clearTimeout(this.dismissNotification);
23 | }
24 |
25 | render() {
26 | var {notification} = this.props;
27 |
28 | if (!notification) {
29 | return null;
30 | }
31 |
32 | //can use enum key or value
33 | var classes = NotificationType[notification.type] || notification.type;
34 |
35 | return (
36 |
37 | {notification.message}
38 |
39 |
40 | );
41 | }
42 | }
43 |
44 |
45 | Notification.displayName = 'Notification';
46 | Notification.propTypes = {
47 | notification: PropTypes.object.isRequired,
48 | timeout: PropTypes.number,
49 | dismiss: PropTypes.func
50 | };
51 | Notification.defaultProps = {
52 | timeout: 6000
53 | };
54 |
--------------------------------------------------------------------------------
/web/src/styles/components/_loading.scss:
--------------------------------------------------------------------------------
1 | .sk-spinner-chasing-dots.sk-spinner {
2 | margin: 0 auto;
3 | width: 40px;
4 | height: 40px;
5 | top: 10px;
6 | right: 10px;
7 | text-align: center;
8 | -webkit-animation: sk-chasingDotsRotate 2s infinite linear;
9 | animation: sk-chasingDotsRotate 2s infinite linear; }
10 | .sk-spinner-chasing-dots .sk-dot1, .sk-spinner-chasing-dots .sk-dot2 {
11 | width: 60%;
12 | height: 60%;
13 | display: inline-block;
14 | position: absolute;
15 | top: 0;
16 | background-color: #333;
17 | border-radius: 100%;
18 | -webkit-animation: sk-chasingDotsBounce 2s infinite ease-in-out;
19 | animation: sk-chasingDotsBounce 2s infinite ease-in-out; }
20 | .sk-spinner-chasing-dots .sk-dot2 {
21 | top: auto;
22 | bottom: 0px;
23 | -webkit-animation-delay: -1s;
24 | animation-delay: -1s; }
25 |
26 | @-webkit-keyframes sk-chasingDotsRotate {
27 | 100% {
28 | -webkit-transform: rotate(360deg);
29 | transform: rotate(360deg); } }
30 |
31 | @keyframes sk-chasingDotsRotate {
32 | 100% {
33 | -webkit-transform: rotate(360deg);
34 | transform: rotate(360deg); } }
35 |
36 | @-webkit-keyframes sk-chasingDotsBounce {
37 | 0%, 100% {
38 | -webkit-transform: scale(0);
39 | transform: scale(0); }
40 |
41 | 50% {
42 | -webkit-transform: scale(1);
43 | transform: scale(1); } }
44 |
45 | @keyframes sk-chasingDotsBounce {
46 | 0%, 100% {
47 | -webkit-transform: scale(0);
48 | transform: scale(0); }
49 |
50 | 50% {
51 | -webkit-transform: scale(1);
52 | transform: scale(1);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/translator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Translator for documentation pages.
5 | *
6 | * To enable translation you should include one of language-files in your index.html
7 | * after .
8 | * For example -
9 | *
10 | * If you wish to translate some new texts you should do two things:
11 | * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too.
12 | * 2. Mark that text it templates this way New Phrase or .
13 | * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate.
14 | *
15 | */
16 | window.SwaggerTranslator = {
17 |
18 | _words:[],
19 |
20 | translate: function(sel) {
21 | var $this = this;
22 | sel = sel || '[data-sw-translate]';
23 |
24 | $(sel).each(function() {
25 | $(this).html($this._tryTranslate($(this).html()));
26 |
27 | $(this).val($this._tryTranslate($(this).val()));
28 | $(this).attr('title', $this._tryTranslate($(this).attr('title')));
29 | });
30 | },
31 |
32 | _tryTranslate: function(word) {
33 | return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
34 | },
35 |
36 | learn: function(wordsMap) {
37 | this._words = wordsMap;
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/translator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Translator for documentation pages.
5 | *
6 | * To enable translation you should include one of language-files in your index.html
7 | * after .
8 | * For example -
9 | *
10 | * If you wish to translate some new texts you should do two things:
11 | * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too.
12 | * 2. Mark that text it templates this way New Phrase or .
13 | * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate.
14 | *
15 | */
16 | window.SwaggerTranslator = {
17 |
18 | _words:[],
19 |
20 | translate: function(sel) {
21 | var $this = this;
22 | sel = sel || '[data-sw-translate]';
23 |
24 | $(sel).each(function() {
25 | $(this).html($this._tryTranslate($(this).html()));
26 |
27 | $(this).val($this._tryTranslate($(this).val()));
28 | $(this).attr('title', $this._tryTranslate($(this).attr('title')));
29 | });
30 | },
31 |
32 | _tryTranslate: function(word) {
33 | return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
34 | },
35 |
36 | learn: function(wordsMap) {
37 | this._words = wordsMap;
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/web/src/api/MoviesApi.js:
--------------------------------------------------------------------------------
1 | import settings from '../config/settings';
2 | import axios from './axios';
3 | import _ from 'lodash';
4 |
5 | const {apiBaseURL} = settings;
6 |
7 | export default class MoviesApi {
8 | static getGenres() {
9 | return axios.get(`${apiBaseURL}/genres`);
10 | }
11 |
12 | static getMoviesByGenres(genreNames) {
13 | return MoviesApi.getGenres()
14 | .then(genres => {
15 | var movieGenres = _.filter(genres, g => {
16 | return genreNames.indexOf(g.name) > -1;
17 | });
18 |
19 | return Promise.all(
20 | movieGenres.map(genre => {
21 | return axios.get(`${apiBaseURL}/movies/genre/${genre.id}/`);
22 | }
23 | ))
24 | .then(genreResults => {
25 | var result = {};
26 | genreResults.forEach((movies, i) => {
27 | result[movieGenres[i].name] = movies;
28 | });
29 |
30 | return result;
31 | });
32 | });
33 | }
34 |
35 | // convert this to top 3 most rated movies
36 | static getFeaturedMovies() {
37 | return Promise.all([
38 | axios.get(`${apiBaseURL}/movies/13380`),
39 | axios.get(`${apiBaseURL}/movies/15292`),
40 | axios.get(`${apiBaseURL}/movies/11398`)
41 | ]);
42 | }
43 |
44 | static getMovie(id) {
45 | return axios.get(`${apiBaseURL}/movies/${id}`);
46 | }
47 |
48 | static rateMovie(id, rating) {
49 | return axios.post(`${apiBaseURL}/movies/${id}/rate`, {rating});
50 | }
51 |
52 | static deleteRating(id) {
53 | return axios.delete(`${apiBaseURL}/movies/${id}/rate`);
54 | }
55 | }
56 |
57 |
58 |
--------------------------------------------------------------------------------
/web/src/pages/App.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import _ from 'lodash';
4 |
5 | import Header from '../components/Header.jsx';
6 | import {getProfile} from '../redux/actions/ProfileActions';
7 | import UserSession from '../UserSession';
8 | // import Footer from '../components/Footer.jsx';
9 | import Breadcrumbs from '../components/Breadcrumbs.jsx';
10 | import NotificationContainer from '../components/common/NotificationContainer.jsx';
11 |
12 | import { connect } from 'react-redux';
13 | import "../styles/main.scss";
14 |
15 | class App extends React.Component {
16 | componentDidMount() {
17 | if (UserSession.getToken() && !this.props.profile) {
18 | this.props.dispatch(getProfile());
19 | }
20 | }
21 |
22 | render() {
23 | var {auth, profile, movie, person} = this.props;
24 |
25 | return (
26 |
37 | );
38 | }
39 | }
40 |
41 | App.displayName = 'App';
42 | App.propTypes = {
43 | movie: PropTypes.object,
44 | person: PropTypes.object
45 | };
46 |
47 | function mapStateToProps(state) {
48 | return {
49 | movie: state.movies.detail,
50 | person: state.person.detail,
51 | auth: state.auth,
52 | profile: _.get(state.profile, 'profile', null)
53 | };
54 | }
55 |
56 | export default connect(mapStateToProps)(App);
57 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/README.md:
--------------------------------------------------------------------------------
1 | # [Foundation](http://foundation.zurb.com)
2 |
3 | [](https://travis-ci.org/zurb/foundation)
4 |
5 |
6 | Foundation is the most advanced responsive front-end framework in the world. You can quickly prototype and build sites or apps that work on any kind of device with Foundation, which includes layout constructs (like a fully responsive grid), elements and best practices.
7 |
8 | To get started, check out
9 |
10 |
11 | ## Quickstart
12 |
13 | To get going with Foundation you can:
14 |
15 | * [Download the latest release](http://foundation.zurb.com/develop/download.html)
16 | * [Install with Bower](http://bower.io): `bower install foundation`
17 | * [Install with npm](http://npmjs.com): `npm install foundation-sites`
18 |
19 | ## Documentation
20 |
21 | Foundation uses [Assemble.io](http://assemble.io) and [Grunt](http://gruntjs.com/) to generate its [documentation pages](http://foundation.zurb.com/docs). Documentation can also be run from your local computer:
22 |
23 | ### View documentation locally
24 |
25 | You'll want to clone the Foundation repo first and install all the dependencies. You can do this using the following commands:
26 |
27 | ```
28 | git clone git@github.com:zurb/foundation.git
29 | cd foundation
30 | npm install -g grunt-cli bower
31 | npm install
32 | bower install
33 | bundle install
34 | ```
35 |
36 | Then just run `grunt build` and the documentation will be compiled:
37 |
38 | ```
39 | foundation/
40 | ├── dist/
41 | │ └── ...
42 | ├────── docs/
43 | │ └── ...
44 | ```
45 |
46 | Copyright (c) 2015 ZURB, inc.
47 |
--------------------------------------------------------------------------------
/web/src/components/UserRating.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const minRating = 1;
5 | const maxRating = 5;
6 |
7 | export default class UserRating extends React.Component {
8 | render() {
9 | var stars = [];
10 | var {movieId, savedRating} = this.props;
11 |
12 | for (let i = minRating; i <= maxRating; i++) {
13 | stars.push(this.renderStar(!savedRating || i > savedRating, movieId, i));
14 | }
15 |
16 | return (
17 |
18 | {stars}
19 | {
20 | savedRating ?
21 |
26 | :
27 | null
28 | }
29 |
30 | );
31 | }
32 |
33 | renderStar(isEmpty, movieId, rating) {
34 | return (
35 | );
40 | }
41 |
42 | onRateClick(movieId, rating, e) {
43 | e.preventDefault();
44 | this.props.onSubmitRating(movieId, rating);
45 | }
46 |
47 | onDeleteRatingClick(movieId, e) {
48 | e.preventDefault();
49 | this.props.onDeleteRating(movieId);
50 | }
51 | }
52 |
53 | UserRating.propTypes = {
54 | movieId: PropTypes.number.isRequired,
55 | savedRating: PropTypes.number,
56 | onSubmitRating: PropTypes.func.isRequired,
57 | onDeleteRating: PropTypes.func.isRequired
58 | };
59 |
60 | UserRating.displayName = 'UserRating';
61 |
62 |
--------------------------------------------------------------------------------
/web/src/styles/components/_carousel.scss:
--------------------------------------------------------------------------------
1 |
2 |
3 | .nt-carousel {
4 | position: relative;
5 |
6 | &-list {
7 | position: relative;
8 | margin: 0;
9 | }
10 |
11 | &-item {
12 | vertical-align: top;
13 | }
14 |
15 | &-arrow {
16 | font-size: 1.5rem;
17 | font-weight: 700;
18 | color: white;
19 | }
20 |
21 | &-left {
22 | position: absolute;
23 | left: 0;
24 | top: 40%;
25 | display: inline-block;
26 | padding: 1rem;
27 | z-index: 2;
28 | background: rgba(0, 0, 0, 0.3);
29 |
30 | &:hover {
31 | background: rgba(0, 0, 0, 0.3);
32 | }
33 | }
34 |
35 | &-right {
36 | position: absolute;
37 | right: 0;
38 | top: 40%;
39 | display: inline-block;
40 | padding: 1rem;
41 | z-index: 2;
42 | background: rgba(0, 0, 0, 0.3);
43 |
44 | &:hover {
45 | background: rgba(0, 0, 0, 0.3);
46 | }
47 | }
48 | }
49 |
50 | .nt-carousel-movie {
51 |
52 | &-title {
53 | font-size: .8rem;
54 | height: 1.2rem;
55 | overflow: hidden;
56 | text-overflow: ellipsis;
57 | white-space: nowrap;
58 | }
59 |
60 | &-role {
61 | font-style: italic;
62 | font-size: .8rem;
63 | height: 1.2rem;
64 | overflow: hidden;
65 | text-overflow: ellipsis;
66 | white-space: nowrap;
67 | }
68 | }
69 |
70 |
71 | .nt-carousel-actor {
72 | &-name {
73 | font-size: 0.8rem;
74 | height: 1.2rem;
75 | overflow: hidden;
76 | text-overflow: ellipsis;
77 | white-space: nowrap;
78 | }
79 | &-role {
80 | font-style: italic;
81 | font-size: 0.8rem;
82 | height: 1.2rem;
83 | overflow: hidden;
84 | text-overflow: ellipsis;
85 | white-space: nowrap;
86 | }
87 | }
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/api/views/user.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1 #{user.name}
5 |
6 | p
7 | a(href='/users') Back to everyone
8 |
9 | if following.length
10 | p #{user.name} is following #{following.length} users:
11 | // TODO should say 'user' if only one! ;)
12 | ul.users
13 | for other in following
14 | li.user
15 | form(action='/users/#{user.id}/unfollow', method='POST')
16 | a(href='/users/#{other.id}') #{other.name}
17 | input(type='hidden', name='user[id]', value='#{other.id}')
18 | input(type='submit', class='unfollow', value='x')
19 | else
20 | p #{user.name} isn't following anyone currently.
21 |
22 | if others.length
23 | form(action='/users/#{user.id}/follow', method='POST')
24 | p Add someone for #{user.name} to follow:
25 | label
26 | select(name='user[id]', required)
27 | option(value='')
28 | for user in others
29 | option(value='#{user.id}') #{user.name}
30 | input(type='submit', value='Follow')
31 | else
32 | p There's no one else left for #{user.name} to follow!
33 |
34 | form(action='/users/#{user.id}', method='POST')
35 | p Edit this user:
36 | input(type='text', name='name', placeholder='#{user.name}', required)
37 | input(type='submit', value='Update')
38 |
39 | form(action='/users/#{user.id}', method='POST', onsubmit='return confirm("Are you sure?");')
40 | p And if you're feeling destructive…
41 | input(type='hidden', name='_method', value='DELETE')
42 | input(type='submit', value='Delete User')
--------------------------------------------------------------------------------
/api/swaggerui/css/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */
2 | html,
3 | body,
4 | div,
5 | span,
6 | applet,
7 | object,
8 | iframe,
9 | h1,
10 | h2,
11 | h3,
12 | h4,
13 | h5,
14 | h6,
15 | p,
16 | blockquote,
17 | pre,
18 | a,
19 | abbr,
20 | acronym,
21 | address,
22 | big,
23 | cite,
24 | code,
25 | del,
26 | dfn,
27 | em,
28 | img,
29 | ins,
30 | kbd,
31 | q,
32 | s,
33 | samp,
34 | small,
35 | strike,
36 | strong,
37 | sub,
38 | sup,
39 | tt,
40 | var,
41 | b,
42 | u,
43 | i,
44 | center,
45 | dl,
46 | dt,
47 | dd,
48 | ol,
49 | ul,
50 | li,
51 | fieldset,
52 | form,
53 | label,
54 | legend,
55 | table,
56 | caption,
57 | tbody,
58 | tfoot,
59 | thead,
60 | tr,
61 | th,
62 | td,
63 | article,
64 | aside,
65 | canvas,
66 | details,
67 | embed,
68 | figure,
69 | figcaption,
70 | footer,
71 | header,
72 | hgroup,
73 | menu,
74 | nav,
75 | output,
76 | ruby,
77 | section,
78 | summary,
79 | time,
80 | mark,
81 | audio,
82 | video {
83 | margin: 0;
84 | padding: 0;
85 | border: 0;
86 | font-size: 100%;
87 | font: inherit;
88 | vertical-align: baseline;
89 | }
90 | /* HTML5 display-role reset for older browsers */
91 | article,
92 | aside,
93 | details,
94 | figcaption,
95 | figure,
96 | footer,
97 | header,
98 | hgroup,
99 | menu,
100 | nav,
101 | section {
102 | display: block;
103 | }
104 | body {
105 | line-height: 1;
106 | }
107 | ol,
108 | ul {
109 | list-style: none;
110 | }
111 | blockquote,
112 | q {
113 | quotes: none;
114 | }
115 | blockquote:before,
116 | blockquote:after,
117 | q:before,
118 | q:after {
119 | content: '';
120 | content: none;
121 | }
122 | table {
123 | border-collapse: collapse;
124 | border-spacing: 0;
125 | }
126 |
--------------------------------------------------------------------------------
/web/src/redux/reducers/movies.js:
--------------------------------------------------------------------------------
1 | import * as Types from '../actions/MovieActionTypes';
2 |
3 | const initialState = {
4 | isFetchingFeatured: false,
5 | isFetchingByGenre: false,
6 | isFetching: false,
7 | featured: [],
8 | byGenre: {},
9 | detail: null
10 | };
11 |
12 | export default function movies(state = initialState, action) {
13 | switch (action.type) {
14 | case Types.MOVIES_FEATURED_GET_REQUEST:
15 | return {
16 | ...state,
17 | isFetchingFeatured: true,
18 | isFetching: true
19 | };
20 | case Types.MOVIES_FEATURED_GET_SUCCESS:
21 | return {
22 | ...state,
23 | isFetchingFeatured: false,
24 | isFetching: getIsFetching(false),
25 | featured: action.response
26 | };
27 | case Types.MOVIES_BY_GENRES_GET_REQUEST:
28 | return {
29 | ...state,
30 | isFetchingByGenre: true,
31 | isFetching: true
32 | };
33 | case Types.MOVIES_BY_GENRES_GET_SUCCESS:
34 | return {
35 | ...state,
36 | isFetchingByGenre: false,
37 | isFetching: getIsFetching(false),
38 | byGenre: action.response
39 | };
40 | case Types.MOVIE_DETAIL_GET_REQUEST:
41 | return {
42 | ...state,
43 | isFetching: true
44 | };
45 | case Types.MOVIE_DETAIL_GET_SUCCESS:
46 | return {
47 | ...state,
48 | isFetching: false,
49 | detail: action.response
50 | };
51 | case Types.MOVIE_DETAIL_CLEAR:
52 | return {
53 | ...state,
54 | detail: null
55 | };
56 | default:
57 | return state;
58 | }
59 | }
60 |
61 | function getIsFetching(state, isFetching) {
62 | return (state.isFetchingByGenre || state.isFetchingFeatured || isFetching);
63 | }
64 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/css/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */
2 | html,
3 | body,
4 | div,
5 | span,
6 | applet,
7 | object,
8 | iframe,
9 | h1,
10 | h2,
11 | h3,
12 | h4,
13 | h5,
14 | h6,
15 | p,
16 | blockquote,
17 | pre,
18 | a,
19 | abbr,
20 | acronym,
21 | address,
22 | big,
23 | cite,
24 | code,
25 | del,
26 | dfn,
27 | em,
28 | img,
29 | ins,
30 | kbd,
31 | q,
32 | s,
33 | samp,
34 | small,
35 | strike,
36 | strong,
37 | sub,
38 | sup,
39 | tt,
40 | var,
41 | b,
42 | u,
43 | i,
44 | center,
45 | dl,
46 | dt,
47 | dd,
48 | ol,
49 | ul,
50 | li,
51 | fieldset,
52 | form,
53 | label,
54 | legend,
55 | table,
56 | caption,
57 | tbody,
58 | tfoot,
59 | thead,
60 | tr,
61 | th,
62 | td,
63 | article,
64 | aside,
65 | canvas,
66 | details,
67 | embed,
68 | figure,
69 | figcaption,
70 | footer,
71 | header,
72 | hgroup,
73 | menu,
74 | nav,
75 | output,
76 | ruby,
77 | section,
78 | summary,
79 | time,
80 | mark,
81 | audio,
82 | video {
83 | margin: 0;
84 | padding: 0;
85 | border: 0;
86 | font-size: 100%;
87 | font: inherit;
88 | vertical-align: baseline;
89 | }
90 | /* HTML5 display-role reset for older browsers */
91 | article,
92 | aside,
93 | details,
94 | figcaption,
95 | figure,
96 | footer,
97 | header,
98 | hgroup,
99 | menu,
100 | nav,
101 | section {
102 | display: block;
103 | }
104 | body {
105 | line-height: 1;
106 | }
107 | ol,
108 | ul {
109 | list-style: none;
110 | }
111 | blockquote,
112 | q {
113 | quotes: none;
114 | }
115 | blockquote:before,
116 | blockquote:after,
117 | q:before,
118 | q:after {
119 | content: '';
120 | content: none;
121 | }
122 | table {
123 | border-collapse: collapse;
124 | border-spacing: 0;
125 | }
126 |
--------------------------------------------------------------------------------
/web/src/pages/AuthenticatedPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { withRouter } from 'react-router';
4 | import {connect} from 'react-redux';
5 |
6 | /**
7 | * Higher ordered component for pages requiring authentication.
8 | */
9 | var AuthenticatedPage = (PageComponent) => {
10 |
11 | class AuthenticatedPage extends React.Component {
12 |
13 | constructor() {
14 | super();
15 |
16 | this.redirectOnLogout = this.redirectOnLogout.bind(this);
17 | }
18 |
19 | componentWillMount() {
20 | var {auth, location, history} = this.props;
21 |
22 | if (!auth.token) {
23 | var query = {redirectTo: (location.pathname + location.search)};
24 | history.push({pathname: '/login', query});
25 | }
26 | }
27 |
28 | componentWillReceiveProps(nextProps) {
29 | this.redirectOnLogout(nextProps);
30 | }
31 |
32 | redirectOnLogout(props) {
33 | var {auth, location, history} = props;
34 |
35 | if (!auth.token && location.pathname !== '/login') {
36 | history.push('/login');
37 | }
38 | }
39 |
40 | render() {
41 | var {auth} = this.props;
42 | if (!auth.token) {
43 | return null;
44 | }
45 |
46 | return ();
47 | }
48 | }
49 |
50 | AuthenticatedPage.displayName = 'AuthenticatedPage';
51 | AuthenticatedPage.contextTypes = {
52 | router: PropTypes.object.isRequired
53 | };
54 |
55 | function mapStateToProps(state) {
56 | return {
57 | auth: state.auth
58 | };
59 | }
60 |
61 | // Wrap the component to inject dispatch and state into it
62 | return connect(mapStateToProps)(withRouter(AuthenticatedPage));
63 | };
64 |
65 | export default AuthenticatedPage;
66 |
67 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/scss/foundation/components/_inline-lists.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | @import 'global';
6 |
7 | //
8 | // @variables
9 | //
10 | $include-html-inline-list-classes: $include-html-classes !default;
11 |
12 | // We use this to control the margins and padding of the inline list.
13 | $inline-list-top-margin: 0 !default;
14 | $inline-list-opposite-margin: 0 !default;
15 | $inline-list-bottom-margin: rem-calc(17) !default;
16 | $inline-list-default-float-margin: rem-calc(-22) !default;
17 | $inline-list-default-float-list-margin: rem-calc(22) !default;
18 |
19 | $inline-list-padding: 0 !default;
20 |
21 | // We use this to control the overflow of the inline list.
22 | $inline-list-overflow: hidden !default;
23 |
24 | // We use this to control the list items
25 | $inline-list-display: block !default;
26 |
27 | // We use this to control any elements within list items
28 | $inline-list-children-display: block !default;
29 |
30 | //
31 | // @mixins
32 | //
33 | // We use this mixin to create inline lists
34 | @mixin inline-list {
35 | list-style: none;
36 | margin-top: $inline-list-top-margin;
37 | margin-bottom: $inline-list-bottom-margin;
38 | margin-#{$default-float}: $inline-list-default-float-margin;
39 | margin-#{$opposite-direction}: $inline-list-opposite-margin;
40 | overflow: $inline-list-overflow;
41 | padding: $inline-list-padding;
42 |
43 | > li {
44 | display: $inline-list-display;
45 | float: $default-float;
46 | list-style: none;
47 | margin-#{$default-float}: $inline-list-default-float-list-margin;
48 | > * { display: $inline-list-children-display; }
49 | }
50 | }
51 |
52 | @include exports("inline-list") {
53 | @if $include-html-inline-list-classes {
54 | .inline-list {
55 | @include inline-list();
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/web/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/web/src/pages/SignupStatus.jsx:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import {Link} from 'react-router-dom';
5 | import {createProfileInit} from '../redux/actions/ProfileActions';
6 | import {connect} from 'react-redux';
7 |
8 | class SignupStatus extends React.Component {
9 | componentWillMount() {
10 | var {profile} = this.props;
11 |
12 | if (!profile) {
13 | this.context.router.replace('/signup');
14 | }
15 | }
16 |
17 | componentWillUnmount() {
18 | this.props.dispatch(createProfileInit());
19 | }
20 |
21 | render() {
22 | var {profile} = this.props;
23 |
24 | return (
25 |
26 | {profile ?
27 |
28 |
29 |
30 |
Congratulations!
31 |
32 |
33 | {profile.name ?
34 |
35 | {profile.name},
36 |
37 | : null }
38 |
You have successfully created an account.
39 |
40 | Homepage
41 |
42 |
43 |
44 |
: null }
45 |
46 |
47 | );
48 | }
49 | }
50 |
51 | SignupStatus.displayName = 'SignupStatus';
52 | SignupStatus.contextTypes = {
53 | router: PropTypes.object.isRequired
54 | };
55 |
56 | function mapStateToProps(state) {
57 | return {
58 | profile: _.get(state.signup, 'savedProfile')
59 | };
60 | }
61 |
62 | export default connect(mapStateToProps)(SignupStatus);
63 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/scss/foundation.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | // Behold, here are all the Foundation components.
6 | @import 'foundation/components/grid';
7 | @import 'foundation/components/accordion';
8 | @import 'foundation/components/alert-boxes';
9 | @import 'foundation/components/block-grid';
10 | @import 'foundation/components/breadcrumbs';
11 | @import 'foundation/components/button-groups';
12 | @import 'foundation/components/buttons';
13 | @import 'foundation/components/clearing';
14 | @import 'foundation/components/dropdown';
15 | @import 'foundation/components/dropdown-buttons';
16 | @import 'foundation/components/flex-video';
17 | @import 'foundation/components/forms';
18 | @import 'foundation/components/icon-bar';
19 | @import 'foundation/components/inline-lists';
20 | @import 'foundation/components/joyride';
21 | @import 'foundation/components/keystrokes';
22 | @import 'foundation/components/labels';
23 | @import 'foundation/components/magellan';
24 | @import 'foundation/components/orbit';
25 | @import 'foundation/components/pagination';
26 | @import 'foundation/components/panels';
27 | @import 'foundation/components/pricing-tables';
28 | @import 'foundation/components/progress-bars';
29 | @import 'foundation/components/range-slider';
30 | @import 'foundation/components/reveal';
31 | @import 'foundation/components/side-nav';
32 | @import 'foundation/components/split-buttons';
33 | @import 'foundation/components/sub-nav';
34 | @import 'foundation/components/switches';
35 | @import 'foundation/components/tables';
36 | @import 'foundation/components/tabs';
37 | @import 'foundation/components/thumbs';
38 | @import 'foundation/components/tooltips';
39 | @import 'foundation/components/top-bar';
40 | @import 'foundation/components/type';
41 | @import 'foundation/components/offcanvas';
42 | @import 'foundation/components/visibility';
43 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/zh-cn.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"警告:已过时",
6 | "Implementation Notes":"实现备注",
7 | "Response Class":"响应类",
8 | "Status":"状态",
9 | "Parameters":"参数",
10 | "Parameter":"参数",
11 | "Value":"值",
12 | "Description":"描述",
13 | "Parameter Type":"参数类型",
14 | "Data Type":"数据类型",
15 | "Response Messages":"响应消息",
16 | "HTTP Status Code":"HTTP状态码",
17 | "Reason":"原因",
18 | "Response Model":"响应模型",
19 | "Request URL":"请求URL",
20 | "Response Body":"响应体",
21 | "Response Code":"响应码",
22 | "Response Headers":"响应头",
23 | "Hide Response":"隐藏响应",
24 | "Headers":"头",
25 | "Try it out!":"试一下!",
26 | "Show/Hide":"显示/隐藏",
27 | "List Operations":"显示操作",
28 | "Expand Operations":"展开操作",
29 | "Raw":"原始",
30 | "can't parse JSON. Raw result":"无法解析JSON. 原始结果",
31 | "Model Schema":"模型架构",
32 | "Model":"模型",
33 | "apply":"应用",
34 | "Username":"用户名",
35 | "Password":"密码",
36 | "Terms of service":"服务条款",
37 | "Created by":"创建者",
38 | "See more at":"查看更多:",
39 | "Contact the developer":"联系开发者",
40 | "api version":"api版本",
41 | "Response Content Type":"响应Content Type",
42 | "fetching resource":"正在获取资源",
43 | "fetching resource list":"正在获取资源列表",
44 | "Explore":"浏览",
45 | "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。",
47 | "Please specify the protocol for":"请指定协议:",
48 | "Can't read swagger JSON from":"无法读取swagger JSON于",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI",
50 | "Unable to read api":"无法读取api",
51 | "from path":"从路径",
52 | "server returned":"服务器返回"
53 | });
54 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/scss/foundation/components/_thumbs.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | @import 'global';
6 |
7 | //
8 | // @name _thumbs.scss
9 | // @dependencies _globals.scss
10 | //
11 |
12 | //
13 | // @variables
14 | //
15 |
16 | $include-html-media-classes: $include-html-classes !default;
17 |
18 | // We use these to control border styles
19 | $thumb-border-style: solid !default;
20 | $thumb-border-width: 4px !default;
21 | $thumb-border-color: $white !default;
22 | $thumb-box-shadow: 0 0 0 1px rgba($black,.2) !default;
23 | $thumb-box-shadow-hover: 0 0 6px 1px rgba($primary-color,0.5) !default;
24 |
25 | // Radius and transition speed for thumbs
26 | $thumb-radius: $global-radius !default;
27 | $thumb-transition-speed: 200ms !default;
28 |
29 | //
30 | // @mixins
31 | //
32 |
33 | // We use this to create image thumbnail styles.
34 | //
35 | // $border-width - Width of border around thumbnail. Default: $thumb-border-width.
36 | // $box-shadow - Box shadow to apply to thumbnail. Default: $thumb-box-shadow.
37 | // $box-shadow-hover - Box shadow to apply on hover. Default: $thumb-box-shadow-hover.
38 | @mixin thumb(
39 | $border-width:$thumb-border-width,
40 | $box-shadow:$thumb-box-shadow,
41 | $box-shadow-hover:$thumb-box-shadow-hover) {
42 | border: $thumb-border-style $border-width $thumb-border-color;
43 | box-shadow: $box-shadow;
44 | display: inline-block;
45 | line-height: 0;
46 | max-width: 100%;
47 |
48 | &:hover,
49 | &:focus {
50 | box-shadow: $box-shadow-hover;
51 | }
52 | }
53 |
54 |
55 | @include exports("thumb") {
56 | @if $include-html-media-classes {
57 |
58 | /* Image Thumbnails */
59 | .th {
60 | @include thumb;
61 | @include single-transition(all, $thumb-transition-speed, ease-out);
62 |
63 | &.radius { @include radius($thumb-radius); }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/zh-cn.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"警告:已过时",
6 | "Implementation Notes":"实现备注",
7 | "Response Class":"响应类",
8 | "Status":"状态",
9 | "Parameters":"参数",
10 | "Parameter":"参数",
11 | "Value":"值",
12 | "Description":"描述",
13 | "Parameter Type":"参数类型",
14 | "Data Type":"数据类型",
15 | "Response Messages":"响应消息",
16 | "HTTP Status Code":"HTTP状态码",
17 | "Reason":"原因",
18 | "Response Model":"响应模型",
19 | "Request URL":"请求URL",
20 | "Response Body":"响应体",
21 | "Response Code":"响应码",
22 | "Response Headers":"响应头",
23 | "Hide Response":"隐藏响应",
24 | "Headers":"头",
25 | "Try it out!":"试一下!",
26 | "Show/Hide":"显示/隐藏",
27 | "List Operations":"显示操作",
28 | "Expand Operations":"展开操作",
29 | "Raw":"原始",
30 | "can't parse JSON. Raw result":"无法解析JSON. 原始结果",
31 | "Model Schema":"模型架构",
32 | "Model":"模型",
33 | "apply":"应用",
34 | "Username":"用户名",
35 | "Password":"密码",
36 | "Terms of service":"服务条款",
37 | "Created by":"创建者",
38 | "See more at":"查看更多:",
39 | "Contact the developer":"联系开发者",
40 | "api version":"api版本",
41 | "Response Content Type":"响应Content Type",
42 | "fetching resource":"正在获取资源",
43 | "fetching resource list":"正在获取资源列表",
44 | "Explore":"浏览",
45 | "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。",
47 | "Please specify the protocol for":"请指定协议:",
48 | "Can't read swagger JSON from":"无法读取swagger JSON于",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI",
50 | "Unable to read api":"无法读取api",
51 | "from path":"从路径",
52 | "server returned":"服务器返回"
53 | });
54 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | import.report
2 | .DS_Store
3 | web/build
4 | web/bower_components
5 | web/node_modules
6 | web/package-lock.json
7 |
8 | api/node_modules
9 | api/config/settings.json
10 | *.pyc
11 | flask-api/venv
12 |
13 | database/*
14 |
15 | ### Vim template
16 | [._]*.s[a-w][a-z]
17 | [._]s[a-w][a-z]
18 | *.un~
19 | Session.vim
20 | .netrwhist
21 | *~
22 | ### JetBrains template
23 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
24 |
25 | *.iml
26 |
27 | ## Directory-based project format:
28 | .idea
29 | # if you remove the above rule, at least ignore the following:
30 |
31 | # User-specific stuff:
32 | # .idea/workspace.xml
33 | # .idea/tasks.xml
34 | # .idea/dictionaries
35 |
36 | # Sensitive or high-churn files:
37 | # .idea/dataSources.ids
38 | # .idea/dataSources.xml
39 | # .idea/sqlDataSources.xml
40 | # .idea/dynamic.xml
41 | # .idea/uiDesigner.xml
42 |
43 | # Gradle:
44 | # .idea/gradle.xml
45 | # .idea/libraries
46 |
47 | # Mongo Explorer plugin:
48 | # .idea/mongoSettings.xml
49 |
50 | ## File-based project format:
51 | *.ipr
52 | *.iws
53 |
54 | ## Plugin-specific files:
55 |
56 | # IntelliJ
57 | /out/
58 |
59 | # mpeltonen/sbt-idea plugin
60 | .idea_modules/
61 |
62 | # JIRA plugin
63 | atlassian-ide-plugin.xml
64 |
65 | # Crashlytics plugin (for Android Studio and IntelliJ)
66 | com_crashlytics_export_strings.xml
67 | crashlytics.properties
68 | crashlytics-build.properties
69 | ### SublimeText template
70 | # cache files for sublime text
71 | *.tmlanguage.cache
72 | *.tmPreferences.cache
73 | *.stTheme.cache
74 |
75 | # workspace files are user-specific
76 | *.sublime-workspace
77 |
78 | # project files should be checked into the repository, unless a significant
79 | # proportion of contributors will probably not be using SublimeText
80 | # *.sublime-project
81 |
82 | # sftp configuration file
83 | sftp-config.json
84 |
85 | # Created by .ignore support plugin (hsz.mobi)
86 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/ko-kr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"경고:폐기예정됨",
6 | "Implementation Notes":"구현 노트",
7 | "Response Class":"응답 클래스",
8 | "Status":"상태",
9 | "Parameters":"매개변수들",
10 | "Parameter":"매개변수",
11 | "Value":"값",
12 | "Description":"설명",
13 | "Parameter Type":"매개변수 타입",
14 | "Data Type":"데이터 타입",
15 | "Response Messages":"응답 메세지",
16 | "HTTP Status Code":"HTTP 상태 코드",
17 | "Reason":"원인",
18 | "Response Model":"응답 모델",
19 | "Request URL":"요청 URL",
20 | "Response Body":"응답 본문",
21 | "Response Code":"응답 코드",
22 | "Response Headers":"응답 헤더",
23 | "Hide Response":"응답 숨기기",
24 | "Headers":"헤더",
25 | "Try it out!":"써보기!",
26 | "Show/Hide":"보이기/숨기기",
27 | "List Operations":"목록 작업",
28 | "Expand Operations":"전개 작업",
29 | "Raw":"원본",
30 | "can't parse JSON. Raw result":"JSON을 파싱할수 없음. 원본결과:",
31 | "Model Schema":"모델 스키마",
32 | "Model":"모델",
33 | "apply":"적용",
34 | "Username":"사용자 이름",
35 | "Password":"암호",
36 | "Terms of service":"이용약관",
37 | "Created by":"작성자",
38 | "See more at":"추가정보:",
39 | "Contact the developer":"개발자에게 문의",
40 | "api version":"api버전",
41 | "Response Content Type":"응답Content Type",
42 | "fetching resource":"리소스 가져오기",
43 | "fetching resource list":"리소스 목록 가져오기",
44 | "Explore":"탐색",
45 | "Show Swagger Petstore Example Apis":"Swagger Petstore 예제 보기",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"서버로부터 읽어들일수 없습니다. access-control-origin 설정이 올바르지 않을수 있습니다.",
47 | "Please specify the protocol for":"다음을 위한 프로토콜을 정하세요",
48 | "Can't read swagger JSON from":"swagger JSON 을 다음으로 부터 읽을수 없습니다",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"리소스 정보 불러오기 완료. Swagger UI 랜더링",
50 | "Unable to read api":"api를 읽을 수 없습니다.",
51 | "from path":"다음 경로로 부터",
52 | "server returned":"서버 응답함."
53 | });
54 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/ko-kr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"경고:폐기예정됨",
6 | "Implementation Notes":"구현 노트",
7 | "Response Class":"응답 클래스",
8 | "Status":"상태",
9 | "Parameters":"매개변수들",
10 | "Parameter":"매개변수",
11 | "Value":"값",
12 | "Description":"설명",
13 | "Parameter Type":"매개변수 타입",
14 | "Data Type":"데이터 타입",
15 | "Response Messages":"응답 메세지",
16 | "HTTP Status Code":"HTTP 상태 코드",
17 | "Reason":"원인",
18 | "Response Model":"응답 모델",
19 | "Request URL":"요청 URL",
20 | "Response Body":"응답 본문",
21 | "Response Code":"응답 코드",
22 | "Response Headers":"응답 헤더",
23 | "Hide Response":"응답 숨기기",
24 | "Headers":"헤더",
25 | "Try it out!":"써보기!",
26 | "Show/Hide":"보이기/숨기기",
27 | "List Operations":"목록 작업",
28 | "Expand Operations":"전개 작업",
29 | "Raw":"원본",
30 | "can't parse JSON. Raw result":"JSON을 파싱할수 없음. 원본결과:",
31 | "Model Schema":"모델 스키마",
32 | "Model":"모델",
33 | "apply":"적용",
34 | "Username":"사용자 이름",
35 | "Password":"암호",
36 | "Terms of service":"이용약관",
37 | "Created by":"작성자",
38 | "See more at":"추가정보:",
39 | "Contact the developer":"개발자에게 문의",
40 | "api version":"api버전",
41 | "Response Content Type":"응답Content Type",
42 | "fetching resource":"리소스 가져오기",
43 | "fetching resource list":"리소스 목록 가져오기",
44 | "Explore":"탐색",
45 | "Show Swagger Petstore Example Apis":"Swagger Petstore 예제 보기",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"서버로부터 읽어들일수 없습니다. access-control-origin 설정이 올바르지 않을수 있습니다.",
47 | "Please specify the protocol for":"다음을 위한 프로토콜을 정하세요",
48 | "Can't read swagger JSON from":"swagger JSON 을 다음으로 부터 읽을수 없습니다",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"리소스 정보 불러오기 완료. Swagger UI 랜더링",
50 | "Unable to read api":"api를 읽을 수 없습니다.",
51 | "from path":"다음 경로로 부터",
52 | "server returned":"서버 응답함."
53 | });
54 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/ja.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"警告: 廃止予定",
6 | "Implementation Notes":"実装メモ",
7 | "Response Class":"レスポンスクラス",
8 | "Status":"ステータス",
9 | "Parameters":"パラメータ群",
10 | "Parameter":"パラメータ",
11 | "Value":"値",
12 | "Description":"説明",
13 | "Parameter Type":"パラメータタイプ",
14 | "Data Type":"データタイプ",
15 | "Response Messages":"レスポンスメッセージ",
16 | "HTTP Status Code":"HTTPステータスコード",
17 | "Reason":"理由",
18 | "Response Model":"レスポンスモデル",
19 | "Request URL":"リクエストURL",
20 | "Response Body":"レスポンスボディ",
21 | "Response Code":"レスポンスコード",
22 | "Response Headers":"レスポンスヘッダ",
23 | "Hide Response":"レスポンスを隠す",
24 | "Headers":"ヘッダ",
25 | "Try it out!":"実際に実行!",
26 | "Show/Hide":"表示/非表示",
27 | "List Operations":"操作一覧",
28 | "Expand Operations":"操作の展開",
29 | "Raw":"Raw",
30 | "can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果",
31 | "Model Schema":"モデルスキーマ",
32 | "Model":"モデル",
33 | "apply":"実行",
34 | "Username":"ユーザ名",
35 | "Password":"パスワード",
36 | "Terms of service":"サービス利用規約",
37 | "Created by":"Created by",
38 | "See more at":"See more at",
39 | "Contact the developer":"開発者に連絡",
40 | "api version":"APIバージョン",
41 | "Response Content Type":"レスポンス コンテンツタイプ",
42 | "fetching resource":"リソースの取得",
43 | "fetching resource list":"リソース一覧の取得",
44 | "Explore":"Explore",
45 | "Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.",
47 | "Please specify the protocol for":"プロトコルを指定してください",
48 | "Can't read swagger JSON from":"次からswagger JSONを読み込めません",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています",
50 | "Unable to read api":"APIを読み込めません",
51 | "from path":"次のパスから",
52 | "server returned":"サーバからの返答"
53 | });
54 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/ja.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"警告: 廃止予定",
6 | "Implementation Notes":"実装メモ",
7 | "Response Class":"レスポンスクラス",
8 | "Status":"ステータス",
9 | "Parameters":"パラメータ群",
10 | "Parameter":"パラメータ",
11 | "Value":"値",
12 | "Description":"説明",
13 | "Parameter Type":"パラメータタイプ",
14 | "Data Type":"データタイプ",
15 | "Response Messages":"レスポンスメッセージ",
16 | "HTTP Status Code":"HTTPステータスコード",
17 | "Reason":"理由",
18 | "Response Model":"レスポンスモデル",
19 | "Request URL":"リクエストURL",
20 | "Response Body":"レスポンスボディ",
21 | "Response Code":"レスポンスコード",
22 | "Response Headers":"レスポンスヘッダ",
23 | "Hide Response":"レスポンスを隠す",
24 | "Headers":"ヘッダ",
25 | "Try it out!":"実際に実行!",
26 | "Show/Hide":"表示/非表示",
27 | "List Operations":"操作一覧",
28 | "Expand Operations":"操作の展開",
29 | "Raw":"Raw",
30 | "can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果",
31 | "Model Schema":"モデルスキーマ",
32 | "Model":"モデル",
33 | "apply":"実行",
34 | "Username":"ユーザ名",
35 | "Password":"パスワード",
36 | "Terms of service":"サービス利用規約",
37 | "Created by":"Created by",
38 | "See more at":"See more at",
39 | "Contact the developer":"開発者に連絡",
40 | "api version":"APIバージョン",
41 | "Response Content Type":"レスポンス コンテンツタイプ",
42 | "fetching resource":"リソースの取得",
43 | "fetching resource list":"リソース一覧の取得",
44 | "Explore":"Explore",
45 | "Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.",
47 | "Please specify the protocol for":"プロトコルを指定してください",
48 | "Can't read swagger JSON from":"次からswagger JSONを読み込めません",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています",
50 | "Unable to read api":"APIを読み込めません",
51 | "from path":"次のパスから",
52 | "server returned":"サーバからの返答"
53 | });
54 |
--------------------------------------------------------------------------------
/web/src/components/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Link} from 'react-router-dom';
3 | import {logout} from '../redux/actions/AuthActions';
4 | import {connect} from 'react-redux';
5 | import _ from 'lodash';
6 | import logoImg from '../assets/logo.png';
7 |
8 | class Header extends React.Component {
9 | render() {
10 | var {props} = this;
11 | var profile = _.get(props, 'profile');
12 | var isLoggedIn = !!_.get(props, 'auth.token');
13 |
14 | return (
15 |
49 | );
50 | }
51 |
52 | getAvatarStyle(profile) {
53 | return {background: `url(${_.get(profile, 'avatar.fullSize')}) center`};
54 | }
55 |
56 | logout() {
57 | this.props.dispatch(logout());
58 | }
59 | }
60 |
61 | Header.displayName = 'Header';
62 |
63 | export default connect()(Header);
64 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/scss/foundation/components/_keystrokes.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | @import 'global';
6 |
7 | //
8 | // @variables
9 | //
10 | $include-html-keystroke-classes: $include-html-classes !default;
11 |
12 | // We use these to control text styles.
13 | $keystroke-font: "Consolas", "Menlo", "Courier", monospace !default;
14 | $keystroke-font-size: inherit !default;
15 | $keystroke-font-color: $jet !default;
16 | $keystroke-font-color-alt: $white !default;
17 | $keystroke-function-factor: -7% !default;
18 |
19 | // We use this to control keystroke padding.
20 | $keystroke-padding: rem-calc(2 4 0) !default;
21 |
22 | // We use these to control background and border styles.
23 | $keystroke-bg: scale-color($white, $lightness: $keystroke-function-factor) !default;
24 | $keystroke-border-style: solid !default;
25 | $keystroke-border-width: 1px !default;
26 | $keystroke-border-color: scale-color($keystroke-bg, $lightness: $keystroke-function-factor) !default;
27 | $keystroke-radius: $global-radius !default;
28 |
29 | //
30 | // @mixins
31 | //
32 | // We use this mixin to create keystroke styles.
33 | // $bg - Default: $keystroke-bg || scale-color($white, $lightness: $keystroke-function-factor) !default;
34 | @mixin keystroke($bg:$keystroke-bg) {
35 | // This find the lightness percentage of the background color.
36 | $bg-lightness: lightness($bg);
37 | background-color: $bg;
38 | border-color: scale-color($bg, $lightness: $keystroke-function-factor);
39 |
40 | // We adjust the font color based on the brightness of the background.
41 | @if $bg-lightness > 70% { color: $keystroke-font-color; }
42 | @else { color: $keystroke-font-color-alt; }
43 |
44 | border-style: $keystroke-border-style;
45 | border-width: $keystroke-border-width;
46 | font-family: $keystroke-font;
47 | font-size: $keystroke-font-size;
48 | margin: 0;
49 | padding: $keystroke-padding;
50 | }
51 |
52 | @include exports("keystroke") {
53 | @if $include-html-keystroke-classes {
54 | .keystroke,
55 | kbd {
56 | @include keystroke;
57 | @include radius($keystroke-radius);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/web/src/redux/actions/MovieActions.js:
--------------------------------------------------------------------------------
1 | import * as Types from './MovieActionTypes';
2 |
3 | export function clearMovie() {
4 | return {type: Types.MOVIE_DETAIL_CLEAR};
5 | }
6 |
7 | export function getGenres() {
8 | return {type: Types.MOVIE_GENRES_GET_REQUEST};
9 | }
10 |
11 | export function getGenresSuccess(genres) {
12 | return {type: Types.MOVIE_GENRES_GET_SUCCESS, genres};
13 | }
14 |
15 | export function getGenresFailure(error) {
16 | return {type: Types.MOVIE_GENRES_GET_FAILURE, error};
17 | }
18 |
19 | export function getMoviesByGenres(names) {
20 | return {type: Types.MOVIES_BY_GENRES_GET_REQUEST, names};
21 | }
22 |
23 | export function getMoviesByGenresSuccess(response) {
24 | return {type: Types.MOVIES_BY_GENRES_GET_SUCCESS, response};
25 | }
26 |
27 | export function getMoviesByGenresFailure(error) {
28 | return {type: Types.MOVIES_BY_GENRES_GET_FAILURE, error};
29 | }
30 |
31 | export function getFeaturedMovies() {
32 | return {type: Types.MOVIES_FEATURED_GET_REQUEST};
33 | }
34 |
35 | export function getFeaturedMoviesSuccess(response) {
36 | return {type: Types.MOVIES_FEATURED_GET_SUCCESS, response};
37 | }
38 |
39 | export function getFeaturedMoviesFailure(error) {
40 | return {type: Types.MOVIES_FEATURED_GET_FAILURE, error};
41 | }
42 |
43 | export function getMovie(id) {
44 | return {type: Types.MOVIE_DETAIL_GET_REQUEST, id};
45 | }
46 |
47 | export function getMovieSuccess(response) {
48 | return {type: Types.MOVIE_DETAIL_GET_SUCCESS, response};
49 | }
50 |
51 | export function getMovieFailure(error) {
52 | return {type: Types.MOVIE_DETAIL_GET_FAILURE, error};
53 | }
54 |
55 | export function rateMovie(id, rating) {
56 | return {type: Types.MOVIE_RATE, id, rating};
57 | }
58 |
59 | export function rateMovieSuccess() {
60 | return {type: Types.MOVIE_RATE_SUCCESS};
61 | }
62 |
63 | export function rateMovieFailure() {
64 | return {type: Types.MOVIE_RATE_FAILURE};
65 | }
66 |
67 | export function deleteMovieRating(id) {
68 | return {type: Types.MOVIE_DELETE_RATING, id};
69 | }
70 |
71 | export function deleteMovieRatingSuccess() {
72 | return {type: Types.MOVIE_DELETE_RATING_SUCCESS};
73 | }
74 |
75 | export function deleteMovieRatingFailure() {
76 | return {type: Types.MOVIE_DELETE_RATING_FAILURE};
77 | }
78 |
--------------------------------------------------------------------------------
/web/src/redux/actions/ProfileActions.js:
--------------------------------------------------------------------------------
1 | import * as Types from './ProfileActionTypes';
2 |
3 | export function getProfile() {
4 | return {type: Types.PROFILE_GET};
5 | }
6 |
7 | export function getProfileSuccess(payload) {
8 | return {type: Types.PROFILE_GET_SUCCESS, payload};
9 | }
10 |
11 | export function getProfileFailure(error) {
12 | return {type: Types.PROFILE_GET_FAILURE, error};
13 | }
14 |
15 | export function createProfile(payload) {
16 | return {type: Types.PROFILE_CREATE, payload};
17 | }
18 |
19 | export function createProfileSuccess(payload) {
20 | return {type: Types.PROFILE_CREATE_SUCCESS, payload};
21 | }
22 |
23 | export function createProfileFailure(error) {
24 | return {type: Types.PROFILE_CREATE_FAILURE, error};
25 | }
26 |
27 | export function createProfileInit() {
28 | return {type: Types.PROFILE_CREATE_INIT};
29 | }
30 |
31 | export function getProfileRatings() {
32 | return {type: Types.PROFILE_GET_RATINGS};
33 | }
34 |
35 | export function getProfileRatingsSuccess(payload) {
36 | return {type: Types.PROFILE_GET_RATINGS_SUCCESS, payload};
37 | }
38 |
39 | export function getProfileRatingsFailure() {
40 | return {type: Types.PROFILE_GET_RATINGS_FAILURE};
41 | }
42 |
43 | export function profileRateMovie(id, rating) {
44 | return {type: Types.PROFILE_MOVIE_RATE, id, rating};
45 | }
46 |
47 | export function profileRateMovieSuccess() {
48 | return {type: Types.PROFILE_MOVIE_RATE_SUCCESS};
49 | }
50 |
51 | export function profileRateMovieFailure() {
52 | return {type: Types.PROFILE_MOVIE_RATE_FAILURE};
53 | }
54 |
55 | export function profileDeleteMovieRating(id) {
56 | return {type: Types.PROFILE_MOVIE_DELETE_RATING, id};
57 | }
58 |
59 | export function profileDeleteMovieRatingSuccess() {
60 | return {type: Types.PROFILE_MOVIE_DELETE_RATING_SUCCESS};
61 | }
62 |
63 | export function profileDeleteMovieRatingFailure() {
64 | return {type: Types.PROFILE_MOVIE_DELETE_RATING_FAILURE};
65 | }
66 |
67 | export function getProfileRecommendations(id) {
68 | return {type: Types.PROFILE_GET_RECOMMENDATIONS, id};
69 | }
70 |
71 | export function getProfileRecommendationsSuccess(payload) {
72 | return {type: Types.PROFILE_GET_RECOMMENDATIONS_SUCCESS, payload};
73 | }
74 |
75 | export function getProfileRecommendationsFailure() {
76 | return {type: Types.PROFILE_GET_RECOMMENDATIONS_FAILURE};
77 | }
78 |
--------------------------------------------------------------------------------
/web/src/redux/sagas/profileFlow.js:
--------------------------------------------------------------------------------
1 | import {all, call, put, takeEvery} from 'redux-saga/effects';
2 | import ProfileApi from '../../api/ProfileApi';
3 | import MoviesApi from '../../api/MoviesApi';
4 | import * as Actions from '../actions/ProfileActions';
5 | import * as Types from '../actions/ProfileActionTypes';
6 |
7 | export default function* profileFlow() {
8 | yield all([
9 | takeEvery(Types.PROFILE_GET, getProfile),
10 | takeEvery(Types.PROFILE_GET_RATINGS, getProfileRatings),
11 | takeEvery(Types.PROFILE_MOVIE_RATE, profileRateMovie),
12 | takeEvery(Types.PROFILE_MOVIE_DELETE_RATING, profileDeleteRating),
13 | takeEvery(Types.PROFILE_GET_RECOMMENDATIONS, getProfileRecommendations)
14 | ]);
15 | }
16 |
17 | function* getProfile() {
18 | try {
19 | const response = yield call(ProfileApi.getProfile);
20 | yield put(Actions.getProfileSuccess(response));
21 | }
22 | catch (error) {
23 | yield put(Actions.getProfileFailure(error));
24 | }
25 | }
26 |
27 | function* getProfileRatings() {
28 | try {
29 | const response = yield call(ProfileApi.getProfileRatings);
30 | yield put(Actions.getProfileRatingsSuccess(response));
31 | }
32 | catch (error) {
33 | yield put(Actions.getProfileRatingsFailure(error));
34 | }
35 | }
36 |
37 | function* profileRateMovie(action) {
38 | var {id, rating} = action;
39 | try {
40 | const response = yield call(MoviesApi.rateMovie, id, rating);
41 | yield put(Actions.profileRateMovieSuccess(response));
42 | yield put(Actions.getProfileRatings());
43 | }
44 | catch (error) {
45 | yield put(Actions.profileRateMovieFailure(error));
46 | }
47 | }
48 |
49 | function* profileDeleteRating(action) {
50 | var {id} = action;
51 | try {
52 | const response = yield call(MoviesApi.deleteRating, id);
53 | yield put(Actions.profileDeleteMovieRatingSuccess(response));
54 | yield put(Actions.getProfileRatings());
55 | }
56 | catch (error) {
57 | yield put(Actions.profileDeleteMovieRatingFailure(error));
58 | }
59 | }
60 |
61 | function* getProfileRecommendations() {
62 | try {
63 | const response = yield call(ProfileApi.getProfileRecommendations);
64 | yield put(Actions.getProfileRecommendationsSuccess(response));
65 | }
66 | catch (error) {
67 | yield put(Actions.getProfileRecommendationsFailure(error));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/tr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Uyarı: Deprecated",
6 | "Implementation Notes":"Gerçekleştirim Notları",
7 | "Response Class":"Dönen Sınıf",
8 | "Status":"Statü",
9 | "Parameters":"Parametreler",
10 | "Parameter":"Parametre",
11 | "Value":"Değer",
12 | "Description":"Açıklama",
13 | "Parameter Type":"Parametre Tipi",
14 | "Data Type":"Veri Tipi",
15 | "Response Messages":"Dönüş Mesajı",
16 | "HTTP Status Code":"HTTP Statü Kodu",
17 | "Reason":"Gerekçe",
18 | "Response Model":"Dönüş Modeli",
19 | "Request URL":"İstek URL",
20 | "Response Body":"Dönüş İçeriği",
21 | "Response Code":"Dönüş Kodu",
22 | "Response Headers":"Dönüş Üst Bilgileri",
23 | "Hide Response":"Dönüşü Gizle",
24 | "Headers":"Üst Bilgiler",
25 | "Try it out!":"Dene!",
26 | "Show/Hide":"Göster/Gizle",
27 | "List Operations":"Operasyonları Listele",
28 | "Expand Operations":"Operasyonları Aç",
29 | "Raw":"Ham",
30 | "can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç",
31 | "Model Schema":"Model Şema",
32 | "Model":"Model",
33 | "apply":"uygula",
34 | "Username":"Kullanıcı Adı",
35 | "Password":"Parola",
36 | "Terms of service":"Servis şartları",
37 | "Created by":"Oluşturan",
38 | "See more at":"Daha fazlası için",
39 | "Contact the developer":"Geliştirici ile İletişime Geçin",
40 | "api version":"api versiyon",
41 | "Response Content Type":"Dönüş İçerik Tipi",
42 | "fetching resource":"kaynak getiriliyor",
43 | "fetching resource list":"kaynak listesi getiriliyor",
44 | "Explore":"Keşfet",
45 | "Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.",
47 | "Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz",
48 | "Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor",
50 | "Unable to read api":"api okunamadı",
51 | "from path":"yoldan",
52 | "server returned":"sunucuya dönüldü"
53 | });
54 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/tr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Uyarı: Deprecated",
6 | "Implementation Notes":"Gerçekleştirim Notları",
7 | "Response Class":"Dönen Sınıf",
8 | "Status":"Statü",
9 | "Parameters":"Parametreler",
10 | "Parameter":"Parametre",
11 | "Value":"Değer",
12 | "Description":"Açıklama",
13 | "Parameter Type":"Parametre Tipi",
14 | "Data Type":"Veri Tipi",
15 | "Response Messages":"Dönüş Mesajı",
16 | "HTTP Status Code":"HTTP Statü Kodu",
17 | "Reason":"Gerekçe",
18 | "Response Model":"Dönüş Modeli",
19 | "Request URL":"İstek URL",
20 | "Response Body":"Dönüş İçeriği",
21 | "Response Code":"Dönüş Kodu",
22 | "Response Headers":"Dönüş Üst Bilgileri",
23 | "Hide Response":"Dönüşü Gizle",
24 | "Headers":"Üst Bilgiler",
25 | "Try it out!":"Dene!",
26 | "Show/Hide":"Göster/Gizle",
27 | "List Operations":"Operasyonları Listele",
28 | "Expand Operations":"Operasyonları Aç",
29 | "Raw":"Ham",
30 | "can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç",
31 | "Model Schema":"Model Şema",
32 | "Model":"Model",
33 | "apply":"uygula",
34 | "Username":"Kullanıcı Adı",
35 | "Password":"Parola",
36 | "Terms of service":"Servis şartları",
37 | "Created by":"Oluşturan",
38 | "See more at":"Daha fazlası için",
39 | "Contact the developer":"Geliştirici ile İletişime Geçin",
40 | "api version":"api versiyon",
41 | "Response Content Type":"Dönüş İçerik Tipi",
42 | "fetching resource":"kaynak getiriliyor",
43 | "fetching resource list":"kaynak listesi getiriliyor",
44 | "Explore":"Keşfet",
45 | "Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.",
47 | "Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz",
48 | "Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor",
50 | "Unable to read api":"api okunamadı",
51 | "from path":"yoldan",
52 | "server returned":"sunucuya dönüldü"
53 | });
54 |
--------------------------------------------------------------------------------
/web/src/components/Carousel.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Carousel extends React.Component {
4 | constructor() {
5 | super();
6 |
7 | this.state = {
8 | startIndex: 0,
9 | visibleCount: 0
10 | };
11 |
12 | this.onWidthChange = this.onWidthChange.bind(this);
13 | }
14 |
15 | componentDidMount() {
16 | if (matchMedia) {
17 | var mq = window.matchMedia('(max-width: 600px)');
18 | mq.addListener(this.onWidthChange);
19 | this.onWidthChange(mq);
20 | }
21 | }
22 |
23 | onWidthChange(mq) {
24 | if (mq.matches) {
25 | this.setState({visibleCount: 2});
26 | } else {
27 | this.setState({visibleCount: 5});
28 | }
29 | }
30 |
31 | render() {
32 | var {children} = this.props;
33 | var {startIndex, visibleCount} = this.state;
34 |
35 | return (
36 |
37 |
40 |
43 |
44 | {
45 | React.Children.map(children, (c, i) => {
46 | var style = {
47 | width: (100 / visibleCount).toFixed(0) + '%',
48 | display: (i >= startIndex && i - startIndex < visibleCount) ? 'inline-block' : 'none'
49 | };
50 |
51 | return (
52 | -
53 | {c}
54 |
);
55 | })
56 | }
57 |
58 |
59 | );
60 | }
61 |
62 | onRightClick(e) {
63 | e.preventDefault();
64 | var {startIndex, visibleCount} = this.state;
65 |
66 | if(startIndex + visibleCount < React.Children.count(this.props.children)) {
67 | this.setState({startIndex: startIndex + 1});
68 | }
69 | }
70 |
71 | onLeftClick(e) {
72 | e.preventDefault();
73 | var {startIndex} = this.state;
74 |
75 | if (startIndex > 0) {
76 | this.setState({startIndex: startIndex - 1});
77 | }
78 | }
79 | }
80 |
81 | Carousel.displayName = 'Carousel';
82 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/pl.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Uwaga: Wycofane",
6 | "Implementation Notes":"Uwagi Implementacji",
7 | "Response Class":"Klasa Odpowiedzi",
8 | "Status":"Status",
9 | "Parameters":"Parametry",
10 | "Parameter":"Parametr",
11 | "Value":"Wartość",
12 | "Description":"Opis",
13 | "Parameter Type":"Typ Parametru",
14 | "Data Type":"Typ Danych",
15 | "Response Messages":"Wiadomości Odpowiedzi",
16 | "HTTP Status Code":"Kod Statusu HTTP",
17 | "Reason":"Przyczyna",
18 | "Response Model":"Model Odpowiedzi",
19 | "Request URL":"URL Wywołania",
20 | "Response Body":"Treść Odpowiedzi",
21 | "Response Code":"Kod Odpowiedzi",
22 | "Response Headers":"Nagłówki Odpowiedzi",
23 | "Hide Response":"Ukryj Odpowiedź",
24 | "Headers":"Nagłówki",
25 | "Try it out!":"Wypróbuj!",
26 | "Show/Hide":"Pokaż/Ukryj",
27 | "List Operations":"Lista Operacji",
28 | "Expand Operations":"Rozwiń Operacje",
29 | "Raw":"Nieprzetworzone",
30 | "can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane",
31 | "Model Schema":"Schemat Modelu",
32 | "Model":"Model",
33 | "apply":"użyj",
34 | "Username":"Nazwa użytkownika",
35 | "Password":"Hasło",
36 | "Terms of service":"Warunki używania",
37 | "Created by":"Utworzone przez",
38 | "See more at":"Zobacz więcej na",
39 | "Contact the developer":"Kontakt z deweloperem",
40 | "api version":"wersja api",
41 | "Response Content Type":"Typ Zasobu Odpowiedzi",
42 | "fetching resource":"ładowanie zasobu",
43 | "fetching resource list":"ładowanie listy zasobów",
44 | "Explore":"Eksploruj",
45 | "Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.",
47 | "Please specify the protocol for":"Proszę podać protokół dla",
48 | "Can't read swagger JSON from":"Nie można odczytać swagger JSON z",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI",
50 | "Unable to read api":"Nie można odczytać api",
51 | "from path":"ze ścieżki",
52 | "server returned":"serwer zwrócił"
53 | });
54 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/pl.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Uwaga: Wycofane",
6 | "Implementation Notes":"Uwagi Implementacji",
7 | "Response Class":"Klasa Odpowiedzi",
8 | "Status":"Status",
9 | "Parameters":"Parametry",
10 | "Parameter":"Parametr",
11 | "Value":"Wartość",
12 | "Description":"Opis",
13 | "Parameter Type":"Typ Parametru",
14 | "Data Type":"Typ Danych",
15 | "Response Messages":"Wiadomości Odpowiedzi",
16 | "HTTP Status Code":"Kod Statusu HTTP",
17 | "Reason":"Przyczyna",
18 | "Response Model":"Model Odpowiedzi",
19 | "Request URL":"URL Wywołania",
20 | "Response Body":"Treść Odpowiedzi",
21 | "Response Code":"Kod Odpowiedzi",
22 | "Response Headers":"Nagłówki Odpowiedzi",
23 | "Hide Response":"Ukryj Odpowiedź",
24 | "Headers":"Nagłówki",
25 | "Try it out!":"Wypróbuj!",
26 | "Show/Hide":"Pokaż/Ukryj",
27 | "List Operations":"Lista Operacji",
28 | "Expand Operations":"Rozwiń Operacje",
29 | "Raw":"Nieprzetworzone",
30 | "can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane",
31 | "Model Schema":"Schemat Modelu",
32 | "Model":"Model",
33 | "apply":"użyj",
34 | "Username":"Nazwa użytkownika",
35 | "Password":"Hasło",
36 | "Terms of service":"Warunki używania",
37 | "Created by":"Utworzone przez",
38 | "See more at":"Zobacz więcej na",
39 | "Contact the developer":"Kontakt z deweloperem",
40 | "api version":"wersja api",
41 | "Response Content Type":"Typ Zasobu Odpowiedzi",
42 | "fetching resource":"ładowanie zasobu",
43 | "fetching resource list":"ładowanie listy zasobów",
44 | "Explore":"Eksploruj",
45 | "Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.",
47 | "Please specify the protocol for":"Proszę podać protokół dla",
48 | "Can't read swagger JSON from":"Nie można odczytać swagger JSON z",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI",
50 | "Unable to read api":"Nie można odczytać api",
51 | "from path":"ze ścieżki",
52 | "server returned":"serwer zwrócił"
53 | });
54 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/pt.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Aviso: Depreciado",
6 | "Implementation Notes":"Notas de Implementação",
7 | "Response Class":"Classe de resposta",
8 | "Status":"Status",
9 | "Parameters":"Parâmetros",
10 | "Parameter":"Parâmetro",
11 | "Value":"Valor",
12 | "Description":"Descrição",
13 | "Parameter Type":"Tipo de parâmetro",
14 | "Data Type":"Tipo de dados",
15 | "Response Messages":"Mensagens de resposta",
16 | "HTTP Status Code":"Código de status HTTP",
17 | "Reason":"Razão",
18 | "Response Model":"Modelo resposta",
19 | "Request URL":"URL requisição",
20 | "Response Body":"Corpo da resposta",
21 | "Response Code":"Código da resposta",
22 | "Response Headers":"Cabeçalho da resposta",
23 | "Headers":"Cabeçalhos",
24 | "Hide Response":"Esconder resposta",
25 | "Try it out!":"Tente agora!",
26 | "Show/Hide":"Mostrar/Esconder",
27 | "List Operations":"Listar operações",
28 | "Expand Operations":"Expandir operações",
29 | "Raw":"Cru",
30 | "can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru",
31 | "Model Schema":"Modelo esquema",
32 | "Model":"Modelo",
33 | "apply":"Aplicar",
34 | "Username":"Usuário",
35 | "Password":"Senha",
36 | "Terms of service":"Termos do serviço",
37 | "Created by":"Criado por",
38 | "See more at":"Veja mais em",
39 | "Contact the developer":"Contate o desenvolvedor",
40 | "api version":"Versão api",
41 | "Response Content Type":"Tipo de conteúdo da resposta",
42 | "fetching resource":"busca recurso",
43 | "fetching resource list":"buscando lista de recursos",
44 | "Explore":"Explorar",
45 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin",
47 | "Please specify the protocol for":"Por favor especifique o protocolo",
48 | "Can't read swagger JSON from":"Não é possível ler o JSON Swagger de",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI",
50 | "Unable to read api":"Não foi possível ler api",
51 | "from path":"do caminho",
52 | "server returned":"servidor retornou"
53 | });
54 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/pt.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Aviso: Depreciado",
6 | "Implementation Notes":"Notas de Implementação",
7 | "Response Class":"Classe de resposta",
8 | "Status":"Status",
9 | "Parameters":"Parâmetros",
10 | "Parameter":"Parâmetro",
11 | "Value":"Valor",
12 | "Description":"Descrição",
13 | "Parameter Type":"Tipo de parâmetro",
14 | "Data Type":"Tipo de dados",
15 | "Response Messages":"Mensagens de resposta",
16 | "HTTP Status Code":"Código de status HTTP",
17 | "Reason":"Razão",
18 | "Response Model":"Modelo resposta",
19 | "Request URL":"URL requisição",
20 | "Response Body":"Corpo da resposta",
21 | "Response Code":"Código da resposta",
22 | "Response Headers":"Cabeçalho da resposta",
23 | "Headers":"Cabeçalhos",
24 | "Hide Response":"Esconder resposta",
25 | "Try it out!":"Tente agora!",
26 | "Show/Hide":"Mostrar/Esconder",
27 | "List Operations":"Listar operações",
28 | "Expand Operations":"Expandir operações",
29 | "Raw":"Cru",
30 | "can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru",
31 | "Model Schema":"Modelo esquema",
32 | "Model":"Modelo",
33 | "apply":"Aplicar",
34 | "Username":"Usuário",
35 | "Password":"Senha",
36 | "Terms of service":"Termos do serviço",
37 | "Created by":"Criado por",
38 | "See more at":"Veja mais em",
39 | "Contact the developer":"Contate o desenvolvedor",
40 | "api version":"Versão api",
41 | "Response Content Type":"Tipo de conteúdo da resposta",
42 | "fetching resource":"busca recurso",
43 | "fetching resource list":"buscando lista de recursos",
44 | "Explore":"Explorar",
45 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin",
47 | "Please specify the protocol for":"Por favor especifique o protocolo",
48 | "Can't read swagger JSON from":"Não é possível ler o JSON Swagger de",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI",
50 | "Unable to read api":"Não foi possível ler api",
51 | "from path":"do caminho",
52 | "server returned":"servidor retornou"
53 | });
54 |
--------------------------------------------------------------------------------
/web/src/components/validation/ValidatedComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import _ from 'lodash'
3 |
4 | /**
5 | * A higher ordered component containing boilerplate code for handling validation of internal input fields.
6 | *
7 | * About higher order components:
8 | * It's a way of implementing mixin-like enhancements for React components (mixins are not possible with ES6 and they have other issues)
9 | * Check here for more: https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750
10 | */
11 | export const ValidatorContext = React.createContext({
12 | registerValidator: () => {},
13 | unregisterValidator: () => {},
14 | })
15 |
16 | const ValidatedComponent = ComposedComponent => {
17 | class ValidatedComponent extends React.Component {
18 | constructor() {
19 | super()
20 | this.validators = []
21 | }
22 |
23 | getValidationFormProps() {
24 | return {
25 | isComponentValid: this.isValid.bind(this),
26 | getValidationMessages: this.getValidationMessages.bind(this),
27 | }
28 | }
29 |
30 | getFieldValidatorContext() {
31 | return {
32 | registerValidator: this.onRegisterValidator.bind(this),
33 | unregisterValidator: this.onUnregisterValidator.bind(this),
34 | }
35 | }
36 |
37 | onRegisterValidator(validator) {
38 | this.validators.push(validator)
39 | }
40 |
41 | onUnregisterValidator(owner) {
42 | _.remove(this.validators, {owner})
43 | }
44 |
45 | isValid() {
46 | let isValid = true
47 | this.validators.forEach(v => {
48 | v.owner.validate()
49 | isValid = isValid && v.owner.isValid()
50 | })
51 | return isValid
52 | }
53 |
54 | getValidationMessages() {
55 | const results = []
56 | this.validators.forEach(v => {
57 | const message = v.owner.getValidationMessage()
58 | if (message) {
59 | results.push(message)
60 | }
61 | })
62 |
63 | return results
64 | }
65 |
66 | render() {
67 | const newProps = {...this.props, ...this.getValidationFormProps()}
68 | return (
69 |
70 |
71 |
72 | )
73 | }
74 | }
75 |
76 | ValidatedComponent.displayName = 'ValidatedComponent'
77 |
78 | return ValidatedComponent
79 | }
80 |
81 | export default ValidatedComponent
82 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/en.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Warning: Deprecated",
6 | "Implementation Notes":"Implementation Notes",
7 | "Response Class":"Response Class",
8 | "Status":"Status",
9 | "Parameters":"Parameters",
10 | "Parameter":"Parameter",
11 | "Value":"Value",
12 | "Description":"Description",
13 | "Parameter Type":"Parameter Type",
14 | "Data Type":"Data Type",
15 | "Response Messages":"Response Messages",
16 | "HTTP Status Code":"HTTP Status Code",
17 | "Reason":"Reason",
18 | "Response Model":"Response Model",
19 | "Request URL":"Request URL",
20 | "Response Body":"Response Body",
21 | "Response Code":"Response Code",
22 | "Response Headers":"Response Headers",
23 | "Hide Response":"Hide Response",
24 | "Headers":"Headers",
25 | "Try it out!":"Try it out!",
26 | "Show/Hide":"Show/Hide",
27 | "List Operations":"List Operations",
28 | "Expand Operations":"Expand Operations",
29 | "Raw":"Raw",
30 | "can't parse JSON. Raw result":"can't parse JSON. Raw result",
31 | "Example Value":"Example Value",
32 | "Model Schema":"Model Schema",
33 | "Model":"Model",
34 | "Click to set as parameter value":"Click to set as parameter value",
35 | "apply":"apply",
36 | "Username":"Username",
37 | "Password":"Password",
38 | "Terms of service":"Terms of service",
39 | "Created by":"Created by",
40 | "See more at":"See more at",
41 | "Contact the developer":"Contact the developer",
42 | "api version":"api version",
43 | "Response Content Type":"Response Content Type",
44 | "Parameter content type:":"Parameter content type:",
45 | "fetching resource":"fetching resource",
46 | "fetching resource list":"fetching resource list",
47 | "Explore":"Explore",
48 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.",
50 | "Please specify the protocol for":"Please specify the protocol for",
51 | "Can't read swagger JSON from":"Can't read swagger JSON from",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI",
53 | "Unable to read api":"Unable to read api",
54 | "from path":"from path",
55 | "server returned":"server returned"
56 | });
57 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/en.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Warning: Deprecated",
6 | "Implementation Notes":"Implementation Notes",
7 | "Response Class":"Response Class",
8 | "Status":"Status",
9 | "Parameters":"Parameters",
10 | "Parameter":"Parameter",
11 | "Value":"Value",
12 | "Description":"Description",
13 | "Parameter Type":"Parameter Type",
14 | "Data Type":"Data Type",
15 | "Response Messages":"Response Messages",
16 | "HTTP Status Code":"HTTP Status Code",
17 | "Reason":"Reason",
18 | "Response Model":"Response Model",
19 | "Request URL":"Request URL",
20 | "Response Body":"Response Body",
21 | "Response Code":"Response Code",
22 | "Response Headers":"Response Headers",
23 | "Hide Response":"Hide Response",
24 | "Headers":"Headers",
25 | "Try it out!":"Try it out!",
26 | "Show/Hide":"Show/Hide",
27 | "List Operations":"List Operations",
28 | "Expand Operations":"Expand Operations",
29 | "Raw":"Raw",
30 | "can't parse JSON. Raw result":"can't parse JSON. Raw result",
31 | "Example Value":"Example Value",
32 | "Model Schema":"Model Schema",
33 | "Model":"Model",
34 | "Click to set as parameter value":"Click to set as parameter value",
35 | "apply":"apply",
36 | "Username":"Username",
37 | "Password":"Password",
38 | "Terms of service":"Terms of service",
39 | "Created by":"Created by",
40 | "See more at":"See more at",
41 | "Contact the developer":"Contact the developer",
42 | "api version":"api version",
43 | "Response Content Type":"Response Content Type",
44 | "Parameter content type:":"Parameter content type:",
45 | "fetching resource":"fetching resource",
46 | "fetching resource list":"fetching resource list",
47 | "Explore":"Explore",
48 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.",
50 | "Please specify the protocol for":"Please specify the protocol for",
51 | "Can't read swagger JSON from":"Can't read swagger JSON from",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI",
53 | "Unable to read api":"Unable to read api",
54 | "from path":"from path",
55 | "server returned":"server returned"
56 | });
57 |
--------------------------------------------------------------------------------
/web/src/redux/sagas/movieFlow.js:
--------------------------------------------------------------------------------
1 | import {all, call, put, takeEvery} from 'redux-saga/effects';
2 | import MoviesApi from '../../api/MoviesApi';
3 | import * as Actions from '../actions/MovieActions';
4 | import * as Types from '../actions/MovieActionTypes';
5 |
6 | export default function* movieFlow() {
7 | yield all([
8 | takeEvery(Types.MOVIE_GENRES_GET_REQUEST, getGenres),
9 | takeEvery(Types.MOVIES_BY_GENRES_GET_REQUEST, getMoviesByGenre),
10 | takeEvery(Types.MOVIES_FEATURED_GET_REQUEST, getFeaturedMovies),
11 | takeEvery(Types.MOVIE_DETAIL_GET_REQUEST, getMovie),
12 | takeEvery(Types.MOVIE_RATE, rateMovie),
13 | takeEvery(Types.MOVIE_DELETE_RATING, deleteRating),
14 | ]);
15 | }
16 |
17 | function* getGenres() {
18 | try {
19 | const response = yield call(MoviesApi.getGenres);
20 | yield put(Actions.getGenresSuccess(response));
21 | }
22 | catch (error) {
23 | yield put(Actions.getGenresFailure(error));
24 | }
25 | }
26 |
27 | function* getMoviesByGenre(action) {
28 | var {names} = action;
29 | try {
30 | const response = yield call(MoviesApi.getMoviesByGenres, names);
31 | yield put(Actions.getMoviesByGenresSuccess(response));
32 | }
33 | catch (error) {
34 | yield put(Actions.getMoviesByGenresFailure(error));
35 | }
36 | }
37 |
38 | function* getFeaturedMovies() {
39 | try {
40 | const response = yield call(MoviesApi.getFeaturedMovies);
41 | yield put(Actions.getFeaturedMoviesSuccess(response));
42 | }
43 | catch (error) {
44 | yield put(Actions.getFeaturedMoviesFailure(error));
45 | }
46 | }
47 |
48 | function* getMovie(action) {
49 | var {id} = action;
50 | try {
51 | const response = yield call(MoviesApi.getMovie, id);
52 | yield put(Actions.getMovieSuccess(response));
53 | }
54 | catch (error) {
55 | yield put(Actions.getMovieFailure(error));
56 | }
57 | }
58 |
59 | function* rateMovie(action) {
60 | var {id, rating} = action;
61 | try {
62 | const response = yield call(MoviesApi.rateMovie, id, rating);
63 | yield put(Actions.rateMovieSuccess(response));
64 | yield put(Actions.getMovie(id));
65 | }
66 | catch (error) {
67 | yield put(Actions.rateMovieFailure(error));
68 | }
69 | }
70 |
71 | function* deleteRating(action) {
72 | var {id} = action;
73 | try {
74 | const response = yield call(MoviesApi.deleteRating, id);
75 | yield put(Actions.deleteMovieRatingSuccess(response));
76 | yield put(Actions.getMovie(id));
77 | }
78 | catch (error) {
79 | yield put(Actions.deleteMovieRatingFailure(error));
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/ru.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Предупреждение: Устарело",
6 | "Implementation Notes":"Заметки",
7 | "Response Class":"Пример ответа",
8 | "Status":"Статус",
9 | "Parameters":"Параметры",
10 | "Parameter":"Параметр",
11 | "Value":"Значение",
12 | "Description":"Описание",
13 | "Parameter Type":"Тип параметра",
14 | "Data Type":"Тип данных",
15 | "HTTP Status Code":"HTTP код",
16 | "Reason":"Причина",
17 | "Response Model":"Структура ответа",
18 | "Request URL":"URL запроса",
19 | "Response Body":"Тело ответа",
20 | "Response Code":"HTTP код ответа",
21 | "Response Headers":"Заголовки ответа",
22 | "Hide Response":"Спрятать ответ",
23 | "Headers":"Заголовки",
24 | "Response Messages":"Что может прийти в ответ",
25 | "Try it out!":"Попробовать!",
26 | "Show/Hide":"Показать/Скрыть",
27 | "List Operations":"Операции кратко",
28 | "Expand Operations":"Операции подробно",
29 | "Raw":"В сыром виде",
30 | "can't parse JSON. Raw result":"Не удается распарсить ответ:",
31 | "Example Value":"Пример",
32 | "Model Schema":"Структура",
33 | "Model":"Описание",
34 | "Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра",
35 | "apply":"применить",
36 | "Username":"Имя пользователя",
37 | "Password":"Пароль",
38 | "Terms of service":"Условия использования",
39 | "Created by":"Разработано",
40 | "See more at":"Еще тут",
41 | "Contact the developer":"Связаться с разработчиком",
42 | "api version":"Версия API",
43 | "Response Content Type":"Content Type ответа",
44 | "Parameter content type:":"Content Type параметра:",
45 | "fetching resource":"Получение ресурса",
46 | "fetching resource list":"Получение ресурсов",
47 | "Explore":"Показать",
48 | "Show Swagger Petstore Example Apis":"Показать примеры АПИ",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа",
50 | "Please specify the protocol for":"Пожалуйста, укажите протокол для",
51 | "Can't read swagger JSON from":"Не получается прочитать swagger json из",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим",
53 | "Unable to read api":"Не удалось прочитать api",
54 | "from path":"по адресу",
55 | "server returned":"сервер сказал"
56 | });
57 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/ca.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Advertència: Obsolet",
6 | "Implementation Notes":"Notes d'implementació",
7 | "Response Class":"Classe de la Resposta",
8 | "Status":"Estatus",
9 | "Parameters":"Paràmetres",
10 | "Parameter":"Paràmetre",
11 | "Value":"Valor",
12 | "Description":"Descripció",
13 | "Parameter Type":"Tipus del Paràmetre",
14 | "Data Type":"Tipus de la Dada",
15 | "Response Messages":"Missatges de la Resposta",
16 | "HTTP Status Code":"Codi d'Estatus HTTP",
17 | "Reason":"Raó",
18 | "Response Model":"Model de la Resposta",
19 | "Request URL":"URL de la Sol·licitud",
20 | "Response Body":"Cos de la Resposta",
21 | "Response Code":"Codi de la Resposta",
22 | "Response Headers":"Capçaleres de la Resposta",
23 | "Hide Response":"Amagar Resposta",
24 | "Try it out!":"Prova-ho!",
25 | "Show/Hide":"Mostrar/Amagar",
26 | "List Operations":"Llista Operacions",
27 | "Expand Operations":"Expandir Operacions",
28 | "Raw":"Cru",
29 | "can't parse JSON. Raw result":"no puc analitzar el JSON. Resultat cru",
30 | "Example Value":"Valor d'Exemple",
31 | "Model Schema":"Esquema del Model",
32 | "Model":"Model",
33 | "apply":"aplicar",
34 | "Username":"Nom d'usuari",
35 | "Password":"Contrasenya",
36 | "Terms of service":"Termes del servei",
37 | "Created by":"Creat per",
38 | "See more at":"Veure més en",
39 | "Contact the developer":"Contactar amb el desenvolupador",
40 | "api version":"versió de la api",
41 | "Response Content Type":"Tipus de Contingut de la Resposta",
42 | "fetching resource":"recollint recurs",
43 | "fetching resource list":"recollins llista de recursos",
44 | "Explore":"Explorant",
45 | "Show Swagger Petstore Example Apis":"Mostrar API d'Exemple Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No es pot llegir del servidor. Potser no teniu la configuració de control d'accés apropiada.",
47 | "Please specify the protocol for":"Si us plau, especifiqueu el protocol per a",
48 | "Can't read swagger JSON from":"No es pot llegir el JSON de swagger des de",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalitzada la càrrega del recurs informatiu. Renderitzant Swagger UI",
50 | "Unable to read api":"No es pot llegir l'api",
51 | "from path":"des de la ruta",
52 | "server returned":"el servidor ha retornat"
53 | });
54 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/ru.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Предупреждение: Устарело",
6 | "Implementation Notes":"Заметки",
7 | "Response Class":"Пример ответа",
8 | "Status":"Статус",
9 | "Parameters":"Параметры",
10 | "Parameter":"Параметр",
11 | "Value":"Значение",
12 | "Description":"Описание",
13 | "Parameter Type":"Тип параметра",
14 | "Data Type":"Тип данных",
15 | "HTTP Status Code":"HTTP код",
16 | "Reason":"Причина",
17 | "Response Model":"Структура ответа",
18 | "Request URL":"URL запроса",
19 | "Response Body":"Тело ответа",
20 | "Response Code":"HTTP код ответа",
21 | "Response Headers":"Заголовки ответа",
22 | "Hide Response":"Спрятать ответ",
23 | "Headers":"Заголовки",
24 | "Response Messages":"Что может прийти в ответ",
25 | "Try it out!":"Попробовать!",
26 | "Show/Hide":"Показать/Скрыть",
27 | "List Operations":"Операции кратко",
28 | "Expand Operations":"Операции подробно",
29 | "Raw":"В сыром виде",
30 | "can't parse JSON. Raw result":"Не удается распарсить ответ:",
31 | "Example Value":"Пример",
32 | "Model Schema":"Структура",
33 | "Model":"Описание",
34 | "Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра",
35 | "apply":"применить",
36 | "Username":"Имя пользователя",
37 | "Password":"Пароль",
38 | "Terms of service":"Условия использования",
39 | "Created by":"Разработано",
40 | "See more at":"Еще тут",
41 | "Contact the developer":"Связаться с разработчиком",
42 | "api version":"Версия API",
43 | "Response Content Type":"Content Type ответа",
44 | "Parameter content type:":"Content Type параметра:",
45 | "fetching resource":"Получение ресурса",
46 | "fetching resource list":"Получение ресурсов",
47 | "Explore":"Показать",
48 | "Show Swagger Petstore Example Apis":"Показать примеры АПИ",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа",
50 | "Please specify the protocol for":"Пожалуйста, укажите протокол для",
51 | "Can't read swagger JSON from":"Не получается прочитать swagger json из",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим",
53 | "Unable to read api":"Не удалось прочитать api",
54 | "from path":"по адресу",
55 | "server returned":"сервер сказал"
56 | });
57 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/ca.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Advertència: Obsolet",
6 | "Implementation Notes":"Notes d'implementació",
7 | "Response Class":"Classe de la Resposta",
8 | "Status":"Estatus",
9 | "Parameters":"Paràmetres",
10 | "Parameter":"Paràmetre",
11 | "Value":"Valor",
12 | "Description":"Descripció",
13 | "Parameter Type":"Tipus del Paràmetre",
14 | "Data Type":"Tipus de la Dada",
15 | "Response Messages":"Missatges de la Resposta",
16 | "HTTP Status Code":"Codi d'Estatus HTTP",
17 | "Reason":"Raó",
18 | "Response Model":"Model de la Resposta",
19 | "Request URL":"URL de la Sol·licitud",
20 | "Response Body":"Cos de la Resposta",
21 | "Response Code":"Codi de la Resposta",
22 | "Response Headers":"Capçaleres de la Resposta",
23 | "Hide Response":"Amagar Resposta",
24 | "Try it out!":"Prova-ho!",
25 | "Show/Hide":"Mostrar/Amagar",
26 | "List Operations":"Llista Operacions",
27 | "Expand Operations":"Expandir Operacions",
28 | "Raw":"Cru",
29 | "can't parse JSON. Raw result":"no puc analitzar el JSON. Resultat cru",
30 | "Example Value":"Valor d'Exemple",
31 | "Model Schema":"Esquema del Model",
32 | "Model":"Model",
33 | "apply":"aplicar",
34 | "Username":"Nom d'usuari",
35 | "Password":"Contrasenya",
36 | "Terms of service":"Termes del servei",
37 | "Created by":"Creat per",
38 | "See more at":"Veure més en",
39 | "Contact the developer":"Contactar amb el desenvolupador",
40 | "api version":"versió de la api",
41 | "Response Content Type":"Tipus de Contingut de la Resposta",
42 | "fetching resource":"recollint recurs",
43 | "fetching resource list":"recollins llista de recursos",
44 | "Explore":"Explorant",
45 | "Show Swagger Petstore Example Apis":"Mostrar API d'Exemple Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No es pot llegir del servidor. Potser no teniu la configuració de control d'accés apropiada.",
47 | "Please specify the protocol for":"Si us plau, especifiqueu el protocol per a",
48 | "Can't read swagger JSON from":"No es pot llegir el JSON de swagger des de",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalitzada la càrrega del recurs informatiu. Renderitzant Swagger UI",
50 | "Unable to read api":"No es pot llegir l'api",
51 | "from path":"des de la ruta",
52 | "server returned":"el servidor ha retornat"
53 | });
54 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/geo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"ყურადღება: აღარ გამოიყენება",
6 | "Implementation Notes":"იმპლემენტაციის აღწერა",
7 | "Response Class":"რესპონს კლასი",
8 | "Status":"სტატუსი",
9 | "Parameters":"პარამეტრები",
10 | "Parameter":"პარამეტრი",
11 | "Value":"მნიშვნელობა",
12 | "Description":"აღწერა",
13 | "Parameter Type":"პარამეტრის ტიპი",
14 | "Data Type":"მონაცემის ტიპი",
15 | "Response Messages":"პასუხი",
16 | "HTTP Status Code":"HTTP სტატუსი",
17 | "Reason":"მიზეზი",
18 | "Response Model":"რესპონს მოდელი",
19 | "Request URL":"მოთხოვნის URL",
20 | "Response Body":"პასუხის სხეული",
21 | "Response Code":"პასუხის კოდი",
22 | "Response Headers":"პასუხის ჰედერები",
23 | "Hide Response":"დამალე პასუხი",
24 | "Headers":"ჰედერები",
25 | "Try it out!":"ცადე !",
26 | "Show/Hide":"გამოჩენა/დამალვა",
27 | "List Operations":"ოპერაციების სია",
28 | "Expand Operations":"ოპერაციები ვრცლად",
29 | "Raw":"ნედლი",
30 | "can't parse JSON. Raw result":"JSON-ის დამუშავება ვერ მოხერხდა. ნედლი პასუხი",
31 | "Example Value":"მაგალითი",
32 | "Model Schema":"მოდელის სტრუქტურა",
33 | "Model":"მოდელი",
34 | "Click to set as parameter value":"პარამეტრისთვის მნიშვნელობის მისანიჭებლად, დააკლიკე",
35 | "apply":"გამოყენება",
36 | "Username":"მოხმარებელი",
37 | "Password":"პაროლი",
38 | "Terms of service":"მომსახურების პირობები",
39 | "Created by":"შექმნა",
40 | "See more at":"ნახე ვრცლად",
41 | "Contact the developer":"დაუკავშირდი დეველოპერს",
42 | "api version":"api ვერსია",
43 | "Response Content Type":"პასუხის კონტენტის ტიპი",
44 | "Parameter content type:":"პარამეტრის კონტენტის ტიპი:",
45 | "fetching resource":"რესურსების მიღება",
46 | "fetching resource list":"რესურსების სიის მიღება",
47 | "Explore":"ნახვა",
48 | "Show Swagger Petstore Example Apis":"ნახე Swagger Petstore სამაგალითო Api",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"სერვერთან დაკავშირება ვერ ხერხდება. შეამოწმეთ access-control-origin.",
50 | "Please specify the protocol for":"მიუთითეთ პროტოკოლი",
51 | "Can't read swagger JSON from":"swagger JSON წაკითხვა ვერ მოხერხდა",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"რესურსების ჩატვირთვა სრულდება. Swagger UI რენდერდება",
53 | "Unable to read api":"api წაკითხვა ვერ მოხერხდა",
54 | "from path":"მისამართიდან",
55 | "server returned":"სერვერმა დააბრუნა"
56 | });
57 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/geo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"ყურადღება: აღარ გამოიყენება",
6 | "Implementation Notes":"იმპლემენტაციის აღწერა",
7 | "Response Class":"რესპონს კლასი",
8 | "Status":"სტატუსი",
9 | "Parameters":"პარამეტრები",
10 | "Parameter":"პარამეტრი",
11 | "Value":"მნიშვნელობა",
12 | "Description":"აღწერა",
13 | "Parameter Type":"პარამეტრის ტიპი",
14 | "Data Type":"მონაცემის ტიპი",
15 | "Response Messages":"პასუხი",
16 | "HTTP Status Code":"HTTP სტატუსი",
17 | "Reason":"მიზეზი",
18 | "Response Model":"რესპონს მოდელი",
19 | "Request URL":"მოთხოვნის URL",
20 | "Response Body":"პასუხის სხეული",
21 | "Response Code":"პასუხის კოდი",
22 | "Response Headers":"პასუხის ჰედერები",
23 | "Hide Response":"დამალე პასუხი",
24 | "Headers":"ჰედერები",
25 | "Try it out!":"ცადე !",
26 | "Show/Hide":"გამოჩენა/დამალვა",
27 | "List Operations":"ოპერაციების სია",
28 | "Expand Operations":"ოპერაციები ვრცლად",
29 | "Raw":"ნედლი",
30 | "can't parse JSON. Raw result":"JSON-ის დამუშავება ვერ მოხერხდა. ნედლი პასუხი",
31 | "Example Value":"მაგალითი",
32 | "Model Schema":"მოდელის სტრუქტურა",
33 | "Model":"მოდელი",
34 | "Click to set as parameter value":"პარამეტრისთვის მნიშვნელობის მისანიჭებლად, დააკლიკე",
35 | "apply":"გამოყენება",
36 | "Username":"მოხმარებელი",
37 | "Password":"პაროლი",
38 | "Terms of service":"მომსახურების პირობები",
39 | "Created by":"შექმნა",
40 | "See more at":"ნახე ვრცლად",
41 | "Contact the developer":"დაუკავშირდი დეველოპერს",
42 | "api version":"api ვერსია",
43 | "Response Content Type":"პასუხის კონტენტის ტიპი",
44 | "Parameter content type:":"პარამეტრის კონტენტის ტიპი:",
45 | "fetching resource":"რესურსების მიღება",
46 | "fetching resource list":"რესურსების სიის მიღება",
47 | "Explore":"ნახვა",
48 | "Show Swagger Petstore Example Apis":"ნახე Swagger Petstore სამაგალითო Api",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"სერვერთან დაკავშირება ვერ ხერხდება. შეამოწმეთ access-control-origin.",
50 | "Please specify the protocol for":"მიუთითეთ პროტოკოლი",
51 | "Can't read swagger JSON from":"swagger JSON წაკითხვა ვერ მოხერხდა",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"რესურსების ჩატვირთვა სრულდება. Swagger UI რენდერდება",
53 | "Unable to read api":"api წაკითხვა ვერ მოხერხდა",
54 | "from path":"მისამართიდან",
55 | "server returned":"სერვერმა დააბრუნა"
56 | });
57 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/it.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Attenzione: Deprecato",
6 | "Implementation Notes":"Note di implementazione",
7 | "Response Class":"Classe della risposta",
8 | "Status":"Stato",
9 | "Parameters":"Parametri",
10 | "Parameter":"Parametro",
11 | "Value":"Valore",
12 | "Description":"Descrizione",
13 | "Parameter Type":"Tipo di parametro",
14 | "Data Type":"Tipo di dato",
15 | "Response Messages":"Messaggi della risposta",
16 | "HTTP Status Code":"Codice stato HTTP",
17 | "Reason":"Motivo",
18 | "Response Model":"Modello di risposta",
19 | "Request URL":"URL della richiesta",
20 | "Response Body":"Corpo della risposta",
21 | "Response Code":"Oggetto della risposta",
22 | "Response Headers":"Intestazioni della risposta",
23 | "Hide Response":"Nascondi risposta",
24 | "Try it out!":"Provalo!",
25 | "Show/Hide":"Mostra/Nascondi",
26 | "List Operations":"Mostra operazioni",
27 | "Expand Operations":"Espandi operazioni",
28 | "Raw":"Grezzo (raw)",
29 | "can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).",
30 | "Model Schema":"Schema del modello",
31 | "Model":"Modello",
32 | "apply":"applica",
33 | "Username":"Nome utente",
34 | "Password":"Password",
35 | "Terms of service":"Condizioni del servizio",
36 | "Created by":"Creato da",
37 | "See more at":"Informazioni aggiuntive:",
38 | "Contact the developer":"Contatta lo sviluppatore",
39 | "api version":"versione api",
40 | "Response Content Type":"Tipo di contenuto (content type) della risposta",
41 | "fetching resource":"recuperando la risorsa",
42 | "fetching resource list":"recuperando lista risorse",
43 | "Explore":"Esplora",
44 | "Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore",
45 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.",
46 | "Please specify the protocol for":"Si prega di specificare il protocollo per",
47 | "Can't read swagger JSON from":"Impossibile leggere JSON swagger da:",
48 | "Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata",
49 | "Unable to read api":"Impossibile leggere la api",
50 | "from path":"da cartella",
51 | "server returned":"il server ha restituito"
52 | });
53 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/it.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Attenzione: Deprecato",
6 | "Implementation Notes":"Note di implementazione",
7 | "Response Class":"Classe della risposta",
8 | "Status":"Stato",
9 | "Parameters":"Parametri",
10 | "Parameter":"Parametro",
11 | "Value":"Valore",
12 | "Description":"Descrizione",
13 | "Parameter Type":"Tipo di parametro",
14 | "Data Type":"Tipo di dato",
15 | "Response Messages":"Messaggi della risposta",
16 | "HTTP Status Code":"Codice stato HTTP",
17 | "Reason":"Motivo",
18 | "Response Model":"Modello di risposta",
19 | "Request URL":"URL della richiesta",
20 | "Response Body":"Corpo della risposta",
21 | "Response Code":"Oggetto della risposta",
22 | "Response Headers":"Intestazioni della risposta",
23 | "Hide Response":"Nascondi risposta",
24 | "Try it out!":"Provalo!",
25 | "Show/Hide":"Mostra/Nascondi",
26 | "List Operations":"Mostra operazioni",
27 | "Expand Operations":"Espandi operazioni",
28 | "Raw":"Grezzo (raw)",
29 | "can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).",
30 | "Model Schema":"Schema del modello",
31 | "Model":"Modello",
32 | "apply":"applica",
33 | "Username":"Nome utente",
34 | "Password":"Password",
35 | "Terms of service":"Condizioni del servizio",
36 | "Created by":"Creato da",
37 | "See more at":"Informazioni aggiuntive:",
38 | "Contact the developer":"Contatta lo sviluppatore",
39 | "api version":"versione api",
40 | "Response Content Type":"Tipo di contenuto (content type) della risposta",
41 | "fetching resource":"recuperando la risorsa",
42 | "fetching resource list":"recuperando lista risorse",
43 | "Explore":"Esplora",
44 | "Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore",
45 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.",
46 | "Please specify the protocol for":"Si prega di specificare il protocollo per",
47 | "Can't read swagger JSON from":"Impossibile leggere JSON swagger da:",
48 | "Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata",
49 | "Unable to read api":"Impossibile leggere la api",
50 | "from path":"da cartella",
51 | "server returned":"il server ha restituito"
52 | });
53 |
--------------------------------------------------------------------------------
/api/models/users.js:
--------------------------------------------------------------------------------
1 | "use strict"
2 |
3 | const uuid = require('node-uuid');
4 | const randomstring = require("randomstring");
5 | const _ = require('lodash');
6 | const dbUtils = require('../neo4j/dbUtils');
7 | const User = require('../models/neo4j/user');
8 | const crypto = require('crypto');
9 |
10 | const register = function (session, username, password) {
11 | return session.readTransaction(txc => txc.run('MATCH (user:User {username: $username}) RETURN user', {username: username}))
12 | .then(results => {
13 | if (!_.isEmpty(results.records)) {
14 | throw {username: 'username already in use', status: 400}
15 | }
16 | else {
17 | return session.writeTransaction(txc => txc.run('CREATE (user:User {id: $id, username: $username, password: $password, api_key: $api_key}) RETURN user',
18 | {
19 | id: uuid.v4(),
20 | username: username,
21 | password: hashPassword(username, password),
22 | api_key: randomstring.generate({
23 | length: 20,
24 | charset: 'hex'
25 | })
26 | }
27 | )).then(results => {
28 | return new User(results.records[0].get('user'));
29 | }
30 | )
31 | }
32 | });
33 | };
34 |
35 | const me = function (session, apiKey) {
36 | return session.readTransaction(txc => txc.run('MATCH (user:User {api_key: $api_key}) RETURN user', {api_key: apiKey}))
37 | .then(results => {
38 | if (_.isEmpty(results.records)) {
39 | throw {message: 'invalid authorization key', status: 401};
40 | }
41 | return new User(results.records[0].get('user'));
42 | });
43 | };
44 |
45 | const login = function (session, username, password) {
46 | return session.readTransaction(txc => txc.run('MATCH (user:User {username: $username}) RETURN user', {username: username}))
47 | .then(results => {
48 | if (_.isEmpty(results.records)) {
49 | throw {username: 'username does not exist', status: 400}
50 | }
51 | else {
52 | const dbUser = _.get(results.records[0].get('user'), 'properties');
53 | if (dbUser.password != hashPassword(username, password)) {
54 | throw {password: 'wrong password', status: 400}
55 | }
56 | return {token: _.get(dbUser, 'api_key')};
57 | }
58 | }
59 | );
60 | };
61 |
62 | function hashPassword(username, password) {
63 | const s = username + ':' + password;
64 | return crypto.createHash('sha256').update(s).digest('hex');
65 | }
66 |
67 | module.exports = {
68 | register: register,
69 | me: me,
70 | login: login
71 | };
72 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/es.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Advertencia: Obsoleto",
6 | "Implementation Notes":"Notas de implementación",
7 | "Response Class":"Clase de la Respuesta",
8 | "Status":"Status",
9 | "Parameters":"Parámetros",
10 | "Parameter":"Parámetro",
11 | "Value":"Valor",
12 | "Description":"Descripción",
13 | "Parameter Type":"Tipo del Parámetro",
14 | "Data Type":"Tipo del Dato",
15 | "Response Messages":"Mensajes de la Respuesta",
16 | "HTTP Status Code":"Código de Status HTTP",
17 | "Reason":"Razón",
18 | "Response Model":"Modelo de la Respuesta",
19 | "Request URL":"URL de la Solicitud",
20 | "Response Body":"Cuerpo de la Respuesta",
21 | "Response Code":"Código de la Respuesta",
22 | "Response Headers":"Encabezados de la Respuesta",
23 | "Hide Response":"Ocultar Respuesta",
24 | "Try it out!":"Pruébalo!",
25 | "Show/Hide":"Mostrar/Ocultar",
26 | "List Operations":"Listar Operaciones",
27 | "Expand Operations":"Expandir Operaciones",
28 | "Raw":"Crudo",
29 | "can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo",
30 | "Example Value":"Valor de Ejemplo",
31 | "Model Schema":"Esquema del Modelo",
32 | "Model":"Modelo",
33 | "apply":"aplicar",
34 | "Username":"Nombre de usuario",
35 | "Password":"Contraseña",
36 | "Terms of service":"Términos de Servicio",
37 | "Created by":"Creado por",
38 | "See more at":"Ver más en",
39 | "Contact the developer":"Contactar al desarrollador",
40 | "api version":"versión de la api",
41 | "Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta",
42 | "fetching resource":"buscando recurso",
43 | "fetching resource list":"buscando lista del recurso",
44 | "Explore":"Explorar",
45 | "Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.",
47 | "Please specify the protocol for":"Por favor, especificar el protocola para",
48 | "Can't read swagger JSON from":"No se puede leer el JSON de swagger desde",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI",
50 | "Unable to read api":"No se puede leer la api",
51 | "from path":"desde ruta",
52 | "server returned":"el servidor retornó"
53 | });
54 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/es.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Advertencia: Obsoleto",
6 | "Implementation Notes":"Notas de implementación",
7 | "Response Class":"Clase de la Respuesta",
8 | "Status":"Status",
9 | "Parameters":"Parámetros",
10 | "Parameter":"Parámetro",
11 | "Value":"Valor",
12 | "Description":"Descripción",
13 | "Parameter Type":"Tipo del Parámetro",
14 | "Data Type":"Tipo del Dato",
15 | "Response Messages":"Mensajes de la Respuesta",
16 | "HTTP Status Code":"Código de Status HTTP",
17 | "Reason":"Razón",
18 | "Response Model":"Modelo de la Respuesta",
19 | "Request URL":"URL de la Solicitud",
20 | "Response Body":"Cuerpo de la Respuesta",
21 | "Response Code":"Código de la Respuesta",
22 | "Response Headers":"Encabezados de la Respuesta",
23 | "Hide Response":"Ocultar Respuesta",
24 | "Try it out!":"Pruébalo!",
25 | "Show/Hide":"Mostrar/Ocultar",
26 | "List Operations":"Listar Operaciones",
27 | "Expand Operations":"Expandir Operaciones",
28 | "Raw":"Crudo",
29 | "can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo",
30 | "Example Value":"Valor de Ejemplo",
31 | "Model Schema":"Esquema del Modelo",
32 | "Model":"Modelo",
33 | "apply":"aplicar",
34 | "Username":"Nombre de usuario",
35 | "Password":"Contraseña",
36 | "Terms of service":"Términos de Servicio",
37 | "Created by":"Creado por",
38 | "See more at":"Ver más en",
39 | "Contact the developer":"Contactar al desarrollador",
40 | "api version":"versión de la api",
41 | "Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta",
42 | "fetching resource":"buscando recurso",
43 | "fetching resource list":"buscando lista del recurso",
44 | "Explore":"Explorar",
45 | "Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.",
47 | "Please specify the protocol for":"Por favor, especificar el protocola para",
48 | "Can't read swagger JSON from":"No se puede leer el JSON de swagger desde",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI",
50 | "Unable to read api":"No se puede leer la api",
51 | "from path":"desde ruta",
52 | "server returned":"el servidor retornó"
53 | });
54 |
--------------------------------------------------------------------------------
/api/swaggerui/lang/fr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Avertissement : Obsolète",
6 | "Implementation Notes":"Notes d'implémentation",
7 | "Response Class":"Classe de la réponse",
8 | "Status":"Statut",
9 | "Parameters":"Paramètres",
10 | "Parameter":"Paramètre",
11 | "Value":"Valeur",
12 | "Description":"Description",
13 | "Parameter Type":"Type du paramètre",
14 | "Data Type":"Type de données",
15 | "Response Messages":"Messages de la réponse",
16 | "HTTP Status Code":"Code de statut HTTP",
17 | "Reason":"Raison",
18 | "Response Model":"Modèle de réponse",
19 | "Request URL":"URL appelée",
20 | "Response Body":"Corps de la réponse",
21 | "Response Code":"Code de la réponse",
22 | "Response Headers":"En-têtes de la réponse",
23 | "Hide Response":"Cacher la réponse",
24 | "Headers":"En-têtes",
25 | "Try it out!":"Testez !",
26 | "Show/Hide":"Afficher/Masquer",
27 | "List Operations":"Liste des opérations",
28 | "Expand Operations":"Développer les opérations",
29 | "Raw":"Brut",
30 | "can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut",
31 | "Example Value":"Exemple la valeur",
32 | "Model Schema":"Définition du modèle",
33 | "Model":"Modèle",
34 | "apply":"appliquer",
35 | "Username":"Nom d'utilisateur",
36 | "Password":"Mot de passe",
37 | "Terms of service":"Conditions de service",
38 | "Created by":"Créé par",
39 | "See more at":"Voir plus sur",
40 | "Contact the developer":"Contacter le développeur",
41 | "api version":"version de l'api",
42 | "Response Content Type":"Content Type de la réponse",
43 | "fetching resource":"récupération de la ressource",
44 | "fetching resource list":"récupération de la liste de ressources",
45 | "Explore":"Explorer",
46 | "Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger",
47 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.",
48 | "Please specify the protocol for":"Veuillez spécifier un protocole pour",
49 | "Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de",
50 | "Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI",
51 | "Unable to read api":"Impossible de lire l'api",
52 | "from path":"à partir du chemin",
53 | "server returned":"réponse du serveur"
54 | });
55 |
--------------------------------------------------------------------------------
/flask-api/swaggerui/lang/fr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Avertissement : Obsolète",
6 | "Implementation Notes":"Notes d'implémentation",
7 | "Response Class":"Classe de la réponse",
8 | "Status":"Statut",
9 | "Parameters":"Paramètres",
10 | "Parameter":"Paramètre",
11 | "Value":"Valeur",
12 | "Description":"Description",
13 | "Parameter Type":"Type du paramètre",
14 | "Data Type":"Type de données",
15 | "Response Messages":"Messages de la réponse",
16 | "HTTP Status Code":"Code de statut HTTP",
17 | "Reason":"Raison",
18 | "Response Model":"Modèle de réponse",
19 | "Request URL":"URL appelée",
20 | "Response Body":"Corps de la réponse",
21 | "Response Code":"Code de la réponse",
22 | "Response Headers":"En-têtes de la réponse",
23 | "Hide Response":"Cacher la réponse",
24 | "Headers":"En-têtes",
25 | "Try it out!":"Testez !",
26 | "Show/Hide":"Afficher/Masquer",
27 | "List Operations":"Liste des opérations",
28 | "Expand Operations":"Développer les opérations",
29 | "Raw":"Brut",
30 | "can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut",
31 | "Example Value":"Exemple la valeur",
32 | "Model Schema":"Définition du modèle",
33 | "Model":"Modèle",
34 | "apply":"appliquer",
35 | "Username":"Nom d'utilisateur",
36 | "Password":"Mot de passe",
37 | "Terms of service":"Conditions de service",
38 | "Created by":"Créé par",
39 | "See more at":"Voir plus sur",
40 | "Contact the developer":"Contacter le développeur",
41 | "api version":"version de l'api",
42 | "Response Content Type":"Content Type de la réponse",
43 | "fetching resource":"récupération de la ressource",
44 | "fetching resource list":"récupération de la liste de ressources",
45 | "Explore":"Explorer",
46 | "Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger",
47 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.",
48 | "Please specify the protocol for":"Veuillez spécifier un protocole pour",
49 | "Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de",
50 | "Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI",
51 | "Unable to read api":"Impossible de lire l'api",
52 | "from path":"à partir du chemin",
53 | "server returned":"réponse du serveur"
54 | });
55 |
--------------------------------------------------------------------------------
/web/src/styles/foundation/scss/foundation/components/_progress-bars.scss:
--------------------------------------------------------------------------------
1 | // Foundation by ZURB
2 | // foundation.zurb.com
3 | // Licensed under MIT Open Source
4 |
5 | @import 'global';
6 |
7 | //
8 | // @variables
9 | //
10 | $include-html-media-classes: $include-html-classes !default;
11 |
12 | // We use this to set the progress bar height
13 | $progress-bar-height: rem-calc(25) !default;
14 | $progress-bar-color: $vapor !default;
15 |
16 | // We use these to control the border styles
17 | $progress-bar-border-color: scale-color($white, $lightness: 20%) !default;
18 | $progress-bar-border-size: 1px !default;
19 | $progress-bar-border-style: solid !default;
20 | $progress-bar-border-radius: $global-radius !default;
21 |
22 | // We use these to control the margin & padding
23 | $progress-bar-pad: rem-calc(2) !default;
24 | $progress-bar-margin-bottom: rem-calc(10) !default;
25 |
26 | // We use these to set the meter colors
27 | $progress-meter-color: $primary-color !default;
28 | $progress-meter-secondary-color: $secondary-color !default;
29 | $progress-meter-success-color: $success-color !default;
30 | $progress-meter-alert-color: $alert-color !default;
31 |
32 | // @mixins
33 | //
34 | // We use this to set up the progress bar container
35 | @mixin progress-container {
36 | background-color: $progress-bar-color;
37 | border: $progress-bar-border-size $progress-bar-border-style $progress-bar-border-color;
38 | height: $progress-bar-height;
39 | margin-bottom: $progress-bar-margin-bottom;
40 | padding: $progress-bar-pad;
41 | }
42 |
43 | // @mixins
44 | //
45 | // $bg - Default: $progress-meter-color || $primary-color
46 | @mixin progress-meter($bg:$progress-meter-color) {
47 | background: $bg;
48 | display: block;
49 | height: 100%;
50 | float: left;
51 | width: 0%;
52 | }
53 |
54 |
55 | @include exports("progress-bar") {
56 | @if $include-html-media-classes {
57 |
58 | /* Progress Bar */
59 | .progress {
60 | @include progress-container;
61 |
62 | // Meter
63 | .meter {
64 | @include progress-meter;
65 |
66 | &.secondary { @include progress-meter($bg:$progress-meter-secondary-color); }
67 | &.success { @include progress-meter($bg:$progress-meter-success-color); }
68 | &.alert { @include progress-meter($bg:$progress-meter-alert-color); }
69 | }
70 | &.secondary .meter { @include progress-meter($bg:$progress-meter-secondary-color); }
71 | &.success .meter { @include progress-meter($bg:$progress-meter-success-color); }
72 | &.alert .meter { @include progress-meter($bg:$progress-meter-alert-color); }
73 |
74 | &.radius { @include radius($progress-bar-border-radius);
75 | .meter { @include radius($progress-bar-border-radius - 1); }
76 | }
77 |
78 | &.round { @include radius(1000px);
79 | .meter { @include radius(999px); }
80 | }
81 |
82 | }
83 |
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/web/src/pages/Home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import Loading from '../components/Loading.jsx';
4 | import Carousel from '../components/Carousel.jsx';
5 | import _ from 'lodash';
6 |
7 | import * as MovieActions from '../redux/actions/MovieActions';
8 | import { bindActionCreators } from 'redux';
9 | import { connect } from 'react-redux';
10 |
11 | class Home extends React.Component {
12 | constructor() {
13 | super();
14 |
15 | this.renderFeatured = this.renderFeatured.bind(this);
16 | this.renderByGenre = this.renderByGenre.bind(this);
17 | }
18 |
19 | componentWillMount() {
20 | this.props.getFeaturedMovies();
21 | this.props.getMoviesByGenres(['Adventure', 'Drama']);
22 | }
23 |
24 | render() {
25 | var {movies} = this.props;
26 | return (
27 |
28 |
29 |
30 | {movies.isFetching ? : null}
31 | {this.renderFeatured()}
32 |
33 |
34 | {this.renderByGenre('Adventure')}
35 | {this.renderByGenre('Drama')}
36 |
37 |
38 |
39 | );
40 | }
41 |
42 | renderFeatured() {
43 | var {movies} = this.props;
44 |
45 | return (
46 |
47 |
Featured Movies
48 |
49 | { _.compact(movies.featured).map(f => {
50 | return (
51 | -
52 |
53 |
54 |
55 |
56 | );
57 | })}
58 |
59 |
60 | );
61 | }
62 |
63 | renderByGenre(name) {
64 | var {movies} = this.props;
65 | var moviesByGenre = movies.byGenre[name];
66 |
67 | if (_.isEmpty(moviesByGenre)) {
68 | return null;
69 | }
70 |
71 | return (
72 |
73 |
74 |
75 | {name}
76 |
77 |
78 | { moviesByGenre.map(m => {
79 | return (
80 |
81 |
82 |

83 |
84 |
85 | {m.title}
86 |
87 |
88 | );
89 | })}
90 |
91 |
92 |
);
93 | }
94 | }
95 | Home.displayName = 'Home';
96 |
97 | function mapStateToProps(state) {
98 | return {
99 | genres: state.genres.items,
100 | movies: state.movies
101 | };
102 | }
103 |
104 | function mapDispatchToProps(dispatch) {
105 | return bindActionCreators(MovieActions, dispatch);
106 | }
107 |
108 | // Wrap the component to inject dispatch and state into it
109 | export default connect(mapStateToProps, mapDispatchToProps)(Home);
110 |
--------------------------------------------------------------------------------
/api/routes/people.js:
--------------------------------------------------------------------------------
1 | const People = require('../models/people')
2 | , _ = require('lodash')
3 | , writeResponse = require('../helpers/response').writeResponse
4 | , dbUtils = require('../neo4j/dbUtils');
5 |
6 | /**
7 | * @swagger
8 | * definition:
9 | * Person:
10 | * type: object
11 | * properties:
12 | * id:
13 | * type: integer
14 | * name:
15 | * type: string
16 | * poster_image:
17 | * type: string
18 | */
19 |
20 | /**
21 | * @swagger
22 | * /api/v0/people:
23 | * get:
24 | * tags:
25 | * - people
26 | * description: Returns all people
27 | * summary: Returns all people
28 | * produces:
29 | * - application/json
30 | * responses:
31 | * 200:
32 | * description: A list of people
33 | * schema:
34 | * type: array
35 | * items:
36 | * $ref: '#/definitions/Person'
37 | */
38 | exports.list = function (req, res, next) {
39 | People.getAll(dbUtils.getSession(req))
40 | .then(response => writeResponse(res, response))
41 | .catch(next);
42 | };
43 |
44 | /**
45 | * @swagger
46 | * /api/v0/people/bacon:
47 | * get:
48 | * tags:
49 | * - people
50 | * description: Returns all Bacon paths from person 1 to person 2
51 | * summary: Returns all Bacon paths from person 1 to person 2
52 | * produces:
53 | * - application/json
54 | * parameters:
55 | * - name: name1
56 | * description: Name of the origin person
57 | * in: query
58 | * required: true
59 | * type: string
60 | * - name: name2
61 | * description: Name of the target person
62 | * in: query
63 | * required: true
64 | * type: string
65 | * responses:
66 | * 200:
67 | * description: A list of people
68 | * schema:
69 | * type: array
70 | * items:
71 | * $ref: '#/definitions/Person'
72 | */
73 | exports.getBaconPeople = function (req, res, next) {
74 | const name1 = req.query.name1;
75 | const name2 = req.query.name2;
76 |
77 | People.getBaconPeople(dbUtils.getSession(req), req.query.name1, req.query.name2)
78 | .then(response => writeResponse(res, response))
79 | .catch(next);
80 | };
81 |
82 | /**
83 | * @swagger
84 | * /api/v0/people/{id}:
85 | * get:
86 | * tags:
87 | * - people
88 | * description: Returns a person by id
89 | * summary: Returns a person by id
90 | * produces:
91 | * - application/json
92 | * parameters:
93 | * - name: id
94 | * description: Person id
95 | * in: path
96 | * required: true
97 | * type: integer
98 | * responses:
99 | * 200:
100 | * description: A person
101 | * schema:
102 | * $ref: '#/definitions/Person'
103 | * 400:
104 | * description: Error message(s)
105 | * 404:
106 | * description: Person not found
107 | */
108 | exports.findById = function (req, res, next) {
109 | const id = req.params.id;
110 | if (!id) throw {message: 'Invalid id', status: 400};
111 |
112 | People.getById(dbUtils.getSession(req), id)
113 | .then(response => writeResponse(res, response))
114 | .catch(next);
115 | };
--------------------------------------------------------------------------------
/api/models/people.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 | const Person = require('../models/neo4j/person');
3 |
4 | const _singlePersonWithDetails = function (record) {
5 | if (record.length) {
6 | const result = {};
7 | _.extend(result, new Person(record.get('person')));
8 | // mappings are temporary until the neo4j driver team decides what to do about numbers
9 | result.directed = _.map(record.get('directed'), record => {
10 | return record;
11 | });
12 | result.produced = _.map(record.get('produced'), record => {
13 | return record;
14 | });
15 | result.wrote = _.map(record.get('wrote'), record => {
16 | return record;
17 | });
18 | result.actedIn = _.map(record.get('actedIn'), record => {
19 | return record;
20 | });
21 | result.related = _.map(record.get('related'), record => {
22 | return record;
23 | });
24 | return result;
25 | }
26 | else {
27 | return null;
28 | }
29 | };
30 |
31 | // return many people
32 | function _manyPeople(neo4jResult) {
33 | return neo4jResult.records.map(r => new Person(r.get('person')))
34 | }
35 |
36 | // get a single person by id
37 | const getById = function (session, id) {
38 | const query = [
39 | 'MATCH (person:Person {tmdbId: $id})',
40 | 'OPTIONAL MATCH (person)-[:DIRECTED]->(d:Movie)',
41 | 'OPTIONAL MATCH (person)<-[:PRODUCED]->(p:Movie)',
42 | 'OPTIONAL MATCH (person)<-[:WRITER_OF]->(w:Movie)',
43 | 'OPTIONAL MATCH (person)<-[r:ACTED_IN]->(a:Movie)',
44 | 'OPTIONAL MATCH (person)-->(movies)<-[relatedRole:ACTED_IN]-(relatedPerson)',
45 | 'RETURN DISTINCT person,',
46 | 'collect(DISTINCT { name:d.title, id:d.tmdbId, poster_image:d.poster}) AS directed,',
47 | 'collect(DISTINCT { name:p.title, id:p.tmdbId, poster_image:p.poster}) AS produced,',
48 | 'collect(DISTINCT { name:w.title, id:w.tmdbId, poster_image:w.poster}) AS wrote,',
49 | 'collect(DISTINCT{ name:a.title, id:a.tmdbId, poster_image:a.poster, role:r.role}) AS actedIn,',
50 | 'collect(DISTINCT{ name:relatedPerson.name, id:relatedPerson.tmdbId, poster_image:relatedPerson.poster, role:relatedRole.role}) AS related'
51 | ].join('\n');
52 |
53 | return session.readTransaction(txc =>
54 | txc.run(query, {id: id})
55 | ).then(result => {
56 | if (!_.isEmpty(result.records)) {
57 | return _singlePersonWithDetails(result.records[0]);
58 | }
59 | else {
60 | throw {message: 'person not found', status: 404}
61 | }
62 | });
63 | };
64 |
65 | // get all people
66 | const getAll = function (session) {
67 | return session.readTransaction(txc =>
68 | txc.run('MATCH (person:Person) RETURN person')
69 | ).then(result => _manyPeople(result));
70 | };
71 |
72 | // get people in Bacon path, return many persons
73 | const getBaconPeople = function (session, name1, name2) {
74 | //needs to be optimized
75 | const query = [
76 | 'MATCH p = shortestPath( (p1:Person {name: $name1 })-[:ACTED_IN*]-(target:Person {name: $name2 }) )',
77 | 'WITH [n IN nodes(p) WHERE n:Person | n] as bacon',
78 | 'UNWIND(bacon) AS person',
79 | 'RETURN DISTINCT person'
80 | ].join('\n');
81 |
82 | return session.readTransaction(txc =>
83 | txc.run(query, {
84 | name1: name1,
85 | name2: name2
86 | })
87 | ).then(result => _manyPeople(result))
88 | };
89 |
90 | module.exports = {
91 | getAll: getAll,
92 | getById: getById,
93 | getBaconPeople: getBaconPeople
94 | };
95 |
--------------------------------------------------------------------------------