├── backend
├── users
│ ├── __init__.py
│ ├── migrations
│ │ ├── __init__.py
│ │ └── 0001_initial.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── serializers.py
│ └── signals.py
├── thisisproject
│ ├── __init__.py
│ ├── wsgi.py
│ ├── urls.py
│ └── settings.py
├── authentication
│ ├── __init__.py
│ ├── urls.py
│ └── views.py
├── Pipfile
├── manage.py
└── Pipfile.lock
├── frontend
├── static
│ └── .gitkeep
├── .eslintignore
├── config
│ ├── prod.env.js
│ ├── dev.env.js
│ └── index.js
├── .editorconfig
├── .gitignore
├── .babelrc
├── .postcssrc.js
├── src
│ ├── main.js
│ ├── components
│ │ └── UserPanel.vue
│ └── App.vue
├── index.html
├── README.md
├── build
│ ├── vue-loader.conf.js
│ ├── build.js
│ ├── check-versions.js
│ ├── webpack.base.conf.js
│ ├── utils.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── .eslintrc.js
└── package.json
├── other
└── preview.gif
├── .gitignore
└── README.md
/backend/users/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/thisisproject/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/authentication/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/users/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /dist/
4 | /*.js
5 |
--------------------------------------------------------------------------------
/frontend/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"'
4 | }
5 |
--------------------------------------------------------------------------------
/other/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/denisorehovsky/django-vue-google-auth/HEAD/other/preview.gif
--------------------------------------------------------------------------------
/backend/users/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import User
4 |
5 |
6 | @admin.register(User)
7 | class UserAdmin(admin.ModelAdmin):
8 | pass
9 |
--------------------------------------------------------------------------------
/backend/authentication/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | path('google/', views.GoogleLogin.as_view(), name='google_login')
7 | ]
8 |
--------------------------------------------------------------------------------
/backend/users/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class UsersConfig(AppConfig):
5 | name = 'users'
6 |
7 | def ready(self):
8 | import users.signals # noqa
9 |
--------------------------------------------------------------------------------
/frontend/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"'
7 | })
8 |
--------------------------------------------------------------------------------
/frontend/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
--------------------------------------------------------------------------------
/backend/authentication/views.py:
--------------------------------------------------------------------------------
1 | from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
2 | from rest_auth.registration.views import SocialLoginView
3 |
4 |
5 | class GoogleLogin(SocialLoginView):
6 | adapter_class = GoogleOAuth2Adapter
7 |
--------------------------------------------------------------------------------
/backend/users/models.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import AbstractUser
2 | from django.db import models
3 |
4 |
5 | class User(AbstractUser):
6 | photo = models.URLField(blank=True)
7 |
8 | def __str__(self):
9 | return self.username
10 |
--------------------------------------------------------------------------------
/frontend/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime"]
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | "postcss-import": {},
6 | "postcss-url": {},
7 | // to edit target browsers: use "browserslist" field in package.json
8 | "autoprefixer": {}
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/backend/users/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from .models import User
4 |
5 |
6 | class UserSerializer(serializers.ModelSerializer):
7 |
8 | class Meta:
9 | model = User
10 | fields = ('username', 'email', 'first_name', 'last_name', 'photo')
11 | read_only_fields = ('email', )
12 |
--------------------------------------------------------------------------------
/backend/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 |
3 | url = "https://pypi.python.org/simple"
4 | verify_ssl = true
5 | name = "pypi"
6 |
7 |
8 | [packages]
9 |
10 | django = "*"
11 | djangorestframework = "*"
12 | django-rest-auth = "*"
13 | django-allauth = "*"
14 | djangorestframework-jwt = "*"
15 | django-cors-headers = "*"
16 |
17 |
18 | [dev-packages]
19 |
20 | "flake8" = "*"
21 |
--------------------------------------------------------------------------------
/backend/users/signals.py:
--------------------------------------------------------------------------------
1 | from django.db.models.signals import post_save
2 | from django.dispatch import receiver
3 |
4 | from allauth.socialaccount.models import SocialAccount
5 |
6 |
7 | @receiver(post_save, sender=SocialAccount)
8 | def add_extra_data_to_the_user(sender, instance, created, *args, **kwargs):
9 | instance.user.photo = instance.extra_data['picture']
10 | instance.user.save()
11 |
--------------------------------------------------------------------------------
/frontend/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import GSignInButton from 'vue-google-signin-button'
5 | import App from './App'
6 |
7 | Vue.config.productionTip = false
8 |
9 | Vue.use(GSignInButton)
10 |
11 | /* eslint-disable no-new */
12 | new Vue({
13 | el: '#app',
14 | components: { App },
15 | template: ''
16 | })
17 |
--------------------------------------------------------------------------------
/backend/thisisproject/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for thisisproject project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thisisproject.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | thisisproject
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | # thisisproject
2 |
3 | > A Vue.js project
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # install dependencies
9 | npm install
10 |
11 | # serve with hot reload at localhost:8080
12 | npm run dev
13 |
14 | # build for production with minification
15 | npm run build
16 |
17 | # build for production and view the bundle analyzer report
18 | npm run build --report
19 | ```
20 |
21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
22 |
--------------------------------------------------------------------------------
/backend/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thisisproject.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError as exc:
10 | raise ImportError(
11 | "Couldn't import Django. Are you sure it's installed and "
12 | "available on your PYTHONPATH environment variable? Did you "
13 | "forget to activate a virtual environment?"
14 | ) from exc
15 | execute_from_command_line(sys.argv)
16 |
--------------------------------------------------------------------------------
/frontend/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 | module.exports = {
10 | loaders: utils.cssLoaders({
11 | sourceMap: sourceMapEnabled,
12 | extract: isProduction
13 | }),
14 | cssSourceMap: sourceMapEnabled,
15 | cacheBusting: config.dev.cacheBusting,
16 | transformToRequire: {
17 | video: ['src', 'poster'],
18 | source: 'src',
19 | img: 'src',
20 | image: 'xlink:href'
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | ### OSX ###
9 | .DS_Store
10 | .AppleDouble
11 | .LSOverride
12 |
13 | ### SublimeText ###
14 | # cache files for sublime text
15 | *.tmlanguage.cache
16 | *.tmPreferences.cache
17 | *.stTheme.cache
18 |
19 | # workspace files are user-specific
20 | *.sublime-workspace
21 |
22 | # project files should be checked into the repository, unless a significant
23 | # proportion of contributors will probably not be using SublimeText
24 | # *.sublime-project
25 |
26 | # Basics
27 | *.py[cod]
28 | __pycache__
29 |
30 | # Database
31 | db.sqlite3
32 |
33 | # Vim
34 | *~
35 | *.swp
36 | *.swo
37 |
38 | # Compass
39 | .sass-cache
40 |
41 | # virtual environments
42 | env
43 |
44 | # User-uploaded media
45 | staticfiles/
46 | .cache/
47 |
--------------------------------------------------------------------------------
/backend/thisisproject/urls.py:
--------------------------------------------------------------------------------
1 | """thisisproject URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path, include
18 |
19 | urlpatterns = [
20 | path('admin/', admin.site.urls),
21 | path('auth/', include('authentication.urls')),
22 | ]
23 |
--------------------------------------------------------------------------------
/frontend/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parserOptions: {
6 | parser: 'babel-eslint'
7 | },
8 | env: {
9 | browser: true,
10 | },
11 | extends: [
12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
14 | 'plugin:vue/essential',
15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
16 | 'standard'
17 | ],
18 | // required to lint *.vue files
19 | plugins: [
20 | 'vue'
21 | ],
22 | // add your custom rules here
23 | rules: {
24 | // allow async-await
25 | 'generator-star-spacing': 'off',
26 | // allow debugger during development
27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/src/components/UserPanel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
17 |
18 |
19 |
20 |
E-mail
21 |
{{ user.email }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ---
8 |
9 | ## Description
10 |
11 | `django-vue-google-auth` shows how you can implement authentication through Google using **django & django rest framework** as a backend and **vue.js** as a frontend.
12 |
13 | ## How to run
14 |
15 | Clone the repository:
16 |
17 | ```zsh
18 | ➜ git clone https://github.com/apirobot/django-vue-google-auth
19 | ```
20 |
21 | Install dependencies:
22 |
23 | ```zsh
24 | ../backend ➜ pipenv install
25 | ../frontend ➜ npm install
26 | ```
27 |
28 | Run migrations:
29 |
30 | ```zsh
31 | ../backend ➜ python manage.py makemigrations
32 | ../backend ➜ python manage.py migrate
33 | ```
34 |
35 | Start up backend:
36 |
37 | ```zsh
38 | ../backend ➜ python manage.py runserver
39 | ```
40 |
41 | Start up frontend:
42 |
43 | ```zsh
44 | ../frontend ➜ npm start
45 | ```
46 |
47 | We are done.
48 |
49 | - Frontend: http://localhost:8080/
50 | - Backend: http://localhost:8000/
51 |
--------------------------------------------------------------------------------
/frontend/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, (err, stats) => {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/frontend/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 |
7 | function exec (cmd) {
8 | return require('child_process').execSync(cmd).toString().trim()
9 | }
10 |
11 | const versionRequirements = [
12 | {
13 | name: 'node',
14 | currentVersion: semver.clean(process.version),
15 | versionRequirement: packageConfig.engines.node
16 | }
17 | ]
18 |
19 | if (shell.which('npm')) {
20 | versionRequirements.push({
21 | name: 'npm',
22 | currentVersion: exec('npm --version'),
23 | versionRequirement: packageConfig.engines.npm
24 | })
25 | }
26 |
27 | module.exports = function () {
28 | const warnings = []
29 |
30 | for (let i = 0; i < versionRequirements.length; i++) {
31 | const mod = versionRequirements[i]
32 |
33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
34 | warnings.push(mod.name + ': ' +
35 | chalk.red(mod.currentVersion) + ' should be ' +
36 | chalk.green(mod.versionRequirement)
37 | )
38 | }
39 | }
40 |
41 | if (warnings.length) {
42 | console.log('')
43 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
44 | console.log()
45 |
46 | for (let i = 0; i < warnings.length; i++) {
47 | const warning = warnings[i]
48 | console.log(' ' + warning)
49 | }
50 |
51 | console.log()
52 | process.exit(1)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/frontend/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
63 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "thisisproject",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "Denis Orehovsky ",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "lint": "eslint --ext .js,.vue src",
11 | "build": "node build/build.js"
12 | },
13 | "dependencies": {
14 | "axios": "^0.18.0",
15 | "vue": "^2.5.2",
16 | "vue-google-signin-button": "^1.0.2"
17 | },
18 | "devDependencies": {
19 | "autoprefixer": "^7.1.2",
20 | "babel-core": "^6.22.1",
21 | "babel-eslint": "^8.2.1",
22 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
23 | "babel-loader": "^7.1.1",
24 | "babel-plugin-syntax-jsx": "^6.18.0",
25 | "babel-plugin-transform-runtime": "^6.22.0",
26 | "babel-plugin-transform-vue-jsx": "^3.5.0",
27 | "babel-preset-env": "^1.3.2",
28 | "babel-preset-stage-2": "^6.22.0",
29 | "chalk": "^2.0.1",
30 | "copy-webpack-plugin": "^4.0.1",
31 | "css-loader": "^0.28.0",
32 | "eslint": "^4.15.0",
33 | "eslint-config-standard": "^10.2.1",
34 | "eslint-friendly-formatter": "^3.0.0",
35 | "eslint-loader": "^1.7.1",
36 | "eslint-plugin-import": "^2.7.0",
37 | "eslint-plugin-node": "^5.2.0",
38 | "eslint-plugin-promise": "^3.4.0",
39 | "eslint-plugin-standard": "^3.0.1",
40 | "eslint-plugin-vue": "^4.0.0",
41 | "extract-text-webpack-plugin": "^3.0.0",
42 | "file-loader": "^1.1.4",
43 | "friendly-errors-webpack-plugin": "^1.6.1",
44 | "html-webpack-plugin": "^2.30.1",
45 | "node-notifier": "^5.1.2",
46 | "optimize-css-assets-webpack-plugin": "^3.2.0",
47 | "ora": "^1.2.0",
48 | "portfinder": "^1.0.13",
49 | "postcss-import": "^11.0.0",
50 | "postcss-loader": "^2.0.8",
51 | "postcss-url": "^7.2.1",
52 | "rimraf": "^2.6.0",
53 | "semver": "^5.3.0",
54 | "shelljs": "^0.7.6",
55 | "uglifyjs-webpack-plugin": "^1.1.1",
56 | "url-loader": "^0.5.8",
57 | "vue-loader": "^13.3.0",
58 | "vue-style-loader": "^3.0.1",
59 | "vue-template-compiler": "^2.5.2",
60 | "webpack": "^3.6.0",
61 | "webpack-bundle-analyzer": "^2.9.0",
62 | "webpack-dev-server": "^2.9.1",
63 | "webpack-merge": "^4.1.0"
64 | },
65 | "engines": {
66 | "node": ">= 6.0.0",
67 | "npm": ">= 3.0.0"
68 | },
69 | "browserslist": [
70 | "> 1%",
71 | "last 2 versions",
72 | "not ie <= 8"
73 | ]
74 | }
75 |
--------------------------------------------------------------------------------
/frontend/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {},
14 |
15 | // Various Dev Server settings
16 | host: 'localhost', // can be overwritten by process.env.HOST
17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
18 | autoOpenBrowser: false,
19 | errorOverlay: true,
20 | notifyOnErrors: true,
21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
22 |
23 | // Use Eslint Loader?
24 | // If true, your code will be linted during bundling and
25 | // linting errors and warnings will be shown in the console.
26 | useEslint: true,
27 | // If true, eslint errors and warnings will also be shown in the error overlay
28 | // in the browser.
29 | showEslintErrorsInOverlay: false,
30 |
31 | /**
32 | * Source Maps
33 | */
34 |
35 | // https://webpack.js.org/configuration/devtool/#development
36 | devtool: 'cheap-module-eval-source-map',
37 |
38 | // If you have problems debugging vue-files in devtools,
39 | // set this to false - it *may* help
40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
41 | cacheBusting: true,
42 |
43 | cssSourceMap: true
44 | },
45 |
46 | build: {
47 | // Template for index.html
48 | index: path.resolve(__dirname, '../dist/index.html'),
49 |
50 | // Paths
51 | assetsRoot: path.resolve(__dirname, '../dist'),
52 | assetsSubDirectory: 'static',
53 | assetsPublicPath: '/',
54 |
55 | /**
56 | * Source Maps
57 | */
58 |
59 | productionSourceMap: true,
60 | // https://webpack.js.org/configuration/devtool/#production
61 | devtool: '#source-map',
62 |
63 | // Gzip off by default as many popular static hosts such as
64 | // Surge or Netlify already gzip all static assets for you.
65 | // Before setting to `true`, make sure to:
66 | // npm install --save-dev compression-webpack-plugin
67 | productionGzip: false,
68 | productionGzipExtensions: ['js', 'css'],
69 |
70 | // Run the build command with an extra argument to
71 | // View the bundle analyzer report after build finishes:
72 | // `npm run build --report`
73 | // Set to `true` or `false` to always turn it on or off
74 | bundleAnalyzerReport: process.env.npm_config_report
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/frontend/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const config = require('../config')
5 | const vueLoaderConfig = require('./vue-loader.conf')
6 |
7 | function resolve (dir) {
8 | return path.join(__dirname, '..', dir)
9 | }
10 |
11 | const createLintingRule = () => ({
12 | test: /\.(js|vue)$/,
13 | loader: 'eslint-loader',
14 | enforce: 'pre',
15 | include: [resolve('src'), resolve('test')],
16 | options: {
17 | formatter: require('eslint-friendly-formatter'),
18 | emitWarning: !config.dev.showEslintErrorsInOverlay
19 | }
20 | })
21 |
22 | module.exports = {
23 | context: path.resolve(__dirname, '../'),
24 | entry: {
25 | app: './src/main.js'
26 | },
27 | output: {
28 | path: config.build.assetsRoot,
29 | filename: '[name].js',
30 | publicPath: process.env.NODE_ENV === 'production'
31 | ? config.build.assetsPublicPath
32 | : config.dev.assetsPublicPath
33 | },
34 | resolve: {
35 | extensions: ['.js', '.vue', '.json'],
36 | alias: {
37 | 'vue$': 'vue/dist/vue.esm.js',
38 | '@': resolve('src'),
39 | }
40 | },
41 | module: {
42 | rules: [
43 | ...(config.dev.useEslint ? [createLintingRule()] : []),
44 | {
45 | test: /\.vue$/,
46 | loader: 'vue-loader',
47 | options: vueLoaderConfig
48 | },
49 | {
50 | test: /\.js$/,
51 | loader: 'babel-loader',
52 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
53 | },
54 | {
55 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
56 | loader: 'url-loader',
57 | options: {
58 | limit: 10000,
59 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
60 | }
61 | },
62 | {
63 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
64 | loader: 'url-loader',
65 | options: {
66 | limit: 10000,
67 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
68 | }
69 | },
70 | {
71 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
72 | loader: 'url-loader',
73 | options: {
74 | limit: 10000,
75 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
76 | }
77 | }
78 | ]
79 | },
80 | node: {
81 | // prevent webpack from injecting useless setImmediate polyfill because Vue
82 | // source contains it (although only uses it if it's native).
83 | setImmediate: false,
84 | // prevent webpack from injecting mocks to Node native modules
85 | // that does not make sense for the client
86 | dgram: 'empty',
87 | fs: 'empty',
88 | net: 'empty',
89 | tls: 'empty',
90 | child_process: 'empty'
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/backend/users/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.0.2 on 2018-02-25 06:17
2 |
3 | import django.contrib.auth.models
4 | import django.contrib.auth.validators
5 | from django.db import migrations, models
6 | import django.utils.timezone
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | initial = True
12 |
13 | dependencies = [
14 | ('auth', '0009_alter_user_last_name_max_length'),
15 | ]
16 |
17 | operations = [
18 | migrations.CreateModel(
19 | name='User',
20 | fields=[
21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22 | ('password', models.CharField(max_length=128, verbose_name='password')),
23 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
24 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
25 | ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
26 | ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
27 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
28 | ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
29 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
30 | ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
31 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
32 | ('photo', models.URLField(blank=True)),
33 | ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
34 | ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
35 | ],
36 | options={
37 | 'verbose_name': 'user',
38 | 'verbose_name_plural': 'users',
39 | 'abstract': False,
40 | },
41 | managers=[
42 | ('objects', django.contrib.auth.models.UserManager()),
43 | ],
44 | ),
45 | ]
46 |
--------------------------------------------------------------------------------
/frontend/build/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const config = require('../config')
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | const packageConfig = require('../package.json')
6 |
7 | exports.assetsPath = function (_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production'
9 | ? config.build.assetsSubDirectory
10 | : config.dev.assetsSubDirectory
11 |
12 | return path.posix.join(assetsSubDirectory, _path)
13 | }
14 |
15 | exports.cssLoaders = function (options) {
16 | options = options || {}
17 |
18 | const cssLoader = {
19 | loader: 'css-loader',
20 | options: {
21 | sourceMap: options.sourceMap
22 | }
23 | }
24 |
25 | const postcssLoader = {
26 | loader: 'postcss-loader',
27 | options: {
28 | sourceMap: options.sourceMap
29 | }
30 | }
31 |
32 | // generate loader string to be used with extract text plugin
33 | function generateLoaders (loader, loaderOptions) {
34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
35 |
36 | if (loader) {
37 | loaders.push({
38 | loader: loader + '-loader',
39 | options: Object.assign({}, loaderOptions, {
40 | sourceMap: options.sourceMap
41 | })
42 | })
43 | }
44 |
45 | // Extract CSS when that option is specified
46 | // (which is the case during production build)
47 | if (options.extract) {
48 | return ExtractTextPlugin.extract({
49 | use: loaders,
50 | fallback: 'vue-style-loader'
51 | })
52 | } else {
53 | return ['vue-style-loader'].concat(loaders)
54 | }
55 | }
56 |
57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
58 | return {
59 | css: generateLoaders(),
60 | postcss: generateLoaders(),
61 | less: generateLoaders('less'),
62 | sass: generateLoaders('sass', { indentedSyntax: true }),
63 | scss: generateLoaders('sass'),
64 | stylus: generateLoaders('stylus'),
65 | styl: generateLoaders('stylus')
66 | }
67 | }
68 |
69 | // Generate loaders for standalone style files (outside of .vue)
70 | exports.styleLoaders = function (options) {
71 | const output = []
72 | const loaders = exports.cssLoaders(options)
73 |
74 | for (const extension in loaders) {
75 | const loader = loaders[extension]
76 | output.push({
77 | test: new RegExp('\\.' + extension + '$'),
78 | use: loader
79 | })
80 | }
81 |
82 | return output
83 | }
84 |
85 | exports.createNotifierCallback = () => {
86 | const notifier = require('node-notifier')
87 |
88 | return (severity, errors) => {
89 | if (severity !== 'error') return
90 |
91 | const error = errors[0]
92 | const filename = error.file && error.file.split('!').pop()
93 |
94 | notifier.notify({
95 | title: packageConfig.name,
96 | message: severity + ': ' + error.name,
97 | subtitle: filename || '',
98 | icon: path.join(__dirname, 'logo.png')
99 | })
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/frontend/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const path = require('path')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
11 | const portfinder = require('portfinder')
12 |
13 | const HOST = process.env.HOST
14 | const PORT = process.env.PORT && Number(process.env.PORT)
15 |
16 | const devWebpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
19 | },
20 | // cheap-module-eval-source-map is faster for development
21 | devtool: config.dev.devtool,
22 |
23 | // these devServer options should be customized in /config/index.js
24 | devServer: {
25 | clientLogLevel: 'warning',
26 | historyApiFallback: {
27 | rewrites: [
28 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
29 | ],
30 | },
31 | hot: true,
32 | contentBase: false, // since we use CopyWebpackPlugin.
33 | compress: true,
34 | host: HOST || config.dev.host,
35 | port: PORT || config.dev.port,
36 | open: config.dev.autoOpenBrowser,
37 | overlay: config.dev.errorOverlay
38 | ? { warnings: false, errors: true }
39 | : false,
40 | publicPath: config.dev.assetsPublicPath,
41 | proxy: config.dev.proxyTable,
42 | quiet: true, // necessary for FriendlyErrorsPlugin
43 | watchOptions: {
44 | poll: config.dev.poll,
45 | }
46 | },
47 | plugins: [
48 | new webpack.DefinePlugin({
49 | 'process.env': require('../config/dev.env')
50 | }),
51 | new webpack.HotModuleReplacementPlugin(),
52 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
53 | new webpack.NoEmitOnErrorsPlugin(),
54 | // https://github.com/ampedandwired/html-webpack-plugin
55 | new HtmlWebpackPlugin({
56 | filename: 'index.html',
57 | template: 'index.html',
58 | inject: true
59 | }),
60 | // copy custom static assets
61 | new CopyWebpackPlugin([
62 | {
63 | from: path.resolve(__dirname, '../static'),
64 | to: config.dev.assetsSubDirectory,
65 | ignore: ['.*']
66 | }
67 | ])
68 | ]
69 | })
70 |
71 | module.exports = new Promise((resolve, reject) => {
72 | portfinder.basePort = process.env.PORT || config.dev.port
73 | portfinder.getPort((err, port) => {
74 | if (err) {
75 | reject(err)
76 | } else {
77 | // publish the new Port, necessary for e2e tests
78 | process.env.PORT = port
79 | // add port to devServer config
80 | devWebpackConfig.devServer.port = port
81 |
82 | // Add FriendlyErrorsPlugin
83 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
84 | compilationSuccessInfo: {
85 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
86 | },
87 | onErrors: config.dev.notifyOnErrors
88 | ? utils.createNotifierCallback()
89 | : undefined
90 | }))
91 |
92 | resolve(devWebpackConfig)
93 | }
94 | })
95 | })
96 |
--------------------------------------------------------------------------------
/backend/thisisproject/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for thisisproject project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.0.2.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.0/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '9%6_$*&g9^l$z899si5euq8ps!=*4kjl=zv@y327__*ut5oe7m'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 | SITE_ID = 1
31 |
32 | REST_USE_JWT = True
33 |
34 |
35 | # Application definition
36 |
37 | INSTALLED_APPS = [
38 | 'django.contrib.admin',
39 | 'django.contrib.auth',
40 | 'django.contrib.contenttypes',
41 | 'django.contrib.sessions',
42 | 'django.contrib.messages',
43 | 'django.contrib.staticfiles',
44 | 'django.contrib.sites', # don't forget
45 |
46 | 'corsheaders',
47 | 'rest_framework',
48 | 'rest_framework.authtoken',
49 | 'rest_auth',
50 | 'rest_auth.registration',
51 | 'allauth',
52 | 'allauth.account',
53 | 'allauth.socialaccount',
54 | 'allauth.socialaccount.providers.google',
55 |
56 | 'users.apps.UsersConfig',
57 | ]
58 |
59 | MIDDLEWARE = [
60 | 'django.middleware.security.SecurityMiddleware',
61 | 'django.contrib.sessions.middleware.SessionMiddleware',
62 | 'corsheaders.middleware.CorsMiddleware',
63 | 'django.middleware.common.CommonMiddleware',
64 | 'django.middleware.csrf.CsrfViewMiddleware',
65 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
66 | 'django.contrib.messages.middleware.MessageMiddleware',
67 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
68 | ]
69 |
70 | CORS_ORIGIN_ALLOW_ALL = True
71 |
72 | ROOT_URLCONF = 'thisisproject.urls'
73 |
74 | TEMPLATES = [
75 | {
76 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
77 | 'DIRS': [],
78 | 'APP_DIRS': True,
79 | 'OPTIONS': {
80 | 'context_processors': [
81 | 'django.template.context_processors.debug',
82 | 'django.template.context_processors.request',
83 | 'django.contrib.auth.context_processors.auth',
84 | 'django.contrib.messages.context_processors.messages',
85 | ],
86 | },
87 | },
88 | ]
89 |
90 | WSGI_APPLICATION = 'thisisproject.wsgi.application'
91 |
92 | EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
93 |
94 |
95 | # Database
96 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
97 |
98 | DATABASES = {
99 | 'default': {
100 | 'ENGINE': 'django.db.backends.sqlite3',
101 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
102 | }
103 | }
104 |
105 |
106 | # Password validation
107 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
108 |
109 | AUTH_PASSWORD_VALIDATORS = [
110 | {
111 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
112 | },
113 | {
114 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
115 | },
116 | {
117 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
118 | },
119 | {
120 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
121 | },
122 | ]
123 |
124 | AUTHENTICATION_BACKENDS = [
125 | 'django.contrib.auth.backends.ModelBackend',
126 | 'allauth.account.auth_backends.AuthenticationBackend',
127 | ]
128 |
129 | AUTH_USER_MODEL = 'users.User'
130 |
131 |
132 | # Internationalization
133 | # https://docs.djangoproject.com/en/2.0/topics/i18n/
134 |
135 | LANGUAGE_CODE = 'en-us'
136 |
137 | TIME_ZONE = 'UTC'
138 |
139 | USE_I18N = True
140 |
141 | USE_L10N = True
142 |
143 | USE_TZ = True
144 |
145 |
146 | # Static files (CSS, JavaScript, Images)
147 | # https://docs.djangoproject.com/en/2.0/howto/static-files/
148 |
149 | STATIC_URL = '/static/'
150 |
151 |
152 | REST_FRAMEWORK = {
153 | 'DEFAULT_AUTHENTICATION_CLASSES': (
154 | 'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
155 | 'rest_framework.authentication.SessionAuthentication',
156 | 'rest_framework.authentication.BasicAuthentication',
157 | ),
158 | }
159 |
160 | REST_AUTH_SERIALIZERS = {
161 | 'USER_DETAILS_SERIALIZER': 'users.serializers.UserSerializer',
162 | }
163 |
--------------------------------------------------------------------------------
/frontend/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const webpack = require('webpack')
5 | const config = require('../config')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
13 |
14 | const env = require('../config/prod.env')
15 |
16 | const webpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({
19 | sourceMap: config.build.productionSourceMap,
20 | extract: true,
21 | usePostCSS: true
22 | })
23 | },
24 | devtool: config.build.productionSourceMap ? config.build.devtool : false,
25 | output: {
26 | path: config.build.assetsRoot,
27 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
28 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
29 | },
30 | plugins: [
31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
32 | new webpack.DefinePlugin({
33 | 'process.env': env
34 | }),
35 | new UglifyJsPlugin({
36 | uglifyOptions: {
37 | compress: {
38 | warnings: false
39 | }
40 | },
41 | sourceMap: config.build.productionSourceMap,
42 | parallel: true
43 | }),
44 | // extract css into its own file
45 | new ExtractTextPlugin({
46 | filename: utils.assetsPath('css/[name].[contenthash].css'),
47 | // Setting the following option to `false` will not extract CSS from codesplit chunks.
48 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
49 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
50 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
51 | allChunks: true,
52 | }),
53 | // Compress extracted CSS. We are using this plugin so that possible
54 | // duplicated CSS from different components can be deduped.
55 | new OptimizeCSSPlugin({
56 | cssProcessorOptions: config.build.productionSourceMap
57 | ? { safe: true, map: { inline: false } }
58 | : { safe: true }
59 | }),
60 | // generate dist index.html with correct asset hash for caching.
61 | // you can customize output by editing /index.html
62 | // see https://github.com/ampedandwired/html-webpack-plugin
63 | new HtmlWebpackPlugin({
64 | filename: config.build.index,
65 | template: 'index.html',
66 | inject: true,
67 | minify: {
68 | removeComments: true,
69 | collapseWhitespace: true,
70 | removeAttributeQuotes: true
71 | // more options:
72 | // https://github.com/kangax/html-minifier#options-quick-reference
73 | },
74 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
75 | chunksSortMode: 'dependency'
76 | }),
77 | // keep module.id stable when vendor modules does not change
78 | new webpack.HashedModuleIdsPlugin(),
79 | // enable scope hoisting
80 | new webpack.optimize.ModuleConcatenationPlugin(),
81 | // split vendor js into its own file
82 | new webpack.optimize.CommonsChunkPlugin({
83 | name: 'vendor',
84 | minChunks (module) {
85 | // any required modules inside node_modules are extracted to vendor
86 | return (
87 | module.resource &&
88 | /\.js$/.test(module.resource) &&
89 | module.resource.indexOf(
90 | path.join(__dirname, '../node_modules')
91 | ) === 0
92 | )
93 | }
94 | }),
95 | // extract webpack runtime and module manifest to its own file in order to
96 | // prevent vendor hash from being updated whenever app bundle is updated
97 | new webpack.optimize.CommonsChunkPlugin({
98 | name: 'manifest',
99 | minChunks: Infinity
100 | }),
101 | // This instance extracts shared chunks from code splitted chunks and bundles them
102 | // in a separate chunk, similar to the vendor chunk
103 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
104 | new webpack.optimize.CommonsChunkPlugin({
105 | name: 'app',
106 | async: 'vendor-async',
107 | children: true,
108 | minChunks: 3
109 | }),
110 |
111 | // copy custom static assets
112 | new CopyWebpackPlugin([
113 | {
114 | from: path.resolve(__dirname, '../static'),
115 | to: config.build.assetsSubDirectory,
116 | ignore: ['.*']
117 | }
118 | ])
119 | ]
120 | })
121 |
122 | if (config.build.productionGzip) {
123 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
124 |
125 | webpackConfig.plugins.push(
126 | new CompressionWebpackPlugin({
127 | asset: '[path].gz[query]',
128 | algorithm: 'gzip',
129 | test: new RegExp(
130 | '\\.(' +
131 | config.build.productionGzipExtensions.join('|') +
132 | ')$'
133 | ),
134 | threshold: 10240,
135 | minRatio: 0.8
136 | })
137 | )
138 | }
139 |
140 | if (config.build.bundleAnalyzerReport) {
141 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
142 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
143 | }
144 |
145 | module.exports = webpackConfig
146 |
--------------------------------------------------------------------------------
/backend/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "5a96502caf4a38f6310a7d64da1b2e12432e01cc048baf059055f624ab385133"
5 | },
6 | "host-environment-markers": {
7 | "implementation_name": "cpython",
8 | "implementation_version": "3.6.4",
9 | "os_name": "posix",
10 | "platform_machine": "x86_64",
11 | "platform_python_implementation": "CPython",
12 | "platform_release": "4.15.4-1-ARCH",
13 | "platform_system": "Linux",
14 | "platform_version": "#1 SMP PREEMPT Sat Feb 17 16:01:38 UTC 2018",
15 | "python_full_version": "3.6.4",
16 | "python_version": "3.6",
17 | "sys_platform": "linux"
18 | },
19 | "pipfile-spec": 6,
20 | "requires": {},
21 | "sources": [
22 | {
23 | "name": "pypi",
24 | "url": "https://pypi.python.org/simple",
25 | "verify_ssl": true
26 | }
27 | ]
28 | },
29 | "default": {
30 | "certifi": {
31 | "hashes": [
32 | "sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296",
33 | "sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d"
34 | ],
35 | "version": "==2018.1.18"
36 | },
37 | "chardet": {
38 | "hashes": [
39 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
40 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
41 | ],
42 | "version": "==3.0.4"
43 | },
44 | "defusedxml": {
45 | "hashes": [
46 | "sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20",
47 | "sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4"
48 | ],
49 | "version": "==0.5.0"
50 | },
51 | "django": {
52 | "hashes": [
53 | "sha256:7c8ff92285406fb349e765e9ade685eec7271d6f5c3f918e495a74768b765c99",
54 | "sha256:dc3b61d054f1bced64628c62025d480f655303aea9f408e5996c339a543b45f0"
55 | ],
56 | "version": "==2.0.2"
57 | },
58 | "django-allauth": {
59 | "hashes": [
60 | "sha256:7b31526cccd1c46f9f09acf0703068e8a9669337d29eb065f7e8143c2d897339"
61 | ],
62 | "version": "==0.35.0"
63 | },
64 | "django-cors-headers": {
65 | "hashes": [
66 | "sha256:4e02be61ffaaab5917f1fd7cc3c305c4fb7ccd0156a649c96f49bc0a09c5f572",
67 | "sha256:451bc37a514792c2b46c52362368f7985985933ecdbf1a85f82652579a5cbe01"
68 | ],
69 | "version": "==2.1.0"
70 | },
71 | "django-rest-auth": {
72 | "hashes": [
73 | "sha256:ad155a0ed1061b32e3e46c9b25686e397644fd6acfd35d5c03bc6b9d2fc6c82a"
74 | ],
75 | "version": "==0.9.3"
76 | },
77 | "djangorestframework": {
78 | "hashes": [
79 | "sha256:1f6baf40ed456ed2af6bd1a4ff8bbc3503cebea16509993aea2b7085bc097766",
80 | "sha256:9f9e94e8d22b100ed3a43cee8c47a7ff7b185e778a1f2da9ec5c73fc4e081b87"
81 | ],
82 | "version": "==3.7.7"
83 | },
84 | "djangorestframework-jwt": {
85 | "hashes": [
86 | "sha256:ab15dfbbe535eede8e2e53adaf52ef0cf018ee27dbfad10cbc4cbec2ab63d38c",
87 | "sha256:5efe33032f3a4518a300dc51a51c92145ad95fb6f4b272e5aa24701db67936a7"
88 | ],
89 | "version": "==1.11.0"
90 | },
91 | "idna": {
92 | "hashes": [
93 | "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
94 | "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
95 | ],
96 | "version": "==2.6"
97 | },
98 | "oauthlib": {
99 | "hashes": [
100 | "sha256:ce57b501e906ff4f614e71c36a3ab9eacbb96d35c24d1970d2539bbc3ec70ce1"
101 | ],
102 | "version": "==2.0.6"
103 | },
104 | "pillow": {
105 | "hashes": [
106 | "sha256:718ec7a122b28d64afc5fbc3a9b99bb0545ef511373cac06fe7624520e82cb20",
107 | "sha256:801cca8923508311bf5d6d0f7da5362552e8208ebd8ec0d7b9f2cd2ff5705734",
108 | "sha256:43334f9581cd067945b8898cef9eb5714ee4883f8de0304c011f1dbdb1d4e2aa",
109 | "sha256:153ec6f18f7b61641e0e6e502acfaf4a06c9aba2ea11c0b4b3578ea9f13a4a4a",
110 | "sha256:25193f934d37d836a6b1f4c062ce574a96cbca7c6d9dc8ddfbbac7f9c54deaa4",
111 | "sha256:b85f703c2ffe539313e39ce0676bed0f355cec45a16e58c9ab7417445843047c",
112 | "sha256:8580fc58074a16b749905b26cf8363f7b628dd167ba0130f5382cdc91c86b509",
113 | "sha256:2fcde9954c8882d1c7f93bb828caa34a4c5e3ee69dbc7895dc8652ad972b455a",
114 | "sha256:1a5b93084e01328a1cb1ecdad99d11d75e881e89a95f88d85b523646553b36c2",
115 | "sha256:b2240f298482f823576f397bb9f32ea913ad9456c526e141bc6f0a022b37a3e8",
116 | "sha256:b1d33c63a55d0d85df0ad02b2c16158fb4d8153afa7b908f1a67330fac694cd6",
117 | "sha256:6977cf073d83358b34f93abf5c1f1193b88675fe0e4441e0e28318bc3dcba7a0",
118 | "sha256:1912b7230459fd53682dae32b83cbd8e5d642ba36d4be18566f00a9c063aa13d",
119 | "sha256:4bd4a71501b6d51db4abc07e1f43f5a6fed0a1a9583cca0b401d6af50284b0db",
120 | "sha256:0013f590a8f260df60bcfd65db19d18efc04e7f046c3c82a40e2e2b3292a937c",
121 | "sha256:a224651a81e45ef4f1d0164e256c5f6b4abb49f2ae8f22ba2f3a9d0ff338e608",
122 | "sha256:c793dfaa130847ccff958492b76ae8b9304e60b8a79a92962cb19e368276a22b",
123 | "sha256:0b899ee80920bb533f26581af9b4660bc12aff4562555afe74e429101ebf3c94",
124 | "sha256:9525cd680a6f9e80c6c0af03cf973e6505c59f60b4745f682cd1a449e54b31bb",
125 | "sha256:35f7d998b8e82fb3fb51ff88b30485eb81cd7dd56ec7e1a8deba23eb88532d44",
126 | "sha256:5b0d657460d9f3615876fec6306e97ca15a471f6169b622d76a47e270998acf1",
127 | "sha256:ddd16ab250b4fc97db1c47407e78c25216a75c29d29d10ad37e51b7a2ec7b2c3",
128 | "sha256:b9f63451084a718eccdeb1e382768c94647915653af4d6019f64560d9e98642b",
129 | "sha256:a370d1c570f1d72e877099651e752332444b1c5009381f043c9da5fd47f3ebae",
130 | "sha256:dc4b018d5c9b636f7546583c5591b9ea00c328c3e5871992ef5b95bac353f097",
131 | "sha256:e126ff4fed71e78333840c07279e1617f63cfca76d63ad5b27d65a7277206a3d",
132 | "sha256:fcf64c91fd44485100a2965d23bb0e227d093e91f7e776c5ca3b32574766eb56",
133 | "sha256:2c042352b430d678db50c78c5214e19638eff8b688941271da2de21fd298dfe5",
134 | "sha256:17fe25efc785194d48c38fad85dce470013ba19d2fb66639e149f14bccf1327f",
135 | "sha256:2e818dbe445e86fc6c266973fe540c35125c42eb2cf13a6095e9adaa89c0deb5",
136 | "sha256:135e9aa65150c53f7db85bf2bebb8a0e1a48ea850e80cf66e16dd04fa09d309c",
137 | "sha256:7dfbefdb3fb911ca9faed307bf309861e9995e36cca6b761c7ba6d9b77a9744a",
138 | "sha256:12f29d6c23424f704c66b5b68c02fe0b571504459605cfe36ab8158359b0e1bb",
139 | "sha256:f8d49be8c282df8d2e1ab6ab53ab8abd859b1fa6fed384457ee85c9eff64ef97",
140 | "sha256:82b172e3264e62372c01b5b009b5b1a02fbb9276cbe5cc57ab00a6d6e5ed9a18",
141 | "sha256:57aa6198ba8acba1313c3b743e267d821a60cac77e6026caf0b55ca58d3d23be",
142 | "sha256:d60c1625b108432ace8b1fa1a584017e5efa73f107d0f493c7f39c79bebf1d41",
143 | "sha256:82d1ff571489765df2816785d532e243bde213752156c227fca595723ec5ff42",
144 | "sha256:37cc0339abfa9e295c75d9a7f227d35cb44716feb95057f9449c4a9e9a17daf7",
145 | "sha256:931030d1d6282b7900e6b0a7ff9ecdb503b5e1e6781800dab2b71a9f39405bff",
146 | "sha256:5cd36804f9f06a914a883fe682df5711d16d7b4f44d43189c5f013e7cd91e149"
147 | ],
148 | "version": "==5.0.0"
149 | },
150 | "pyjwt": {
151 | "hashes": [
152 | "sha256:a4e5f1441e3ca7b382fd0c0b416777ced1f97c64ef0c33bfa39daf38505cfd2f",
153 | "sha256:500be75b17a63f70072416843dc80c8821109030be824f4d14758f114978bae7"
154 | ],
155 | "version": "==1.5.3"
156 | },
157 | "python3-openid": {
158 | "hashes": [
159 | "sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa",
160 | "sha256:628d365d687e12da12d02c6691170f4451db28d6d68d050007e4a40065868502"
161 | ],
162 | "version": "==3.1.0"
163 | },
164 | "pytz": {
165 | "hashes": [
166 | "sha256:ed6509d9af298b7995d69a440e2822288f2eca1681b8cce37673dbb10091e5fe",
167 | "sha256:f93ddcdd6342f94cea379c73cddb5724e0d6d0a1c91c9bdef364dc0368ba4fda",
168 | "sha256:61242a9abc626379574a166dc0e96a66cd7c3b27fc10868003fa210be4bff1c9",
169 | "sha256:ba18e6a243b3625513d85239b3e49055a2f0318466e0b8a92b8fb8ca7ccdf55f",
170 | "sha256:07edfc3d4d2705a20a6e99d97f0c4b61c800b8232dc1c04d87e8554f130148dd",
171 | "sha256:3a47ff71597f821cd84a162e71593004286e5be07a340fd462f0d33a760782b5",
172 | "sha256:5bd55c744e6feaa4d599a6cbd8228b4f8f9ba96de2c38d56f08e534b3c9edf0d",
173 | "sha256:887ab5e5b32e4d0c86efddd3d055c1f363cbaa583beb8da5e22d2fa2f64d51ef",
174 | "sha256:410bcd1d6409026fbaa65d9ed33bf6dd8b1e94a499e32168acfc7b332e4095c0"
175 | ],
176 | "version": "==2018.3"
177 | },
178 | "requests": {
179 | "hashes": [
180 | "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
181 | "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
182 | ],
183 | "version": "==2.18.4"
184 | },
185 | "requests-oauthlib": {
186 | "hashes": [
187 | "sha256:50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca",
188 | "sha256:883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468"
189 | ],
190 | "version": "==0.8.0"
191 | },
192 | "six": {
193 | "hashes": [
194 | "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
195 | "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
196 | ],
197 | "version": "==1.11.0"
198 | },
199 | "urllib3": {
200 | "hashes": [
201 | "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
202 | "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
203 | ],
204 | "version": "==1.22"
205 | }
206 | },
207 | "develop": {
208 | "flake8": {
209 | "hashes": [
210 | "sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37",
211 | "sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0"
212 | ],
213 | "version": "==3.5.0"
214 | },
215 | "mccabe": {
216 | "hashes": [
217 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
218 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
219 | ],
220 | "version": "==0.6.1"
221 | },
222 | "pycodestyle": {
223 | "hashes": [
224 | "sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9",
225 | "sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766"
226 | ],
227 | "version": "==2.3.1"
228 | },
229 | "pyflakes": {
230 | "hashes": [
231 | "sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
232 | "sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"
233 | ],
234 | "version": "==1.6.0"
235 | }
236 | }
237 | }
238 |
--------------------------------------------------------------------------------