├── .gitignore ├── LICENSE ├── README.md ├── cookiecutter.json └── {{cookiecutter.github_repository_name}} └── src ├── .coveragerc ├── .travis.yml ├── Procfile ├── README.md ├── docs ├── api │ ├── authentication.md │ └── users.md └── index.md ├── fabfile.py ├── frontend ├── .editorconfig ├── .travis.yml ├── README.md ├── config │ ├── head-config.common.js │ ├── helpers.js │ ├── html-elements-plugin │ │ └── index.js │ ├── karma.conf.js │ ├── modules │ │ └── angular2-hmr-prod.js │ ├── protractor.conf.js │ ├── spec-bundle.js │ ├── webpack.common.js │ ├── webpack.dev.js │ ├── webpack.prod.js │ └── webpack.test.js ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── src │ ├── app │ │ ├── +detail │ │ │ ├── detail.component.ts │ │ │ └── index.ts │ │ ├── about │ │ │ ├── about.component.ts │ │ │ ├── about.spec.ts │ │ │ └── index.ts │ │ ├── app.component.ts │ │ ├── app.e2e.ts │ │ ├── app.module.ts │ │ ├── app.resolver.ts │ │ ├── app.routes.ts │ │ ├── app.service.ts │ │ ├── app.spec.ts │ │ ├── app.style.css │ │ ├── environment.ts │ │ ├── home │ │ │ ├── home.component.ts │ │ │ ├── home.e2e.ts │ │ │ ├── home.spec.ts │ │ │ ├── home.style.scss │ │ │ ├── home.template.pug │ │ │ ├── index.ts │ │ │ ├── title │ │ │ │ ├── index.ts │ │ │ │ ├── title.service.ts │ │ │ │ └── title.spec.ts │ │ │ └── x-large │ │ │ │ ├── index.ts │ │ │ │ ├── x-large.directive.ts │ │ │ │ └── x-large.spec.ts │ │ ├── index.ts │ │ ├── md.module.ts │ │ └── no-content │ │ │ ├── index.ts │ │ │ └── no-content.ts │ ├── assets │ │ ├── css │ │ │ └── .gitkeep │ │ ├── data.json │ │ ├── humans.txt │ │ ├── icon │ │ │ ├── android-icon-144x144.png │ │ │ ├── android-icon-192x192.png │ │ │ ├── android-icon-36x36.png │ │ │ ├── android-icon-48x48.png │ │ │ ├── android-icon-72x72.png │ │ │ ├── android-icon-96x96.png │ │ │ ├── apple-icon-114x114.png │ │ │ ├── apple-icon-120x120.png │ │ │ ├── apple-icon-144x144.png │ │ │ ├── apple-icon-152x152.png │ │ │ ├── apple-icon-180x180.png │ │ │ ├── apple-icon-57x57.png │ │ │ ├── apple-icon-60x60.png │ │ │ ├── apple-icon-72x72.png │ │ │ ├── apple-icon-76x76.png │ │ │ ├── apple-icon-precomposed.png │ │ │ ├── apple-icon.png │ │ │ ├── browserconfig.xml │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon-96x96.png │ │ │ ├── favicon.ico │ │ │ ├── ms-icon-144x144.png │ │ │ ├── ms-icon-150x150.png │ │ │ ├── ms-icon-310x310.png │ │ │ └── ms-icon-70x70.png │ │ ├── img │ │ │ ├── angular-logo.png │ │ │ ├── angularclass-avatar.png │ │ │ └── angularclass-logo.png │ │ ├── manifest.json │ │ ├── mock-data │ │ │ └── mock-data.json │ │ ├── robots.txt │ │ └── service-worker.js │ ├── custom-typings.d.ts │ ├── index.html │ ├── main.browser.ts │ ├── polyfills.browser.ts │ └── vendor.browser.ts ├── tsconfig.json ├── tslint.json ├── typedoc.json └── webpack.config.js ├── mkdocs.yml ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests ├── setup.py └── {{cookiecutter.app_name}}_tests │ ├── __init__.py │ ├── authentication │ ├── __init__.py │ └── test_signals.py │ └── users │ ├── __init__.py │ ├── factories.py │ ├── test_serializers.py │ └── test_views.py └── {{cookiecutter.app_name}} ├── __init__.py ├── authentication ├── __init__.py ├── migrations │ └── __init__.py ├── models.py ├── urls.py └── views.py ├── config ├── __init__.py ├── common.py ├── local.py └── production.py ├── manage.py ├── urls.py ├── users ├── __init__.py ├── admin.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── permissions.py ├── serializers.py └── views.py └── wsgi.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | src/frontend/node_modules 3 | frontend/.gitignore 4 | frontend/src/app/about/about.spec.ts 5 | frontend/src/app/app.spec.ts 6 | frontend/src/app/app.style.css 7 | frontend/src/app/home/home.spec.ts 8 | frontend/src/app/home/home.style.scss 9 | frontend/src/app/home/home.template.pug 10 | frontend/src/app/home/title/title.spec.ts 11 | frontend/src/app/home/x-large/x-large.spec.ts 12 | frontend/src/app/md.module.ts 13 | frontend/src/app/no-content/no-content.ts 14 | 15 | *.pyc 16 | bin 17 | build 18 | include 19 | local 20 | man 21 | share 22 | Scripts 23 | .Python 24 | *~ 25 | *.sqlite3 26 | .DS_Store 27 | .env 28 | static 29 | 30 | # @AngularClass 31 | 32 | # Logs 33 | logs 34 | *.log 35 | 36 | # Runtime data 37 | pids 38 | *.pid 39 | *.seed 40 | 41 | # Directory for instrumented libs generated by jscoverage/JSCover 42 | lib-cov 43 | 44 | # Coverage directory used by tools like istanbul 45 | coverage 46 | 47 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 48 | .grunt 49 | 50 | # Compiled binary addons (http://nodejs.org/api/addons.html) 51 | build/Release 52 | 53 | # Users Environment Variables 54 | .lock-wscript 55 | 56 | # OS generated files # 57 | ehthumbs.db 58 | Icon? 59 | Thumbs.db 60 | 61 | # Node Files # 62 | /node_modules 63 | /bower_components 64 | npm-debug.log 65 | 66 | # Coverage # 67 | /coverage/ 68 | 69 | # Typing # 70 | /src/typings/tsd/ 71 | /typings/ 72 | /tsd_typings/ 73 | 74 | # Dist # 75 | /dist 76 | /public/__build__/ 77 | /src/*/__build__/ 78 | /__build__/** 79 | /public/dist/ 80 | /src/*/dist/ 81 | /dist/** 82 | /.awcache 83 | .webpack.json 84 | 85 | # Doc # 86 | /doc/ 87 | 88 | # IDE # 89 | .idea/ 90 | *.swp 91 | 92 | *.db 93 | 94 | html/ 95 | htmlcov/ 96 | coverage/ 97 | .coverage 98 | .tox 99 | nosetests.xml 100 | build/ 101 | dist/ 102 | *.egg-info/ 103 | MANIFEST 104 | 105 | bin/ 106 | include/ 107 | lib/ 108 | local/ 109 | 110 | pip-log.txt 111 | 112 | env 113 | site 114 | 115 | scripts/make_angular_templates_raw.py 116 | */src/frontend/node_modules 117 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Amit Assaraf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular 2 django boilerplate 2 | by @amitassaraf 3 | 4 | ![enter image description here](https://travis-ci.org/agconti/cookiecutter-django-rest.svg?branch=master) 5 | 6 | Overview 7 | === 8 | This is a flexiable boilerplate for Angular 2 and Django. 9 | It also uses cookiecutter. 10 | 11 | This repository is a merge of a django boilerplate and @AngularClass's angular2-webpack-starter. 12 | 13 | Quickstart 14 | === 15 | 16 | To begin: 17 | 18 | Either use - 19 | 20 | ```bash 21 | cookiecutter gh:amitassaraf/angular2-django-boilerplate 22 | ``` 23 | 24 | or 25 | 26 | ```bash 27 | git clone https://github.com/amitassaraf/angular2-django-boilerplate 28 | 29 | cd angular2-django-boilerplate 30 | 31 | cookiecutter . 32 | ``` 33 | 34 | Then fill in all the information asked. 35 | 36 | If you don't have cookie cutter, install it using: 37 | ```bash 38 | pip install cookiecutter 39 | ``` 40 | 41 | Frontend 42 | ----- 43 | ----- 44 | 45 | After running cookiecutter, enter yourappname/src/frontend 46 | and run: 47 | ```bash 48 | sudo npm install 49 | ``` 50 | 51 | Then run: 52 | ```bash 53 | npm start 54 | ``` 55 | To start the development web pack server and make sure everything is working good. 56 | 57 | at this point you can surf to http://localhost:3000 to see the boilerplate front end website. 58 | 59 | Backend 60 | --- 61 | ----- 62 | 63 | Install all the requirements: 64 | ```bash 65 | pip install -r requirements.txt 66 | ``` 67 | 68 | Create the Django DB: 69 | ```bash 70 | createdb {{cookiecutter.app_name}} 71 | ``` 72 | 73 | Migrate the database and create a superuser: 74 | ```bash 75 | python {{cookiecutter.app_name}}/manage.py migrate 76 | python {{cookiecutter.app_name}}/manage.py createsuperuser 77 | ``` 78 | 79 | Start the development server: 80 | ```bash 81 | python {{cookiecutter.app_name}}/manage.py runserver 82 | ``` 83 | 84 | Contact Me 85 | --- 86 | --- 87 | If you have any problems/suggestions you can always contact me 88 | 89 | **Email**: amitassaraf@me.com 90 | **Website**: http://amitassaraf.com 91 | -------------------------------------------------------------------------------- /cookiecutter.json: -------------------------------------------------------------------------------- 1 | { 2 | "github_repository_name": "my_app_g", 3 | "app_name": "my_app", 4 | "app_title": "{{cookiecutter.app_name | replace('_', ' ') | replace('-', ' ') | title}}", 5 | "angular_app_name": "{{cookiecutter.app_title | replace(cookiecutter.app_title | first, cookiecutter.app_title | first | lower, 1) | replace(' ', '')}}", 6 | "email": "amitassaraf@me.com", 7 | "description": "An angular 2 & django boilerplate", 8 | "github_username": "amitassaraf", 9 | "_copy_without_render": [ 10 | "*node_modules" 11 | ] 12 | } -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | omit = *migrations*, 4 | *urls*, 5 | *test*, 6 | *admin*, 7 | ./{{ cookiecutter.app_name }}/config/*, 8 | ./{{ cookiecutter.app_name }}/manage.py, 9 | ./{{ cookiecutter.app_name }}/wsgi.py, 10 | *__init__* 11 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | services: 3 | - postgresql 4 | - redis-server 5 | python: 6 | - "2.7" 7 | before_script: 8 | - export DATABASE_URL=postgres://postgres@localhost/{{ cookiecutter.app_name }} 9 | - export DJANGO_SECRET=`openssl rand -base64 32` 10 | - psql -c 'CREATE DATABASE "{{ cookiecutter.app_name }}";' -U postgres 11 | install: 12 | - "pip install -r requirements/test.txt" 13 | script: 14 | - ./{{cookiecutter.app_name}}/manage.py test {{cookiecutter.app_name}} 15 | after_success: 16 | - coveralls 17 | 18 | deploy: 19 | provider: heroku 20 | app: 21 | master: {{cookiecutter.app_name}}-dev 22 | qa: {{cookiecutter.app_name}}-qa 23 | prod: {{cookiecutter.app_name}}-prod 24 | on: 25 | repo: {{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}} 26 | run: 27 | - "./{{cookiecutter.app_name}}/manage.py migrate" 28 | 29 | notifications: 30 | email: false 31 | 32 | # This reportedly works around an issue downloading packages from pypi on 33 | # travis. Consider removing this after the underlying issue is fixed. 34 | # https://github.com/travis-ci/travis-ci/issues/2389 35 | sudo: false 36 | 37 | matrix: 38 | fast_finish: true 39 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/Procfile: -------------------------------------------------------------------------------- 1 | web: newrelic-admin run-program gunicorn --pythonpath="$PWD/{{ cookiecutter.app_name }}" wsgi:application 2 | worker: python {{cookiecutter.app_name}}/manage.py rqworker default -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/README.md: -------------------------------------------------------------------------------- 1 | #{{cookiecutter.github_repository_name}} 2 | [![Build Status](https://travis-ci.org/{{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}}.svg?branch=master)](https://travis-ci.org/{{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}}) 3 | 4 | {{cookiecutter.description}}. Check out the project's [documentation](http://{{cookiecutter.github_username}}.github.io/{{cookiecutter.github_repository_name}}/). 5 | 6 | # Prerequisites 7 | - [virtualenv](https://virtualenv.pypa.io/en/latest/) 8 | - [postgresql](http://www.postgresql.org/) 9 | - [redis](http://redis.io/) 10 | - [travis cli](http://blog.travis-ci.com/2013-01-14-new-client/) 11 | - [heroku toolbelt](https://toolbelt.heroku.com/) 12 | 13 | # Initialize the project 14 | Create and activate a virtualenv: 15 | 16 | ```bash 17 | virtualenv env 18 | source env/bin/activate 19 | ``` 20 | Install dependencies: 21 | 22 | ```bash 23 | pip install -r requirements/local.txt 24 | ``` 25 | Create the database: 26 | 27 | ```bash 28 | createdb {{cookiecutter.app_name}} 29 | ``` 30 | Initialize the git repository 31 | 32 | ``` 33 | git init 34 | git remote add origin git@github.com:{{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}}.git 35 | ``` 36 | 37 | Migrate the database and create a superuser: 38 | ```bash 39 | python {{cookiecutter.app_name}}/manage.py migrate 40 | python {{cookiecutter.app_name}}/manage.py createsuperuser 41 | ``` 42 | 43 | Run the development server: 44 | ```bash 45 | python {{cookiecutter.app_name}}/manage.py runserver 46 | ``` 47 | 48 | # Create Servers 49 | By default the included fabfile will setup three environments: 50 | 51 | - dev -- The bleeding edge of development 52 | - qa -- For quality assurance testing 53 | - prod -- For the live application 54 | 55 | Create these servers on Heroku with: 56 | 57 | ```bash 58 | fab init 59 | ``` 60 | 61 | # Automated Deployment 62 | Deployment is handled via Travis. When builds pass Travis will automatically deploy that branch to Heroku. Enable this with: 63 | ```bash 64 | travis encrypt $(heroku auth:token) --add deploy.api_key 65 | ``` 66 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/docs/api/authentication.md: -------------------------------------------------------------------------------- 1 | # Authentication 2 | For clients to authenticate, the token key should be included in the Authorization HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example: 3 | 4 | ``` 5 | Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b 6 | ``` 7 | 8 | Unauthenticated responses that are denied permission will result in an HTTP `401 Unauthorized` response with an appropriate `WWW-Authenticate` header. For example: 9 | 10 | ``` 11 | WWW-Authenticate: Token 12 | ``` 13 | 14 | The curl command line tool may be useful for testing token authenticated APIs. For example: 15 | 16 | ```bash 17 | curl -X GET http://127.0.0.1:8000/api/v1/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' 18 | ``` 19 | 20 | ## Retrieving Tokens 21 | Authorization tokens are issued and returned when a user registers. A registered user can also retrieve their token with the following request: 22 | 23 | **Request**: 24 | 25 | `POST` `api-token-auth/` 26 | 27 | Parameters: 28 | 29 | Name | Type | Description 30 | ---|---|--- 31 | username | string | The user's username 32 | password | string | The user's password 33 | 34 | **Response**: 35 | ```json 36 | { 37 | "token" : "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/docs/api/users.md: -------------------------------------------------------------------------------- 1 | # Users 2 | Supports registering, viewing, and updating user accounts. 3 | 4 | ## Register a new user account 5 | 6 | **Request**: 7 | 8 | `POST` `/users/` 9 | 10 | Parameters: 11 | 12 | Name | Type | Description 13 | ---------|--------|--- 14 | username | string | The username for the new user. 15 | password | string | The password for the new user. 16 | 17 | *Note:* 18 | 19 | - *Not* **Authorization Protected** 20 | 21 | **Response**: 22 | 23 | ```json 24 | Content-Type application/json 25 | 201 Created 26 | 27 | { 28 | "id": "6d5f9bae-a31b-4b7b-82c4-3853eda2b011", 29 | "username": "richard", 30 | "password": "pbkdf2_sha256$24000$aGozcCr6QXhv$WCgPt2voqVO+Nno2flVnNnLcfks6Yq8XJyxoadB/r50=", 31 | "auth_token": "132cf952e0165a274bf99e115ab483671b3d9ff6" 32 | } 33 | ``` 34 | 35 | The `auth_token` returned with this response should be stored by the client for 36 | authenticating future requests to the API. See [Authentication](authentication.md). 37 | 38 | 39 | ## Get a user's profile information 40 | 41 | **Request**: 42 | 43 | `GET` `/users/:id` 44 | 45 | Parameters: 46 | 47 | *Note:* 48 | 49 | - **[Authorization Protected](authentication.md)** 50 | 51 | **Response**: 52 | 53 | ```json 54 | Content-Type application/json 55 | 200 OK 56 | 57 | { 58 | "id": "6d5f9bae-a31b-4b7b-82c4-3853eda2b011", 59 | "username": "richard", 60 | "first_name": "Richard", 61 | "last_name": "Hendriks" 62 | } 63 | ``` 64 | 65 | 66 | ## Update your profile information 67 | 68 | **Request**: 69 | 70 | `PUT/PATCH` `/users/:id` 71 | 72 | Parameters: 73 | 74 | Name | Type | Description 75 | -----------|--------|--- 76 | first_name | string | The new first_name of the user object. 77 | last_name | string | The new last_name of the user object. 78 | 79 | 80 | *Note:* 81 | 82 | - All parameters are optional 83 | - **[Authorization Protected](authentication.md)** 84 | 85 | **Response**: 86 | 87 | ```json 88 | Content-Type application/json 89 | 200 OK 90 | 91 | { 92 | "id": "6d5f9bae-a31b-4b7b-82c4-3853eda2b011", 93 | "username": "richard", 94 | "first_name": "Richard", 95 | "last_name": "Hendriks" 96 | } 97 | ``` 98 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/docs/index.md: -------------------------------------------------------------------------------- 1 | #{{cookiecutter.github_repository_name}} 2 | [![Build Status](https://travis-ci.org/{{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}}.svg?branch=master)](https://travis-ci.org/{{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}}) 3 | 4 | {{cookiecutter.description}}. Check out the project's [documentation](http://{{cookiecutter.github_username}}.github.io/{{cookiecutter.github_repository_name}}/). 5 | 6 | # Prerequisites 7 | - [virtualenv](https://virtualenv.pypa.io/en/latest/) 8 | - [postgresql](http://www.postgresql.org/) 9 | - [redis](http://redis.io/) 10 | - [travis cli](http://blog.travis-ci.com/2013-01-14-new-client/) 11 | - [heroku toolbelt](https://toolbelt.heroku.com/) 12 | 13 | # Initialize the project 14 | Create and activate a virtualenv: 15 | 16 | ```bash 17 | virtualenv env 18 | source env/bin/activate 19 | ``` 20 | Install dependencies: 21 | 22 | ```bash 23 | pip install -r requirements/local.txt 24 | ``` 25 | Create the database: 26 | 27 | ```bash 28 | createdb {{cookiecutter.app_name}} 29 | ``` 30 | Initialize the git repository 31 | 32 | ``` 33 | git init 34 | git remote add origin git@github.com:{{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}}.git 35 | ``` 36 | 37 | Migrate, create a superuser, and run the server: 38 | ```bash 39 | python {{cookiecutter.app_name}}/manage.py migrate 40 | python {{cookiecutter.app_name}}/manage.py createsuperuser 41 | python {{cookiecutter.app_name}}/manage.py runserver 42 | ``` 43 | 44 | # Create Servers 45 | By default the included fabfile will setup three environments: 46 | 47 | - dev -- The bleeding edge of development 48 | - qa -- For quality assurance testing 49 | - prod -- For the live application 50 | 51 | Create these servers on Heroku with: 52 | 53 | ```bash 54 | fab init 55 | ``` 56 | 57 | # Automated Deployment 58 | Deployment is handled via Travis. When builds pass Travis will automatically deploy that branch to Heroku. Enable this with: 59 | ```bash 60 | travis encrypt $(heroku auth:token) --add deploy.api_key 61 | ``` 62 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/fabfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import string 4 | 5 | from fabric.api import env, local, require, lcd 6 | from fabric.colors import cyan 7 | from fabric.operations import prompt 8 | 9 | current_dir = os.getcwd() 10 | env.project_name = '{{cookiecutter.app_name}}' 11 | env.branch = 'master' 12 | env.environments = ['dev', 13 | 'qa', 14 | 'prod'] 15 | 16 | 17 | def serve(): 18 | local('python {}/manage.py runserver'.format(env.project_name)) 19 | 20 | 21 | def test(): 22 | """ 23 | Runs nose test suite 24 | """ 25 | local('flake8 {}'.format(env.project_name)) 26 | print cyan('flake8 passed!', bold=True) 27 | local('python {}/manage.py test'.format(env.project_name)) 28 | 29 | 30 | def init(): 31 | """ 32 | Deploys servers 33 | """ 34 | print cyan('Initializing...', bold=True) 35 | set_remotes() 36 | ask_for_aws_keys() 37 | for environment in env.environments: 38 | env.environment = environment 39 | env.server_name = '{}-{}'.format(env.project_name, env.environment) 40 | create_standard_server() 41 | deploy_docs() 42 | 43 | 44 | def set_remotes(): 45 | """ 46 | Sets git remotes based on project structure 47 | """ 48 | require('project_name') 49 | print cyan('Setting git remotes...') 50 | 51 | local('git remote add dev git@heroku.com:{}-dev.git'.format(env.project_name)) 52 | local('git remote add qa git@heroku.com:{}-qa.git'.format(env.project_name)) 53 | local('git remote add prod git@heroku.com:{}-prod.git'.format(env.project_name)) 54 | 55 | 56 | def ask_for_aws_keys(): 57 | """ 58 | Gets AWS keys from user 59 | """ 60 | env.aws_access = prompt('AWS_ACCESS_KEY_ID?') 61 | env.aws_secret = prompt('AWS_SECRET_ACCESS_KEY?') 62 | 63 | 64 | def create_standard_server(): 65 | """ 66 | Creates a sever with a standard build 67 | """ 68 | create_server() 69 | configure_sever() 70 | push() 71 | migrate() 72 | create_superuser() 73 | ps() 74 | open_heroku() 75 | 76 | 77 | def create_server(): 78 | """ 79 | Creates a new server on heroku 80 | """ 81 | require('environment') 82 | require('project_name') 83 | 84 | print cyan('Creating new server'.format(env.project_name, env.environment)) 85 | require('environment') 86 | local('heroku create {}-{} --buildpack https://github.com/heroku/heroku-buildpack-python' 87 | .format(env.project_name, env.environment)) 88 | 89 | 90 | def configure_sever(): 91 | """ 92 | Configures server with a general configuration 93 | """ 94 | require('environment') 95 | local('heroku addons:create heroku-postgresql --remote {}'.format(env.environment)) 96 | local('heroku pg:backups schedule DATABASE --at "04:00 UTC" --remote {}'.format(env.environment)) 97 | local('heroku pg:promote DATABASE_URL --remote {}'.format(env.environment)) 98 | local('heroku addons:create redistogo:nano --remote {}'.format(env.environment)) 99 | local('heroku addons:create newrelic:wayne --remote {}'.format(env.environment)) 100 | local('heroku config:set NEW_RELIC_APP_NAME="{}" --remote {}'.format(env.project_name, env.environment)) 101 | local('heroku config:set DJANGO_CONFIGURATION=Production --remote {}'.format(env.environment)) 102 | local('heroku config:set DJANGO_SECRET_KEY="{}" --remote {}'.format(create_secret_key(), env.environment)) 103 | set_aws_keys() 104 | 105 | 106 | def deploy_docs(): 107 | print cyan('Deploying docs...') 108 | local('mkdocs gh-deploy') 109 | 110 | 111 | def push(): 112 | require('environment') 113 | require('branch') 114 | 115 | print cyan('Pushing to Heroku...') 116 | require('environment') 117 | local('git push {} {}:master'.format(env.environment, env.branch)) 118 | 119 | 120 | def migrate(): 121 | require('environment') 122 | local('heroku run python {}/manage.py migrate --remote {}'.format(env.project_name, 123 | env.environment)) 124 | 125 | def create_superuser(): 126 | require('environment') 127 | local('heroku run python {}/manage.py ' 128 | 'createsuperuser --remote {}'.format(env.project_name, env.environment)) 129 | 130 | 131 | def ps(): 132 | """ 133 | Scales a web dyno on Heroku 134 | """ 135 | require('environment') 136 | local('heroku ps:scale web=1:hobby --remote {}'.format(env.environment)) 137 | 138 | 139 | def open_heroku(): 140 | require('environment') 141 | local('heroku open --remote {}'.format(env.environment)) 142 | 143 | 144 | def set_aws_keys(): 145 | """ 146 | Configures S3 Keys 147 | """ 148 | require('aws_access') 149 | require('aws_secret') 150 | require('project_name') 151 | 152 | local('heroku config:set DJANGO_AWS_ACCESS_KEY_ID={} --remote {}' 153 | .format(env.aws_access, env.environment)) 154 | local('heroku config:set DJANGO_AWS_SECRET_ACCESS_KEY={} --remote {}' 155 | .format(env.aws_secret, env.environment)) 156 | local('heroku config:set DJANGO_AWS_STORAGE_BUCKET_NAME={0}-{1} --remote {1}' 157 | .format(env.project_name, env.environment)) 158 | 159 | 160 | def create_secret_key(): 161 | """ 162 | Creates a random string of letters and numbers 163 | """ 164 | return ''.join(random.choice(string.ascii_letters + string.digits) for i in range(30)) 165 | 166 | 167 | def dev(): 168 | """fab dev [command]""" 169 | env.environment = 'dev' 170 | env.branch = 'master' 171 | 172 | 173 | def qa(): 174 | """fab staging [command]""" 175 | env.environment = 'qa' 176 | env.branch = 'qa' 177 | 178 | 179 | def prod(): 180 | """fab staging [command]""" 181 | env.environment = 'prod' 182 | env.branch = 'prod' 183 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # @AngularClass 2 | # http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | insert_final_newline = false 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "5" 5 | - "node" 6 | before_install: 7 | - export CHROME_BIN=chromium-browser 8 | - export DISPLAY=:99.0 9 | - sh -e /etc/init.d/xvfb start 10 | - sleep 3 11 | sudo: false 12 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Angular 2 Fundamentals 4 | 5 |

6 | 7 | ___ 8 | 9 | 10 | 11 | [![taylor swift](https://img.shields.io/badge/secured%20by-taylor%20swift-brightgreen.svg)](https://twitter.com/SwiftOnSecurity) 12 | [![volkswagen status](https://auchenberg.github.io/volkswagen/volkswargen_ci.svg?v=1)](https://github.com/auchenberg/volkswagen) [![GitHub version](https://badge.fury.io/gh/angularclass%2Fangular2-webpack-starter.svg)](https://badge.fury.io/gh/angularclass%2Fangular2-webpack-starter) [![Dependency Status](https://david-dm.org/angularclass/angular2-webpack-starter.svg)](https://david-dm.org/angularclass/angular2-webpack-starter) 13 | [![Stack Share](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](http://stackshare.io/angularclass/angular-2-webpack-starter) 14 | 15 |

16 | 17 | Webpack and Angular 2 18 | 19 |

20 | 21 | # Angular2 Webpack Starter [![Join Slack](https://img.shields.io/badge/slack-join-brightgreen.svg)](https://angularclass.com/slack-join) [![Join the chat at https://gitter.im/angularclass/angular2-webpack-starter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angularclass/angular2-webpack-starter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 22 | 23 | 24 | > An Angular 2 starter kit featuring [Angular 2](https://angular.io) ([Router](https://angular.io/docs/js/latest/api/router/), [Forms](https://angular.io/docs/js/latest/api/forms/), 25 | [Http](https://angular.io/docs/js/latest/api/http/), 26 | [Services](https://gist.github.com/gdi2290/634101fec1671ee12b3e#_follow_@AngularClass_on_twitter), 27 | [Tests](https://angular.io/docs/js/latest/api/test/), [E2E](https://angular.github.io/protractor/#/faq#what-s-the-difference-between-karma-and-protractor-when-do-i-use-which-)), [Material](https://github.com/angular/material2), [Karma](https://karma-runner.github.io/), [Protractor](https://angular.github.io/protractor/), [Jasmine](https://github.com/jasmine/jasmine), [Istanbul](https://github.com/gotwarlost/istanbul), [TypeScript](http://www.typescriptlang.org/), [@types](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0ahUKEwjgjdrR7u_NAhUQ7GMKHXgpC4EQFggnMAI&url=https%3A%2F%2Fwww.npmjs.com%2F~types&usg=AFQjCNG2PFhwEo88JKo12mrw_4d0w1oNiA&sig2=N69zbO0yN8ET7v4KVCUOKA), [TsLint](http://palantir.github.io/tslint/), [Codelyzer](https://github.com/mgechev/codelyzer), [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement-with-webpack.html), and [Webpack 2](http://webpack.github.io/) by [AngularClass](https://angularclass.com). 28 | 29 | > If you're looking for Angular 1.x please use [NG6-starter](https://github.com/angularclass/NG6-starter) 30 | > If you're looking to learn about Webpack and ES6 Build Tools check out [ES6-build-tools](https://github.com/AngularClass/ES6-build-tools) 31 | > If you're looking to learn TypeScript see [TypeStrong/learn-typescript](https://github.com/TypeStrong/learn-typescript) 32 | > If you're looking for something easier to get started with then see the angular2-seed that I also maintain [angular/angular2-seed](https://github.com/AngularClass/angular2-seed) 33 | > If you're looking to add Angular 2 Material Design we have a branch [material2](https://github.com/AngularClass/angular2-webpack-starter/tree/material2) 34 | 35 | This seed repo serves as an Angular 2 starter for anyone looking to get up and running with Angular 2 and TypeScript fast. Using a [Webpack 2](http://webpack.github.io/) for building our files and assisting with boilerplate. We're also using Protractor for our end-to-end story and Karma for our unit tests. 36 | * Best practices in file and application organization for Angular 2. 37 | * Ready to go build system using Webpack for working with TypeScript. 38 | * Angular 2 examples that are ready to go when experimenting with Angular 2. 39 | * A great Angular 2 seed repo for anyone who wants to start their project. 40 | * Testing Angular 2 code with Jasmine and Karma. 41 | * Coverage with Istanbul and Karma 42 | * End-to-end Angular 2 code using Protractor. 43 | * Type manager with @types 44 | * Hot Module Replacement with Webpack and [@angularclass/hmr](https://github.com/angularclass/angular2-hmr) and [@angularclass/hmr-loader](https://github.com/angularclass/angular2-hmr-loader) 45 | * Material Design with [angular/material2](https://github.com/angular/material2) 46 | 47 | ### Quick start 48 | **Make sure you have Node version >= 5.0 and NPM >= 3** 49 | > Clone/Download the repo then edit `app.ts` inside [`/src/app/app.ts`](/src/app/app.ts) 50 | 51 | ```bash 52 | # clone our repo 53 | # --depth 1 removes all but one .git commit history 54 | git clone --depth 1 https://github.com/angularclass/angular2-webpack-starter.git 55 | 56 | # change directory to our repo 57 | cd angular2-webpack-starter 58 | 59 | # install the repo with npm 60 | npm install 61 | 62 | # start the server 63 | npm start 64 | 65 | # use Hot Module Replacement 66 | npm run server:dev:hmr 67 | 68 | # if you're in China use cnpm 69 | # https://github.com/cnpm/cnpm 70 | ``` 71 | go to [http://0.0.0.0:3000](http://0.0.0.0:3000) or [http://localhost:3000](http://localhost:3000) in your browser 72 | 73 | # Table of Contents 74 | * [File Structure](#file-structure) 75 | * [Getting Started](#getting-started) 76 | * [Dependencies](#dependencies) 77 | * [Installing](#installing) 78 | * [Running the app](#running-the-app) 79 | * [Configuration](#configuration) 80 | * [Contributing](#contributing) 81 | * [TypeScript](#typescript) 82 | * [@Types](#types) 83 | * [Frequently asked questions](#frequently-asked-questions) 84 | * [Support, Questions, or Feedback](#support-questions-or-feedback) 85 | * [License](#license) 86 | 87 | 88 | ## File Structure 89 | We use the component approach in our starter. This is the new standard for developing Angular apps and a great way to ensure maintainable code by encapsulation of our behavior logic. A component is basically a self contained app usually in a single file or a folder with each concern as a file: style, template, specs, e2e, and component class. Here's how it looks: 90 | ``` 91 | angular2-webpack-starter/ 92 | ├──config/ * our configuration 93 | | ├──helpers.js * helper functions for our configuration files 94 | | ├──spec-bundle.js * ignore this magic that sets up our angular 2 testing environment 95 | | ├──karma.conf.js * karma config for our unit tests 96 | | ├──protractor.conf.js * protractor config for our end-to-end tests 97 | │ ├──webpack.dev.js * our development webpack config 98 | │ ├──webpack.prod.js * our production webpack config 99 | │ └──webpack.test.js * our testing webpack config 100 | │ 101 | ├──src/ * our source files that will be compiled to javascript 102 | | ├──main.browser.ts * our entry file for our browser environment 103 | │ │ 104 | | ├──index.html * Index.html: where we generate our index page 105 | │ │ 106 | | ├──polyfills.ts * our polyfills file 107 | │ │ 108 | | ├──vendor.ts * our vendor file 109 | │ │ 110 | │ ├──app/ * WebApp: folder 111 | │ │ ├──app.spec.ts * a simple test of components in app.ts 112 | │ │ ├──app.e2e.ts * a simple end-to-end test for / 113 | │ │ └──app.ts * App.ts: a simple version of our App component components 114 | │ │ 115 | │ └──assets/ * static assets are served here 116 | │ ├──icon/ * our list of icons from www.favicon-generator.org 117 | │ ├──service-worker.js * ignore this. Web App service worker that's not complete yet 118 | │ ├──robots.txt * for search engines to crawl your website 119 | │ └──humans.txt * for humans to know who the developers are 120 | │ 121 | │ 122 | ├──tslint.json * typescript lint config 123 | ├──typedoc.json * typescript documentation generator 124 | ├──tsconfig.json * config that webpack uses for typescript 125 | ├──package.json * what npm uses to manage it's dependencies 126 | └──webpack.config.js * webpack main configuration file 127 | 128 | ``` 129 | 130 | # Getting Started 131 | ## Dependencies 132 | What you need to run this app: 133 | * `node` and `npm` (`brew install node`) 134 | * Ensure you're running the latest versions Node `v4.x.x`+ (or `v5.x.x`) and NPM `3.x.x`+ 135 | 136 | Once you have those, you should install these globals with `npm install --global`: 137 | * `webpack` (`npm install --global webpack`) 138 | * `webpack-dev-server` (`npm install --global webpack-dev-server`) 139 | * `karma` (`npm install --global karma-cli`) 140 | * `protractor` (`npm install --global protractor`) 141 | * `typescript` (`npm install --global typescript`) 142 | 143 | ## Installing 144 | * `fork` this repo 145 | * `clone` your fork 146 | * `npm install webpack-dev-server rimraf webpack -g` to install required global dependencies 147 | * `npm install` to install all dependencies 148 | * `npm run server` to start the dev server in another tab 149 | 150 | ## Running the app 151 | After you have installed all dependencies you can now run the app. Run `npm run server` to start a local server using `webpack-dev-server` which will watch, build (in-memory), and reload for you. The port will be displayed to you as `http://0.0.0.0:3000` (or if you prefer IPv6, if you're using `express` server, then it's `http://[::1]:3000/`). 152 | 153 | ### server 154 | ```bash 155 | # development 156 | npm run server 157 | # production 158 | npm run build:prod 159 | npm run server:prod 160 | ``` 161 | 162 | ## Other commands 163 | 164 | ### build files 165 | ```bash 166 | # development 167 | npm run build:dev 168 | # production 169 | npm run build:prod 170 | ``` 171 | 172 | ### hot module replacement 173 | ```bash 174 | npm run server:dev:hmr 175 | ``` 176 | 177 | ### watch and build files 178 | ```bash 179 | npm run watch 180 | ``` 181 | 182 | ### run tests 183 | ```bash 184 | npm run test 185 | ``` 186 | 187 | ### watch and run our tests 188 | ```bash 189 | npm run watch:test 190 | ``` 191 | 192 | ### run end-to-end tests 193 | ```bash 194 | # make sure you have your server running in another terminal 195 | npm run e2e 196 | ``` 197 | 198 | ### run webdriver (for end-to-end) 199 | ```bash 200 | npm run webdriver:update 201 | npm run webdriver:start 202 | ``` 203 | 204 | ### run Protractor's elementExplorer (for end-to-end) 205 | ```bash 206 | npm run webdriver:start 207 | # in another terminal 208 | npm run e2e:live 209 | ``` 210 | 211 | # Configuration 212 | Configuration files live in `config/` we are currently using webpack, karma, and protractor for different stages of your application 213 | 214 | # Contributing 215 | You can include more examples as components but they must introduce a new concept such as `Home` component (separate folders), and Todo (services). I'll accept pretty much everything so feel free to open a Pull-Request 216 | 217 | # TypeScript 218 | > To take full advantage of TypeScript with autocomplete you would have to install it globally and use an editor with the correct TypeScript plugins. 219 | 220 | ## Use latest TypeScript compiler 221 | TypeScript 1.7.x includes everything you need. Make sure to upgrade, even if you installed TypeScript previously. 222 | 223 | ``` 224 | npm install --global typescript 225 | ``` 226 | 227 | ## Use a TypeScript-aware editor 228 | We have good experience using these editors: 229 | 230 | * [Visual Studio Code](https://code.visualstudio.com/) 231 | * [Webstorm 10](https://www.jetbrains.com/webstorm/download/) 232 | * [Atom](https://atom.io/) with [TypeScript plugin](https://atom.io/packages/atom-typescript) 233 | * [Sublime Text](http://www.sublimetext.com/3) with [Typescript-Sublime-Plugin](https://github.com/Microsoft/Typescript-Sublime-plugin#installation) 234 | 235 | # Types 236 | > When you include a module that doesn't include Type Definitions inside of the module you can include external Type Definitions with @types 237 | 238 | ## Custom Type Definitions 239 | When including 3rd party modules you also need to include the type definition for the module 240 | if they don't provide one within the module. You can try to install it with @types 241 | 242 | ``` 243 | npm install @types/node 244 | npm install @types/lodash 245 | ``` 246 | 247 | If you can't find the type definition in the registry we can make an ambient definition in 248 | this file for now. For example 249 | 250 | ```typescript 251 | declare module "my-module" { 252 | export function doesSomething(value: string): string; 253 | } 254 | ``` 255 | 256 | 257 | If you're prototyping and you will fix the types later you can also declare it as type any 258 | 259 | ```typescript 260 | declare var assert: any; 261 | declare var _: any; 262 | declare var $: any; 263 | ``` 264 | 265 | If you're importing a module that uses Node.js modules which are CommonJS you need to import as 266 | 267 | ```typescript 268 | import * as _ from 'lodash'; 269 | ``` 270 | 271 | 272 | # Frequently asked questions 273 | * What's the current browser support for Angular 2 Beta? 274 | * Please view the updated list of [browser support for Angular 2](https://github.com/angularclass/awesome-angular2#current-browser-support-for-angular-2) 275 | * Why is my service, aka provider, is not injecting parameter correctly? 276 | * Please use `@Injectable()` for your service for typescript to correctly attach the metadata (this is a TypeScript problem) 277 | * How do I run protractor with node 0.12.x? 278 | * please check out this repo to use the old version of protractor [#146](https://github.com/AngularClass/angular2-webpack-starter/pull/146/files) 279 | * Where do I write my tests? 280 | * You can write your tests next to your component files. See [`/src/app/home/home.spec.ts`](/src/app/home/home.spec.ts) 281 | * How do I start the app when I get `EACCES` and `EADDRINUSE` errors? 282 | * The `EADDRINUSE` error means the port `3000` is currently being used and `EACCES` is lack of permission for webpack to build files to `./dist/` 283 | * How to use `sass` for css? 284 | * `loaders: ['raw-loader','sass-loader']` and `@Component({ styles: [ require('./filename.scss') ] })` see issue [#136](https://github.com/AngularClass/angular2-webpack-starter/issues/136) 285 | * How do I test a Service? 286 | * See issue [#130](https://github.com/AngularClass/angular2-webpack-starter/issues/130#issuecomment-158872648) 287 | * How do I add `vscode-chrome-debug` support? 288 | * The VS Code chrome debug extension support can be done via `launch.json` see issue [#144](https://github.com/AngularClass/angular2-webpack-starter/issues/144#issuecomment-164063790) 289 | * How do I make the repo work in a virtual machine? 290 | * You need to use `0.0.0.0` so revert these changes [#205](https://github.com/AngularClass/angular2-webpack-starter/pull/205/files) 291 | * What are the naming conventions for Angular 2? 292 | * please see issue [#185](https://github.com/AngularClass/angular2-webpack-starter/issues/185) and PR [196](https://github.com/AngularClass/angular2-webpack-starter/pull/196) 293 | * How do I include bootstrap or jQuery? 294 | * please see issue [#215](https://github.com/AngularClass/angular2-webpack-starter/issues/215) and [#214](https://github.com/AngularClass/angular2-webpack-starter/issues/214#event-511768416) 295 | * How do I async load a component? 296 | * see wiki [How-do-I-async-load-a-component-with-AsyncRoute](https://github.com/AngularClass/angular2-webpack-starter/wiki/How-do-I-async-load-a-component-with-AsyncRoute) 297 | * Error: Cannot find module 'tapable' 298 | * Remove `node_modules/` and run `npm cache clean` then `npm install` 299 | * What about Webpack 2? 300 | * If you're looking for Webpack 2 version then see the [experimental version](https://github.com/gdi2290/angular2-webpack2-starter) that will be merged soon. 301 | * How do I turn on Hot Module Replacement 302 | * Run `npm run server:dev:hmr` 303 | * `RangeError: Maximum call stack size exceeded` 304 | * This is a problem with minifying Angular 2 and it's recent JIT templates. If you set `mangle` to `false` then you should be good. 305 | * Why is the size of my app larger in development? 306 | * We are using inline source-maps and hot module replacement which will increase the bundle size. 307 | * If you're in China 308 | * check out https://github.com/cnpm/cnpm 309 | * If you're looking to add Angular 2 Material Design 310 | * check out the [material2](https://github.com/AngularClass/angular2-webpack-starter/tree/material2) branch 311 | * node-pre-gyp ERR in npm install (Windows) 312 | * install Python x86 version between 2.5 and 3.0 on windows see issue [#626](https://github.com/AngularClass/angular2-webpack-starter/issues/626) 313 | * `Error:Error: Parse tsconfig error [{"messageText":"Unknown compiler option 'lib'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'strictNullChecks'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'baseUrl'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'paths'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'types'.","category":1,"code":5023}]` 314 | * remove `node_modules/typescript` and run `npm install typescript@beta`. This repo now uses ts 2.0 315 | 316 | # Support, Questions, or Feedback 317 | > Contact us anytime for anything about this repo or Angular 2 318 | 319 | * [Chat: AngularClass.slack](http://angularclass.com/member-join/) 320 | * [Twitter: @AngularClass](https://twitter.com/AngularClass) 321 | * [Gitter: AngularClass/angular2-webpack-starter](https://gitter.im/angularclass/angular2-webpack-starter) 322 | 323 | # Quick Start Guides 324 | 325 | ## Nitrous 326 | 327 | You can quickly create a free development environment to get started using this 328 | starter kit in the cloud on [Nitrous](https://www.nitrous.io/): 329 | 330 | 331 | Nitrous Quickstart 332 | 333 | 334 | Simply run `HOST=0.0.0.0 npm start` from the terminal inside of 335 | `~/code/angular2-webpack-starter` and access your site via the "Preview > 3000" 336 | link in the IDE. 337 | 338 |

339 | 340 | Angular 2 Fundamentals 341 | 342 |

343 | 344 | ___ 345 | 346 | enjoy — **AngularClass** 347 | 348 |

349 | 350 | [![AngularClass](https://cloud.githubusercontent.com/assets/1016365/9863770/cb0620fc-5af7-11e5-89df-d4b0b2cdfc43.png "Angular Class")](https://angularclass.com) 351 | ##[AngularClass](https://angularclass.com) 352 | > Learn AngularJS, Angular 2, and Modern Web Development from the best. 353 | > Looking for corporate Angular training, want to host us, or Angular consulting? patrick@angularclass.com 354 | 355 | ___ 356 | 357 | # License 358 | [MIT](/LICENSE) 359 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/head-config.common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Configuration for head elements added during the creation of index.html. 3 | * 4 | * All href attributes are added the publicPath (if exists) by default. 5 | * You can explicitly hint to prefix a publicPath by setting a boolean value to a key that has 6 | * the same name as the attribute you want to operate on, but prefix with = 7 | * 8 | * Example: 9 | * { name: "msapplication-TileImage", content: "/assets/icon/ms-icon-144x144.png", "=content": true }, 10 | * Will prefix the publicPath to content. 11 | * 12 | * { rel: "apple-touch-icon", sizes: "57x57", href: "/assets/icon/apple-icon-57x57.png", "=href": false }, 13 | * Will not prefix the publicPath on href (href attributes are added by default 14 | * 15 | */ 16 | module.exports = { 17 | link: [ 18 | /** tags for "apple-touch-icon" (AKA Web Clips). **/ 19 | { rel: "apple-touch-icon", sizes: "57x57", href: "/assets/icon/apple-icon-57x57.png" }, 20 | { rel: "apple-touch-icon", sizes: "60x60", href: "/assets/icon/apple-icon-60x60.png" }, 21 | { rel: "apple-touch-icon", sizes: "72x72", href: "/assets/icon/apple-icon-72x72.png" }, 22 | { rel: "apple-touch-icon", sizes: "76x76", href: "/assets/icon/apple-icon-76x76.png" }, 23 | { rel: "apple-touch-icon", sizes: "114x114", href: "/assets/icon/apple-icon-114x114.png" }, 24 | { rel: "apple-touch-icon", sizes: "120x120", href: "/assets/icon/apple-icon-120x120.png" }, 25 | { rel: "apple-touch-icon", sizes: "144x144", href: "/assets/icon/apple-icon-144x144.png" }, 26 | { rel: "apple-touch-icon", sizes: "152x152", href: "/assets/icon/apple-icon-152x152.png" }, 27 | { rel: "apple-touch-icon", sizes: "180x180", href: "/assets/icon/apple-icon-180x180.png" }, 28 | 29 | /** tags for android web app icons **/ 30 | { rel: "icon", type: "image/png", sizes: "192x192", href: "/assets/icon/android-icon-192x192.png" }, 31 | 32 | /** tags for favicons **/ 33 | { rel: "icon", type: "image/png", sizes: "32x32", href: "/assets/icon/favicon-32x32.png" }, 34 | { rel: "icon", type: "image/png", sizes: "96x96", href: "/assets/icon/favicon-96x96.png" }, 35 | { rel: "icon", type: "image/png", sizes: "16x16", href: "/assets/icon/favicon-16x16.png" }, 36 | 37 | /** tags for a Web App Manifest **/ 38 | { rel: "manifest", href: "/assets/manifest.json" } 39 | ], 40 | meta: [ 41 | { name: "msapplication-TileColor", content: "#00bcd4" }, 42 | { name: "msapplication-TileImage", content: "/assets/icon/ms-icon-144x144.png", "=content": true }, 43 | { name: "theme-color", content: "#00bcd4" } 44 | ] 45 | }; 46 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/helpers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | var path = require('path'); 5 | 6 | // Helper functions 7 | var ROOT = path.resolve(__dirname, '..'); 8 | 9 | function hasProcessFlag(flag) { 10 | return process.argv.join('').indexOf(flag) > -1; 11 | } 12 | 13 | function isWebpackDevServer() { 14 | return process.argv[1] && !! (/webpack-dev-server$/.exec(process.argv[1])); 15 | } 16 | 17 | function root(args) { 18 | args = Array.prototype.slice.call(arguments, 0); 19 | return path.join.apply(path, [ROOT].concat(args)); 20 | } 21 | 22 | function checkNodeImport(context, request, cb) { 23 | if (!path.isAbsolute(request) && request.charAt(0) !== '.') { 24 | cb(null, 'commonjs ' + request); return; 25 | } 26 | cb(); 27 | } 28 | 29 | exports.hasProcessFlag = hasProcessFlag; 30 | exports.isWebpackDevServer = isWebpackDevServer; 31 | exports.root = root; 32 | exports.checkNodeImport = checkNodeImport; 33 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/html-elements-plugin/index.js: -------------------------------------------------------------------------------- 1 | 2 | function HtmlElementsPlugin(locations) { 3 | this.locations = locations; 4 | } 5 | 6 | HtmlElementsPlugin.prototype.apply = function(compiler) { 7 | var self = this; 8 | compiler.plugin('compilation', function(compilation) { 9 | compilation.options.htmlElements = compilation.options.htmlElements || {}; 10 | 11 | compilation.plugin('html-webpack-plugin-before-html-generation', function(htmlPluginData, callback) { 12 | const locations = self.locations; 13 | 14 | if (locations) { 15 | const publicPath = htmlPluginData.assets.publicPath; 16 | 17 | Object.getOwnPropertyNames(locations).forEach(function(loc) { 18 | compilation.options.htmlElements[loc] = getHtmlElementString(locations[loc], publicPath); 19 | }); 20 | } 21 | 22 | 23 | callback(null, htmlPluginData); 24 | }); 25 | }); 26 | 27 | }; 28 | 29 | const RE_ENDS_WITH_BS = /\/$/; 30 | 31 | /** 32 | * Create an HTML tag with attributes from a map. 33 | * 34 | * Example: 35 | * createTag('link', { rel: "manifest", href: "/assets/manifest.json" }) 36 | * // 37 | * @param tagName The name of the tag 38 | * @param attrMap A Map of attribute names (keys) and their values. 39 | * @param publicPath a path to add to eh start of static asset url 40 | * @returns {string} 41 | */ 42 | function createTag(tagName, attrMap, publicPath) { 43 | publicPath = publicPath || ''; 44 | 45 | // add trailing slash if we have a publicPath and it doesn't have one. 46 | if (publicPath && !RE_ENDS_WITH_BS.test(publicPath)) publicPath += '/'; 47 | 48 | const attributes = Object.getOwnPropertyNames(attrMap) 49 | .filter(function(name) { return name[0] !== '='; } ) 50 | .map(function(name) { 51 | var value = attrMap[name]; 52 | 53 | if (publicPath) { 54 | // check if we have explicit instruction, use it if so (e.g: =herf: false) 55 | // if no instruction, use public path if it's href attribute. 56 | const usePublicPath = attrMap.hasOwnProperty('=' + name) ? !!attrMap['=' + name] : name === 'href'; 57 | 58 | if (usePublicPath) { 59 | // remove a starting trailing slash if the value has one so we wont have // 60 | value = publicPath + (value[0] === '/' ? value.substr(1) : value); 61 | } 62 | } 63 | 64 | return name + '="' + value + '"'; 65 | }); 66 | 67 | return '<' + tagName + ' ' + attributes.join(' ') + '>'; 68 | } 69 | 70 | /** 71 | * Returns a string representing all html elements defined in a data source. 72 | * 73 | * Example: 74 | * 75 | * const ds = { 76 | * link: [ 77 | * { rel: "apple-touch-icon", sizes: "57x57", href: "/assets/icon/apple-icon-57x57.png" } 78 | * ], 79 | * meta: [ 80 | * { name: "msapplication-TileColor", content: "#00bcd4" } 81 | * ] 82 | * } 83 | * 84 | * getHeadTags(ds); 85 | * // "" 86 | * "" 87 | * 88 | * @returns {string} 89 | */ 90 | function getHtmlElementString(dataSource, publicPath) { 91 | return Object.getOwnPropertyNames(dataSource) 92 | .map(function(name) { 93 | if (Array.isArray(dataSource[name])) { 94 | return dataSource[name].map(function(attrs) { return createTag(name, attrs, publicPath); } ); 95 | } else { 96 | return [ createTag(name, dataSource[name], publicPath) ]; 97 | } 98 | }) 99 | .reduce(function(arr, curr) { 100 | return arr.concat(curr); 101 | }, []) 102 | .join('\n\t'); 103 | } 104 | module.exports = HtmlElementsPlugin; 105 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/karma.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | module.exports = function(config) { 6 | var testWebpackConfig = require('./webpack.test.js'); 7 | 8 | var configuration = { 9 | 10 | // base path that will be used to resolve all patterns (e.g. files, exclude) 11 | basePath: '', 12 | 13 | /* 14 | * Frameworks to use 15 | * 16 | * available frameworks: https://npmjs.org/browse/keyword/karma-adapter 17 | */ 18 | frameworks: ['jasmine'], 19 | 20 | // list of files to exclude 21 | exclude: [ ], 22 | 23 | /* 24 | * list of files / patterns to load in the browser 25 | * 26 | * we are building the test environment in ./spec-bundle.js 27 | */ 28 | files: [ { pattern: './config/spec-bundle.js', watched: false } ], 29 | 30 | /* 31 | * preprocess matching files before serving them to the browser 32 | * available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 33 | */ 34 | preprocessors: { './config/spec-bundle.js': ['coverage', 'webpack', 'sourcemap'] }, 35 | 36 | // Webpack Config at ./webpack.test.js 37 | webpack: testWebpackConfig, 38 | 39 | coverageReporter: { 40 | dir : 'coverage/', 41 | reporters: [ 42 | { type: 'text-summary' }, 43 | { type: 'json' }, 44 | { type: 'html' } 45 | ] 46 | }, 47 | 48 | // Webpack please don't spam the console when running in karma! 49 | webpackServer: { noInfo: true }, 50 | 51 | /* 52 | * test results reporter to use 53 | * 54 | * possible values: 'dots', 'progress' 55 | * available reporters: https://npmjs.org/browse/keyword/karma-reporter 56 | */ 57 | reporters: [ 'mocha', 'coverage' ], 58 | 59 | // web server port 60 | port: 9876, 61 | 62 | // enable / disable colors in the output (reporters and logs) 63 | colors: true, 64 | 65 | /* 66 | * level of logging 67 | * possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 68 | */ 69 | logLevel: config.LOG_INFO, 70 | 71 | // enable / disable watching file and executing tests whenever any file changes 72 | autoWatch: false, 73 | 74 | /* 75 | * start these browsers 76 | * available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 77 | */ 78 | browsers: [ 79 | 'Chrome' 80 | ], 81 | 82 | customLaunchers: { 83 | Chrome_travis_ci: { 84 | base: 'Chrome', 85 | flags: ['--no-sandbox'] 86 | } 87 | }, 88 | 89 | /* 90 | * Continuous Integration mode 91 | * if true, Karma captures browsers, runs the tests and exits 92 | */ 93 | singleRun: true 94 | }; 95 | 96 | if(process.env.TRAVIS){ 97 | configuration.browsers = ['Chrome_travis_ci']; 98 | } 99 | 100 | config.set(configuration); 101 | }; 102 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/modules/angular2-hmr-prod.js: -------------------------------------------------------------------------------- 1 | exports.HmrState = function() { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/protractor.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | require('ts-node/register'); 6 | var helpers = require('./helpers'); 7 | 8 | exports.config = { 9 | baseUrl: 'http://localhost:3000/', 10 | 11 | // use `npm run e2e` 12 | specs: [ 13 | helpers.root('src/**/**.e2e.ts'), 14 | helpers.root('src/**/*.e2e.ts') 15 | ], 16 | exclude: [], 17 | 18 | framework: 'jasmine2', 19 | 20 | allScriptsTimeout: 110000, 21 | 22 | jasmineNodeOpts: { 23 | showTiming: true, 24 | showColors: true, 25 | isVerbose: false, 26 | includeStackTrace: false, 27 | defaultTimeoutInterval: 400000 28 | }, 29 | directConnect: true, 30 | 31 | capabilities: { 32 | 'browserName': 'chrome', 33 | 'chromeOptions': { 34 | 'args': ['show-fps-counter=true'] 35 | } 36 | }, 37 | 38 | onPrepare: function() { 39 | browser.ignoreSynchronization = true; 40 | }, 41 | 42 | /** 43 | * Angular 2 configuration 44 | * 45 | * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching 46 | * `rootEl` 47 | */ 48 | useAllAngular2AppRoots: true 49 | }; 50 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/spec-bundle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | /* 6 | * When testing with webpack and ES6, we have to do some extra 7 | * things to get testing to work right. Because we are gonna write tests 8 | * in ES6 too, we have to compile those as well. That's handled in 9 | * karma.conf.js with the karma-webpack plugin. This is the entry 10 | * file for webpack test. Just like webpack will create a bundle.js 11 | * file for our client, when we run test, it will compile and bundle them 12 | * all here! Crazy huh. So we need to do some setup 13 | */ 14 | Error.stackTraceLimit = Infinity; 15 | 16 | require('core-js/es6'); 17 | require('core-js/es7/reflect'); 18 | 19 | // Typescript emit helpers polyfill 20 | require('ts-helpers'); 21 | 22 | require('zone.js/dist/zone'); 23 | require('zone.js/dist/long-stack-trace-zone'); 24 | require('zone.js/dist/async-test'); 25 | require('zone.js/dist/fake-async-test'); 26 | require('zone.js/dist/sync-test'); 27 | require('zone.js/dist/proxy'); // since zone.js 0.6.15 28 | require('zone.js/dist/jasmine-patch'); // put here since zone.js 0.6.14 29 | 30 | // RxJS 31 | require('rxjs/Rx'); 32 | 33 | var testing = require('@angular/core/testing'); 34 | var browser = require('@angular/platform-browser-dynamic/testing'); 35 | 36 | testing.setBaseTestProviders( 37 | browser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, 38 | browser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS 39 | ); 40 | 41 | /* 42 | * Ok, this is kinda crazy. We can use the context method on 43 | * require that webpack created in order to tell webpack 44 | * what files we actually want to require or import. 45 | * Below, context will be a function/object with file names as keys. 46 | * Using that regex we are saying look in ../src then find 47 | * any file that ends with spec.ts and get its path. By passing in true 48 | * we say do this recursively 49 | */ 50 | var testContext = require.context('../src', true, /\.spec\.ts/); 51 | 52 | /* 53 | * get all the files, for each file, call the context function 54 | * that will require the file and load it up here. Context will 55 | * loop and require those spec files here 56 | */ 57 | function requireAll(requireContext) { 58 | return requireContext.keys().map(requireContext); 59 | } 60 | 61 | // requires and returns all modules that match 62 | var modules = requireAll(testContext); 63 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/webpack.common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | const webpack = require('webpack'); 6 | const helpers = require('./helpers'); 7 | 8 | /* 9 | * Webpack Plugins 10 | */ 11 | // problem with copy-webpack-plugin 12 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 13 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 14 | const ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin; 15 | const HtmlElementsPlugin = require('./html-elements-plugin'); 16 | 17 | /* 18 | * Webpack Constants 19 | */ 20 | const METADATA = { 21 | title: '{{cookiecutter.github_repository_name}}', 22 | baseUrl: '/', 23 | isDevServer: helpers.isWebpackDevServer() 24 | }; 25 | 26 | /* 27 | * Webpack configuration 28 | * 29 | * See: http://webpack.github.io/docs/configuration.html#cli 30 | */ 31 | module.exports = { 32 | 33 | /* 34 | * Static metadata for index.html 35 | * 36 | * See: (custom attribute) 37 | */ 38 | metadata: METADATA, 39 | 40 | /* 41 | * Cache generated modules and chunks to improve performance for multiple incremental builds. 42 | * This is enabled by default in watch mode. 43 | * You can pass false to disable it. 44 | * 45 | * See: http://webpack.github.io/docs/configuration.html#cache 46 | */ 47 | //cache: false, 48 | 49 | /* 50 | * The entry point for the bundle 51 | * Our Angular.js app 52 | * 53 | * See: http://webpack.github.io/docs/configuration.html#entry 54 | */ 55 | entry: { 56 | 57 | 'polyfills': './src/polyfills.browser.ts', 58 | 'vendor': './src/vendor.browser.ts', 59 | 'main': './src/main.browser.ts' 60 | 61 | }, 62 | 63 | /* 64 | * Options affecting the resolving of modules. 65 | * 66 | * See: http://webpack.github.io/docs/configuration.html#resolve 67 | */ 68 | resolve: { 69 | 70 | /* 71 | * An array of extensions that should be used to resolve modules. 72 | * 73 | * See: http://webpack.github.io/docs/configuration.html#resolve-extensions 74 | */ 75 | extensions: ['', '.ts', '.js', '.json'], 76 | 77 | // Make sure root is src 78 | root: helpers.root('src'), 79 | 80 | // remove other default values 81 | modulesDirectories: ['node_modules'] 82 | 83 | }, 84 | 85 | /* 86 | * Options affecting the normal modules. 87 | * 88 | * See: http://webpack.github.io/docs/configuration.html#module 89 | */ 90 | module: { 91 | 92 | /* 93 | * An array of applied pre and post loaders. 94 | * 95 | * See: http://webpack.github.io/docs/configuration.html#module-preloaders-module-postloaders 96 | */ 97 | preLoaders: [ 98 | { 99 | test: /\.ts$/, 100 | loader: 'string-replace-loader', 101 | query: { 102 | search: '(System|SystemJS)(.*[\\n\\r]\\s*\\.|\\.)import\\((.+)\\)', 103 | replace: '$1.import($3).then(mod => mod.__esModule ? mod.default : mod)', 104 | flags: 'g' 105 | }, 106 | include: [helpers.root('src')] 107 | } 108 | ], 109 | 110 | /* 111 | * An array of automatically applied loaders. 112 | * 113 | * IMPORTANT: The loaders here are resolved relative to the resource which they are applied to. 114 | * This means they are not resolved relative to the configuration file. 115 | * 116 | * See: http://webpack.github.io/docs/configuration.html#module-loaders 117 | */ 118 | loaders: [ 119 | 120 | /* 121 | * Typescript loader support for .ts and Angular 2 async routes via .async.ts 122 | * Replace templateUrl and stylesUrl with require() 123 | * 124 | * See: https://github.com/s-panferov/awesome-typescript-loader 125 | * See: https://github.com/TheLarkInn/angular2-template-loader 126 | */ 127 | { 128 | test: /\.ts$/, 129 | loaders: [ 130 | 'awesome-typescript-loader', 131 | 'angular2-template-loader', 132 | '@angularclass/hmr-loader' 133 | ], 134 | exclude: [/\.(spec|e2e)\.ts$/] 135 | }, 136 | 137 | /* 138 | * Json loader support for *.json files. 139 | * 140 | * See: https://github.com/webpack/json-loader 141 | */ 142 | { 143 | test: /\.json$/, 144 | loader: 'json-loader' 145 | }, 146 | 147 | /* 148 | * to string and css loader support for *.css files 149 | * Returns file content as string 150 | * 151 | */ 152 | { 153 | test: /\.css$/, 154 | loaders: ['to-string-loader', 'css-loader'] 155 | }, 156 | 157 | { 158 | test: /\.scss$/, 159 | exclude: /node_modules/, 160 | loaders: ['raw-loader', 'sass-loader'] // sass-loader not scss-loader 161 | }, 162 | 163 | /* Raw loader support for *.html 164 | * Returns file content as string 165 | * 166 | * See: https://github.com/webpack/raw-loader 167 | */ 168 | { 169 | test: /\.html$/, 170 | loader: 'raw-loader', 171 | exclude: [helpers.root('src/index.html')] 172 | }, 173 | 174 | { 175 | test: /\.(pug|jade)$/, 176 | loader: 'pug-html-loader' 177 | }, 178 | 179 | /* File loader for supporting images, for example, in CSS files. 180 | */ 181 | { 182 | test: /\.(jpg|png|gif)$/, 183 | loader: 'file' 184 | } 185 | ] 186 | 187 | }, 188 | 189 | /* 190 | * Add additional plugins to the compiler. 191 | * 192 | * See: http://webpack.github.io/docs/configuration.html#plugins 193 | */ 194 | plugins: [ 195 | 196 | /* 197 | * Plugin: ForkCheckerPlugin 198 | * Description: Do type checking in a separate process, so webpack don't need to wait. 199 | * 200 | * See: https://github.com/s-panferov/awesome-typescript-loader#forkchecker-boolean-defaultfalse 201 | */ 202 | new ForkCheckerPlugin(), 203 | /* 204 | * Plugin: CommonsChunkPlugin 205 | * Description: Shares common code between the pages. 206 | * It identifies common modules and put them into a commons chunk. 207 | * 208 | * See: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin 209 | * See: https://github.com/webpack/docs/wiki/optimization#multi-page-app 210 | */ 211 | new webpack.optimize.CommonsChunkPlugin({ 212 | name: ['polyfills', 'vendor'].reverse() 213 | }), 214 | 215 | /* 216 | * Plugin: CopyWebpackPlugin 217 | * Description: Copy files and directories in webpack. 218 | * 219 | * Copies project static assets. 220 | * 221 | * See: https://www.npmjs.com/package/copy-webpack-plugin 222 | */ 223 | new CopyWebpackPlugin([{ 224 | from: 'src/assets', 225 | to: 'assets' 226 | }]), 227 | 228 | /* 229 | * Plugin: HtmlWebpackPlugin 230 | * Description: Simplifies creation of HTML files to serve your webpack bundles. 231 | * This is especially useful for webpack bundles that include a hash in the filename 232 | * which changes every compilation. 233 | * 234 | * See: https://github.com/ampedandwired/html-webpack-plugin 235 | */ 236 | new HtmlWebpackPlugin({ 237 | template: 'src/index.html', 238 | chunksSortMode: 'dependency' 239 | }), 240 | 241 | /* 242 | * Plugin: HtmlHeadConfigPlugin 243 | * Description: Generate html tags based on javascript maps. 244 | * 245 | * If a publicPath is set in the webpack output configuration, it will be automatically added to 246 | * href attributes, you can disable that by adding a "=href": false property. 247 | * You can also enable it to other attribute by settings "=attName": true. 248 | * 249 | * The configuration supplied is map between a location (key) and an element definition object (value) 250 | * The location (key) is then exported to the template under then htmlElements property in webpack configuration. 251 | * 252 | * Example: 253 | * Adding this plugin configuration 254 | * new HtmlElementsPlugin({ 255 | * headTags: { ... } 256 | * }) 257 | * 258 | * Means we can use it in the template like this: 259 | * <%= webpackConfig.htmlElements.headTags %> 260 | * 261 | * Dependencies: HtmlWebpackPlugin 262 | */ 263 | new HtmlElementsPlugin({ 264 | headTags: require('./head-config.common') 265 | }) 266 | 267 | ], 268 | 269 | /* 270 | * Include polyfills or mocks for various node stuff 271 | * Description: Node configuration 272 | * 273 | * See: https://webpack.github.io/docs/configuration.html#node 274 | */ 275 | node: { 276 | global: 'window', 277 | crypto: 'empty', 278 | process: true, 279 | module: false, 280 | clearImmediate: false, 281 | setImmediate: false 282 | } 283 | 284 | }; 285 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/webpack.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | const helpers = require('./helpers'); 6 | const webpackMerge = require('webpack-merge'); // used to merge webpack configs 7 | const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev 8 | 9 | /** 10 | * Webpack Plugins 11 | */ 12 | const DefinePlugin = require('webpack/lib/DefinePlugin'); 13 | 14 | /** 15 | * Webpack Constants 16 | */ 17 | const ENV = process.env.ENV = process.env.NODE_ENV = 'development'; 18 | const HOST = process.env.HOST || 'localhost'; 19 | const PORT = process.env.PORT || 3000; 20 | const HMR = helpers.hasProcessFlag('hot'); 21 | const METADATA = webpackMerge(commonConfig.metadata, { 22 | host: HOST, 23 | port: PORT, 24 | ENV: ENV, 25 | HMR: HMR 26 | }); 27 | 28 | /** 29 | * Webpack configuration 30 | * 31 | * See: http://webpack.github.io/docs/configuration.html#cli 32 | */ 33 | module.exports = webpackMerge(commonConfig, { 34 | 35 | /** 36 | * Merged metadata from webpack.common.js for index.html 37 | * 38 | * See: (custom attribute) 39 | */ 40 | metadata: METADATA, 41 | 42 | /** 43 | * Switch loaders to debug mode. 44 | * 45 | * See: http://webpack.github.io/docs/configuration.html#debug 46 | */ 47 | debug: true, 48 | 49 | /** 50 | * Developer tool to enhance debugging 51 | * 52 | * See: http://webpack.github.io/docs/configuration.html#devtool 53 | * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps 54 | */ 55 | devtool: 'cheap-module-source-map', 56 | 57 | /** 58 | * Options affecting the output of the compilation. 59 | * 60 | * See: http://webpack.github.io/docs/configuration.html#output 61 | */ 62 | output: { 63 | 64 | /** 65 | * The output directory as absolute path (required). 66 | * 67 | * See: http://webpack.github.io/docs/configuration.html#output-path 68 | */ 69 | path: helpers.root('dist'), 70 | 71 | /** 72 | * Specifies the name of each output file on disk. 73 | * IMPORTANT: You must not specify an absolute path here! 74 | * 75 | * See: http://webpack.github.io/docs/configuration.html#output-filename 76 | */ 77 | filename: '[name].bundle.js', 78 | 79 | /** 80 | * The filename of the SourceMaps for the JavaScript files. 81 | * They are inside the output.path directory. 82 | * 83 | * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename 84 | */ 85 | sourceMapFilename: '[name].map', 86 | 87 | /** The filename of non-entry chunks as relative path 88 | * inside the output.path directory. 89 | * 90 | * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename 91 | */ 92 | chunkFilename: '[id].chunk.js', 93 | 94 | library: 'ac_[name]', 95 | libraryTarget: 'var', 96 | }, 97 | 98 | plugins: [ 99 | 100 | /** 101 | * Plugin: DefinePlugin 102 | * Description: Define free variables. 103 | * Useful for having development builds with debug logging or adding global constants. 104 | * 105 | * Environment helpers 106 | * 107 | * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin 108 | */ 109 | // NOTE: when adding more properties, make sure you include them in custom-typings.d.ts 110 | new DefinePlugin({ 111 | 'ENV': JSON.stringify(METADATA.ENV), 112 | 'HMR': METADATA.HMR, 113 | 'process.env': { 114 | 'ENV': JSON.stringify(METADATA.ENV), 115 | 'NODE_ENV': JSON.stringify(METADATA.ENV), 116 | 'HMR': METADATA.HMR, 117 | } 118 | }), 119 | ], 120 | 121 | /** 122 | * Static analysis linter for TypeScript advanced options configuration 123 | * Description: An extensible linter for the TypeScript language. 124 | * 125 | * See: https://github.com/wbuchwalter/tslint-loader 126 | */ 127 | tslint: { 128 | emitErrors: false, 129 | failOnHint: false, 130 | resourcePath: 'src' 131 | }, 132 | 133 | /** 134 | * Webpack Development Server configuration 135 | * Description: The webpack-dev-server is a little node.js Express server. 136 | * The server emits information about the compilation state to the client, 137 | * which reacts to those events. 138 | * 139 | * See: https://webpack.github.io/docs/webpack-dev-server.html 140 | */ 141 | devServer: { 142 | port: METADATA.port, 143 | host: METADATA.host, 144 | historyApiFallback: true, 145 | watchOptions: { 146 | aggregateTimeout: 300, 147 | poll: 1000 148 | }, 149 | outputPath: helpers.root('dist') 150 | }, 151 | 152 | /* 153 | * Include polyfills or mocks for various node stuff 154 | * Description: Node configuration 155 | * 156 | * See: https://webpack.github.io/docs/configuration.html#node 157 | */ 158 | node: { 159 | global: 'window', 160 | crypto: 'empty', 161 | process: true, 162 | module: false, 163 | clearImmediate: false, 164 | setImmediate: false 165 | } 166 | 167 | }); 168 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/webpack.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | const helpers = require('./helpers'); 6 | const webpackMerge = require('webpack-merge'); // used to merge webpack configs 7 | const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev 8 | 9 | /** 10 | * Webpack Plugins 11 | */ 12 | const ProvidePlugin = require('webpack/lib/ProvidePlugin'); 13 | const DefinePlugin = require('webpack/lib/DefinePlugin'); 14 | const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin'); 15 | const IgnorePlugin = require('webpack/lib/IgnorePlugin'); 16 | const DedupePlugin = require('webpack/lib/optimize/DedupePlugin'); 17 | const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin'); 18 | const WebpackMd5Hash = require('webpack-md5-hash'); 19 | 20 | /** 21 | * Webpack Constants 22 | */ 23 | const ENV = process.env.NODE_ENV = process.env.ENV = 'production'; 24 | const HOST = process.env.HOST || 'localhost'; 25 | const PORT = process.env.PORT || 8080; 26 | const METADATA = webpackMerge(commonConfig.metadata, { 27 | host: HOST, 28 | port: PORT, 29 | ENV: ENV, 30 | HMR: false 31 | }); 32 | 33 | module.exports = webpackMerge(commonConfig, { 34 | 35 | /** 36 | * Switch loaders to debug mode. 37 | * 38 | * See: http://webpack.github.io/docs/configuration.html#debug 39 | */ 40 | debug: false, 41 | 42 | /** 43 | * Developer tool to enhance debugging 44 | * 45 | * See: http://webpack.github.io/docs/configuration.html#devtool 46 | * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps 47 | */ 48 | devtool: 'source-map', 49 | 50 | /** 51 | * Options affecting the output of the compilation. 52 | * 53 | * See: http://webpack.github.io/docs/configuration.html#output 54 | */ 55 | output: { 56 | 57 | /** 58 | * The output directory as absolute path (required). 59 | * 60 | * See: http://webpack.github.io/docs/configuration.html#output-path 61 | */ 62 | path: helpers.root('dist'), 63 | 64 | /** 65 | * Specifies the name of each output file on disk. 66 | * IMPORTANT: You must not specify an absolute path here! 67 | * 68 | * See: http://webpack.github.io/docs/configuration.html#output-filename 69 | */ 70 | filename: '[name].[chunkhash].bundle.js', 71 | 72 | /** 73 | * The filename of the SourceMaps for the JavaScript files. 74 | * They are inside the output.path directory. 75 | * 76 | * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename 77 | */ 78 | sourceMapFilename: '[name].[chunkhash].bundle.map', 79 | 80 | /** 81 | * The filename of non-entry chunks as relative path 82 | * inside the output.path directory. 83 | * 84 | * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename 85 | */ 86 | chunkFilename: '[id].[chunkhash].chunk.js' 87 | 88 | }, 89 | 90 | /** 91 | * Add additional plugins to the compiler. 92 | * 93 | * See: http://webpack.github.io/docs/configuration.html#plugins 94 | */ 95 | plugins: [ 96 | 97 | /** 98 | * Plugin: WebpackMd5Hash 99 | * Description: Plugin to replace a standard webpack chunkhash with md5. 100 | * 101 | * See: https://www.npmjs.com/package/webpack-md5-hash 102 | */ 103 | new WebpackMd5Hash(), 104 | 105 | /** 106 | * Plugin: DedupePlugin 107 | * Description: Prevents the inclusion of duplicate code into your bundle 108 | * and instead applies a copy of the function at runtime. 109 | * 110 | * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin 111 | * See: https://github.com/webpack/docs/wiki/optimization#deduplication 112 | */ 113 | new DedupePlugin(), 114 | 115 | /** 116 | * Plugin: DefinePlugin 117 | * Description: Define free variables. 118 | * Useful for having development builds with debug logging or adding global constants. 119 | * 120 | * Environment helpers 121 | * 122 | * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin 123 | */ 124 | // NOTE: when adding more properties make sure you include them in custom-typings.d.ts 125 | new DefinePlugin({ 126 | 'ENV': JSON.stringify(METADATA.ENV), 127 | 'HMR': METADATA.HMR, 128 | 'process.env': { 129 | 'ENV': JSON.stringify(METADATA.ENV), 130 | 'NODE_ENV': JSON.stringify(METADATA.ENV), 131 | 'HMR': METADATA.HMR, 132 | } 133 | }), 134 | 135 | /** 136 | * Plugin: UglifyJsPlugin 137 | * Description: Minimize all JavaScript output of chunks. 138 | * Loaders are switched into minimizing mode. 139 | * 140 | * See: https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 141 | */ 142 | // NOTE: To debug prod builds uncomment //debug lines and comment //prod lines 143 | new UglifyJsPlugin({ 144 | // beautify: true, //debug 145 | // mangle: false, //debug 146 | // dead_code: false, //debug 147 | // unused: false, //debug 148 | // deadCode: false, //debug 149 | // compress: { 150 | // screw_ie8: true, 151 | // keep_fnames: true, 152 | // drop_debugger: false, 153 | // dead_code: false, 154 | // unused: false 155 | // }, // debug 156 | // comments: true, //debug 157 | 158 | 159 | beautify: false, //prod 160 | mangle: {screw_ie8: true, keep_fnames: true}, //prod 161 | compress: {screw_ie8: true}, //prod 162 | comments: false //prod 163 | }), 164 | 165 | /** 166 | * Plugin: NormalModuleReplacementPlugin 167 | * Description: Replace resources that matches resourceRegExp with newResource 168 | * 169 | * See: http://webpack.github.io/docs/list-of-plugins.html#normalmodulereplacementplugin 170 | */ 171 | 172 | new NormalModuleReplacementPlugin( 173 | /angular2-hmr/, 174 | helpers.root('config/modules/angular2-hmr-prod.js') 175 | ), 176 | 177 | /** 178 | * Plugin: IgnorePlugin 179 | * Description: Don’t generate modules for requests matching the provided RegExp. 180 | * 181 | * See: http://webpack.github.io/docs/list-of-plugins.html#ignoreplugin 182 | */ 183 | 184 | // new IgnorePlugin(/angular2-hmr/), 185 | 186 | /** 187 | * Plugin: CompressionPlugin 188 | * Description: Prepares compressed versions of assets to serve 189 | * them with Content-Encoding 190 | * 191 | * See: https://github.com/webpack/compression-webpack-plugin 192 | */ 193 | // install compression-webpack-plugin 194 | // new CompressionPlugin({ 195 | // regExp: /\.css$|\.html$|\.js$|\.map$/, 196 | // threshold: 2 * 1024 197 | // }) 198 | 199 | ], 200 | 201 | /** 202 | * Static analysis linter for TypeScript advanced options configuration 203 | * Description: An extensible linter for the TypeScript language. 204 | * 205 | * See: https://github.com/wbuchwalter/tslint-loader 206 | */ 207 | tslint: { 208 | emitErrors: true, 209 | failOnHint: true, 210 | resourcePath: 'src' 211 | }, 212 | 213 | /** 214 | * Html loader advanced options 215 | * 216 | * See: https://github.com/webpack/html-loader#advanced-options 217 | */ 218 | // TODO: Need to workaround Angular 2's html syntax => #id [bind] (event) *ngFor 219 | htmlLoader: { 220 | minimize: true, 221 | removeAttributeQuotes: false, 222 | caseSensitive: true, 223 | customAttrSurround: [ 224 | [/#/, /(?:)/], 225 | [/\*/, /(?:)/], 226 | [/\[?\(?/, /(?:)/] 227 | ], 228 | customAttrAssign: [/\)?\]?=/] 229 | }, 230 | 231 | /* 232 | * Include polyfills or mocks for various node stuff 233 | * Description: Node configuration 234 | * 235 | * See: https://webpack.github.io/docs/configuration.html#node 236 | */ 237 | node: { 238 | global: 'window', 239 | crypto: 'empty', 240 | process: false, 241 | module: false, 242 | clearImmediate: false, 243 | setImmediate: false 244 | } 245 | 246 | }); 247 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/config/webpack.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | const helpers = require('./helpers'); 6 | 7 | /** 8 | * Webpack Plugins 9 | */ 10 | const ProvidePlugin = require('webpack/lib/ProvidePlugin'); 11 | const DefinePlugin = require('webpack/lib/DefinePlugin'); 12 | 13 | /** 14 | * Webpack Constants 15 | */ 16 | const ENV = process.env.ENV = process.env.NODE_ENV = 'test'; 17 | 18 | /** 19 | * Webpack configuration 20 | * 21 | * See: http://webpack.github.io/docs/configuration.html#cli 22 | */ 23 | module.exports = { 24 | 25 | /** 26 | * Source map for Karma from the help of karma-sourcemap-loader & karma-webpack 27 | * 28 | * Do not change, leave as is or it wont work. 29 | * See: https://github.com/webpack/karma-webpack#source-maps 30 | */ 31 | devtool: 'inline-source-map', 32 | 33 | /** 34 | * Options affecting the resolving of modules. 35 | * 36 | * See: http://webpack.github.io/docs/configuration.html#resolve 37 | */ 38 | resolve: { 39 | 40 | /** 41 | * An array of extensions that should be used to resolve modules. 42 | * 43 | * See: http://webpack.github.io/docs/configuration.html#resolve-extensions 44 | */ 45 | extensions: ['', '.ts', '.js'], 46 | 47 | /** 48 | * Make sure root is src 49 | */ 50 | root: helpers.root('src'), 51 | 52 | }, 53 | 54 | /** 55 | * Options affecting the normal modules. 56 | * 57 | * See: http://webpack.github.io/docs/configuration.html#module 58 | */ 59 | module: { 60 | 61 | /** 62 | * An array of applied pre and post loaders. 63 | * 64 | * See: http://webpack.github.io/docs/configuration.html#module-preloaders-module-postloaders 65 | */ 66 | preLoaders: [ 67 | 68 | /** 69 | * Tslint loader support for *.ts files 70 | * 71 | * See: https://github.com/wbuchwalter/tslint-loader 72 | */ 73 | { 74 | test: /\.ts$/, 75 | loader: 'tslint-loader', 76 | exclude: [helpers.root('node_modules')] 77 | }, 78 | 79 | /** 80 | * Source map loader support for *.js files 81 | * Extracts SourceMaps for source files that as added as sourceMappingURL comment. 82 | * 83 | * See: https://github.com/webpack/source-map-loader 84 | */ 85 | { 86 | test: /\.js$/, 87 | loader: 'source-map-loader', 88 | exclude: [ 89 | // these packages have problems with their sourcemaps 90 | helpers.root('node_modules/rxjs'), 91 | helpers.root('node_modules/@angular') 92 | ]} 93 | 94 | ], 95 | 96 | /** 97 | * An array of automatically applied loaders. 98 | * 99 | * IMPORTANT: The loaders here are resolved relative to the resource which they are applied to. 100 | * This means they are not resolved relative to the configuration file. 101 | * 102 | * See: http://webpack.github.io/docs/configuration.html#module-loaders 103 | */ 104 | loaders: [ 105 | 106 | /** 107 | * Typescript loader support for .ts and Angular 2 async routes via .async.ts 108 | * 109 | * See: https://github.com/s-panferov/awesome-typescript-loader 110 | */ 111 | { 112 | test: /\.ts$/, 113 | loader: 'awesome-typescript-loader', 114 | query: { 115 | compilerOptions: { 116 | 117 | // Remove TypeScript helpers to be injected 118 | // below by DefinePlugin 119 | removeComments: true 120 | 121 | } 122 | }, 123 | exclude: [/\.e2e\.ts$/] 124 | }, 125 | 126 | /** 127 | * Json loader support for *.json files. 128 | * 129 | * See: https://github.com/webpack/json-loader 130 | */ 131 | { test: /\.json$/, loader: 'json-loader', exclude: [helpers.root('src/index.html')] }, 132 | 133 | /** 134 | * Raw loader support for *.css files 135 | * Returns file content as string 136 | * 137 | * See: https://github.com/webpack/raw-loader 138 | */ 139 | { test: /\.css$/, loaders: ['to-string-loader', 'css-loader'], exclude: [helpers.root('src/index.html')] }, 140 | 141 | /** 142 | * Raw loader support for *.html 143 | * Returns file content as string 144 | * 145 | * See: https://github.com/webpack/raw-loader 146 | */ 147 | { test: /\.html$/, loader: 'raw-loader', exclude: [helpers.root('src/index.html')] } 148 | 149 | ], 150 | 151 | /** 152 | * An array of applied pre and post loaders. 153 | * 154 | * See: http://webpack.github.io/docs/configuration.html#module-preloaders-module-postloaders 155 | */ 156 | postLoaders: [ 157 | 158 | /** 159 | * Instruments JS files with Istanbul for subsequent code coverage reporting. 160 | * Instrument only testing sources. 161 | * 162 | * See: https://github.com/deepsweet/istanbul-instrumenter-loader 163 | */ 164 | { 165 | test: /\.(js|ts)$/, loader: 'istanbul-instrumenter-loader', 166 | include: helpers.root('src'), 167 | exclude: [ 168 | /\.(e2e|spec)\.ts$/, 169 | /node_modules/ 170 | ] 171 | } 172 | 173 | ] 174 | }, 175 | 176 | /** 177 | * Add additional plugins to the compiler. 178 | * 179 | * See: http://webpack.github.io/docs/configuration.html#plugins 180 | */ 181 | plugins: [ 182 | 183 | /** 184 | * Plugin: DefinePlugin 185 | * Description: Define free variables. 186 | * Useful for having development builds with debug logging or adding global constants. 187 | * 188 | * Environment helpers 189 | * 190 | * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin 191 | */ 192 | // NOTE: when adding more properties make sure you include them in custom-typings.d.ts 193 | new DefinePlugin({ 194 | 'ENV': JSON.stringify(ENV), 195 | 'HMR': false, 196 | 'process.env': { 197 | 'ENV': JSON.stringify(ENV), 198 | 'NODE_ENV': JSON.stringify(ENV), 199 | 'HMR': false, 200 | } 201 | }), 202 | 203 | 204 | ], 205 | 206 | /** 207 | * Static analysis linter for TypeScript advanced options configuration 208 | * Description: An extensible linter for the TypeScript language. 209 | * 210 | * See: https://github.com/wbuchwalter/tslint-loader 211 | */ 212 | tslint: { 213 | emitErrors: false, 214 | failOnHint: false, 215 | resourcePath: 'src' 216 | }, 217 | 218 | /** 219 | * Include polyfills or mocks for various node stuff 220 | * Description: Node configuration 221 | * 222 | * See: https://webpack.github.io/docs/configuration.html#node 223 | */ 224 | node: { 225 | global: 'window', 226 | process: false, 227 | crypto: 'empty', 228 | module: false, 229 | clearImmediate: false, 230 | setImmediate: false 231 | } 232 | 233 | }; 234 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/karma.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | // Look in ./config for karma.conf.js 6 | module.exports = require('./config/karma.conf.js'); 7 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-webpack-starter", 3 | "version": "5.0.5", 4 | "description": "An Angular 2 Webpack Starter kit featuring Angular 2 (Router, Http, Forms, Services, Tests, E2E, Coverage), Karma, Protractor, Jasmine, Istanbul, TypeScript, and Webpack by AngularClass", 5 | "keywords": [ 6 | "angular2", 7 | "webpack", 8 | "typescript" 9 | ], 10 | "author": "Patrick Stapleton ", 11 | "homepage": "https://github.com/angularclass/angular2-webpack-starter", 12 | "license": "MIT", 13 | "scripts": { 14 | "rimraf": "rimraf", 15 | "tslint": "tslint", 16 | "typedoc": "typedoc", 17 | "webpack": "webpack", 18 | "webpack-dev-server": "webpack-dev-server", 19 | "webdriver-manager": "webdriver-manager", 20 | "protractor": "protractor", 21 | "clean": "npm cache clean && npm run rimraf -- node_modules doc coverage dist", 22 | "clean:dist": "npm run rimraf -- dist", 23 | "preclean:install": "npm run clean", 24 | "clean:install": "npm set progress=false && npm install", 25 | "preclean:start": "npm run clean", 26 | "clean:start": "npm start", 27 | "watch": "npm run watch:dev", 28 | "watch:dev": "npm run build:dev -- --watch", 29 | "watch:dev:hmr": "npm run watch:dev -- --hot", 30 | "watch:test": "npm run test -- --auto-watch --no-single-run", 31 | "watch:prod": "npm run build:prod -- --watch", 32 | "build": "npm run build:dev", 33 | "prebuild:dev": "npm run clean:dist", 34 | "build:dev": "webpack --config config/webpack.dev.js --progress --profile", 35 | "prebuild:prod": "npm run clean:dist", 36 | "build:prod": "webpack --config config/webpack.prod.js --progress --profile --bail", 37 | "github-deploy": "npm run github-deploy:dev", 38 | "github-deploy:dev": "webpack --config config/webpack.github-deploy.js --progress --profile --github-dev", 39 | "github-deploy:prod": "webpack --config config/webpack.github-deploy.js --progress --profile --github-prod", 40 | "server": "npm run server:dev", 41 | "server:dev": "webpack-dev-server --config config/webpack.dev.js --progress --profile --watch --content-base src/", 42 | "server:dev:hmr": "npm run server:dev -- --inline --hot", 43 | "server:prod": "http-server dist --cors", 44 | "webdriver:update": "npm run webdriver-manager update", 45 | "webdriver:start": "npm run webdriver-manager start", 46 | "lint": "npm run tslint \"src/**/*.ts\"", 47 | "pree2e": "npm run webdriver:update -- --standalone", 48 | "e2e": "npm run protractor", 49 | "e2e:live": "npm run e2e -- --elementExplorer", 50 | "test": "karma start", 51 | "ci": "npm run lint && npm test && npm run e2e", 52 | "docs": "npm run typedoc -- --options typedoc.json --exclude '**/*.spec.ts' ./src/", 53 | "start": "npm run server:dev", 54 | "start:hmr": "npm run server:dev:hmr", 55 | "preversion": "npm test", 56 | "version": "npm run build", 57 | "postversion": "git push && git push --tags" 58 | }, 59 | "dependencies": { 60 | "@angular/common": "2.0.0-rc.5", 61 | "@angular/compiler": "2.0.0-rc.5", 62 | "@angular/core": "2.0.0-rc.5", 63 | "@angular/forms": "^0.3.0", 64 | "@angular/http": "2.0.0-rc.5", 65 | "@angular/platform-browser": "2.0.0-rc.5", 66 | "@angular/platform-browser-dynamic": "2.0.0-rc.5", 67 | "@angular/platform-server": "2.0.0-rc.5", 68 | "@angular/router": "github:gdi2290/router-builds", 69 | "@angular2-material/button": "2.0.0-alpha.7-4", 70 | "@angular2-material/button-toggle": "2.0.0-alpha.7-4", 71 | "@angular2-material/card": "2.0.0-alpha.7-4", 72 | "@angular2-material/checkbox": "2.0.0-alpha.7-4", 73 | "@angular2-material/core": "2.0.0-alpha.7-4", 74 | "@angular2-material/grid-list": "2.0.0-alpha.7-4", 75 | "@angular2-material/icon": "2.0.0-alpha.7-4", 76 | "@angular2-material/input": "2.0.0-alpha.7-4", 77 | "@angular2-material/list": "2.0.0-alpha.7-4", 78 | "@angular2-material/menu": "2.0.0-alpha.7-4", 79 | "@angular2-material/progress-bar": "2.0.0-alpha.7-4", 80 | "@angular2-material/progress-circle": "2.0.0-alpha.7-4", 81 | "@angular2-material/radio": "2.0.0-alpha.7-4", 82 | "@angular2-material/sidenav": "2.0.0-alpha.7-4", 83 | "@angular2-material/slide-toggle": "2.0.0-alpha.7-4", 84 | "@angular2-material/slider": "2.0.0-alpha.7-4", 85 | "@angular2-material/tabs": "2.0.0-alpha.7-4", 86 | "@angular2-material/toolbar": "2.0.0-alpha.7-4", 87 | "@angular2-material/tooltip": "2.0.0-alpha.7-4", 88 | "@angularclass/conventions-loader": "^1.0.2", 89 | "@angularclass/request-idle-callback": "^1.0.7", 90 | "@angularclass/webpack-toolkit": "^1.3.3", 91 | "angular2-template-loader": "^0.5.0", 92 | "core-js": "^2.4.0", 93 | "hammerjs": "^2.0.8", 94 | "http-server": "^0.9.0", 95 | "ie-shim": "^0.1.0", 96 | "rxjs": "5.0.0-beta.6", 97 | "zone.js": "~0.6.17" 98 | }, 99 | "devDependencies": { 100 | "@angularclass/hmr": "^1.0.1", 101 | "@angularclass/hmr-loader": "^1.0.1", 102 | "@types/core-js": "^0.9.28", 103 | "@types/hammerjs": "^2.0.28", 104 | "@types/jasmine": "^2.2.29", 105 | "@types/node": "^4.0.29", 106 | "@types/protractor": "^1.5.16", 107 | "@types/selenium-webdriver": "2.44.26", 108 | "@types/source-map": "^0.1.26", 109 | "@types/uglify-js": "^2.0.27", 110 | "@types/webpack": "^1.12.29", 111 | "angular2-hmr": "~0.8.0", 112 | "awesome-typescript-loader": "1.1.1", 113 | "codelyzer": "~0.0.21", 114 | "copy-webpack-plugin": "^3.0.1", 115 | "css-loader": "^0.24.0", 116 | "es6-promise-loader": "^1.0.1", 117 | "exports-loader": "^0.6.3", 118 | "expose-loader": "^0.7.1", 119 | "file-loader": "^0.9.0", 120 | "gh-pages": "^0.11.0", 121 | "html-webpack-plugin": "^2.21.0", 122 | "imports-loader": "^0.6.5", 123 | "istanbul-instrumenter-loader": "^0.2.0", 124 | "json-loader": "^0.5.4", 125 | "karma": "^0.13.22", 126 | "karma-chrome-launcher": "^1.0.1", 127 | "karma-coverage": "^1.0.0", 128 | "karma-jasmine": "^1.0.2", 129 | "karma-mocha-reporter": "^2.0.0", 130 | "karma-sourcemap-loader": "^0.3.7", 131 | "karma-webpack": "1.7.0", 132 | "node-sass": "^3.4.2", 133 | "parse5": "^1.5.1", 134 | "protractor": "^3.2.2", 135 | "pug": "^2.0.0-beta6", 136 | "pug-html-loader": "^1.0.9", 137 | "pug-loader": "^2.3.0", 138 | "raw-loader": "^0.5.1", 139 | "remap-istanbul": "^0.6.3", 140 | "rimraf": "^2.5.2", 141 | "sass-loader": "^4.0.0", 142 | "source-map-loader": "^0.1.5", 143 | "string-replace-loader": "^1.0.3", 144 | "style-loader": "^0.13.1", 145 | "to-string-loader": "^1.1.4", 146 | "ts-helpers": "1.1.1", 147 | "ts-node": "^0.9.1", 148 | "tslint": "^3.7.1", 149 | "tslint-loader": "^2.1.3", 150 | "typedoc": "^0.4.4", 151 | "typescript": "^2.0.0-beta", 152 | "url-loader": "^0.5.7", 153 | "webpack": "2.1.0-beta.22", 154 | "webpack-dev-middleware": "^1.6.1", 155 | "webpack-dev-server": "^2.1.0-beta.0", 156 | "webpack-md5-hash": "^0.0.5", 157 | "webpack-merge": "^0.14.0" 158 | }, 159 | "repository": { 160 | "type": "git", 161 | "url": "https://github.com/angularclass/angular2-webpack-starter.git" 162 | }, 163 | "bugs": { 164 | "url": "https://github.com/angularclass/angular2-webpack-starter/issues" 165 | }, 166 | "engines": { 167 | "node": ">= 4.2.1", 168 | "npm": ">= 3" 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/protractor.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | // look in ./config for protractor.conf.js 6 | exports.config = require('./config/protractor.conf.js').config; 7 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/+detail/detail.component.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Component } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'detail', 6 | template: ` 7 |

Hello from Detail

8 | 9 | ` 10 | }) 11 | export class Detail { 12 | constructor() { 13 | 14 | } 15 | 16 | ngOnInit() { 17 | console.log('hello `Detail` component'); 18 | } 19 | 20 | } 21 | 22 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/+detail/index.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { BrowserModule } from '@angular/platform-browser' 3 | import { RouterModule } from '@angular/router'; 4 | import { NgModule } from '@angular/core'; 5 | import { FormsModule } from '@angular/forms'; 6 | 7 | import { Detail } from './detail.component'; 8 | 9 | console.log('`Detail` bundle loaded asynchronously'); 10 | // async components must be named routes for WebpackAsyncRoute 11 | export const routes = [ 12 | { path: '', component: Detail, pathMatch: 'full' } 13 | ]; 14 | 15 | @NgModule({ 16 | declarations: [ 17 | // Components / Directives/ Pipes 18 | Detail 19 | ], 20 | imports: [ 21 | BrowserModule, 22 | FormsModule, 23 | RouterModule.forChild(routes), 24 | ] 25 | }) 26 | export default class AboutModule { 27 | static routes = routes; 28 | } 29 | 30 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/about/about.component.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Component } from '@angular/core'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | /* 5 | * We're loading this component asynchronously 6 | * We are using some magic with es6-promise-loader that will wrap the module with a Promise 7 | * see https://github.com/gdi2290/es6-promise-loader for more info 8 | */ 9 | 10 | console.log('`About` component loaded asynchronously'); 11 | 12 | @Component({ 13 | selector: 'about', 14 | styles: [` 15 | md-card{ 16 | margin: 25px; 17 | } 18 | `], 19 | template: ` 20 | 21 | For hot module reloading run 22 |
npm run start:hmr
23 |
24 | 25 |

26 | patrick@AngularClass.com 27 |

28 |
29 | 30 |
this.localState = {{ localState | json }}
31 |
32 | ` 33 | }) 34 | export class About { 35 | localState; 36 | constructor(public route: ActivatedRoute) { 37 | 38 | } 39 | 40 | ngOnInit() { 41 | this.route 42 | .data 43 | .subscribe((data: any) => { 44 | // your resolved data from route 45 | this.localState = data.yourData; 46 | }); 47 | 48 | console.log('hello `About` component'); 49 | // static data that is bundled 50 | // var mockData = require('assets/mock-data/mock-data.json'); 51 | // console.log('mockData', mockData); 52 | // if you're working with mock data you can also use http.get('assets/mock-data/mock-data.json') 53 | // this.asyncDataWithWebpack(); 54 | } 55 | asyncDataWithWebpack() { 56 | // you can also async load mock data with 'es6-promise-loader' 57 | // you would do this if you don't want the mock-data bundled 58 | // remember that 'es6-promise-loader' is a promise 59 | // var asyncMockDataPromiseFactory = require('es6-promise!assets/mock-data/mock-data.json'); 60 | // setTimeout(() => { 61 | // 62 | // let asyncDataPromise = asyncMockDataPromiseFactory(); 63 | // asyncDataPromise.then(json => { 64 | // console.log('async mockData', json); 65 | // }); 66 | // 67 | // }); 68 | } 69 | 70 | } 71 | 72 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/about/about.spec.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { TestComponentBuilder } from '@angular/core/testing'; 3 | import { Component } from '@angular/core'; 4 | import { ActivatedRoute } from '@angular/router'; 5 | import { 6 | addProviders, 7 | inject 8 | } from '@angular/core/testing'; 9 | 10 | // Load the implementations that should be tested 11 | import { About } from './about.component'; 12 | 13 | describe('About', () => { 14 | // provide our implementations or mocks to the dependency injector 15 | beforeEach(() => addProviders([ 16 | // provide a better mock 17 | { 18 | provide: ActivatedRoute, 19 | useValue: { 20 | data: { 21 | subscribe: (fn) => fn({yourData: 'yolo'}) 22 | } 23 | } 24 | }, 25 | About 26 | ])); 27 | 28 | it('should log ngOnInit', inject([ About ], (about) => { 29 | spyOn(console, 'log'); 30 | expect(console.log).not.toHaveBeenCalled(); 31 | 32 | Home.ngOnInit(); 33 | expect(console.log).toHaveBeenCalled(); 34 | })); 35 | 36 | }); 37 | 38 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/about/index.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | export * from './about.component'; 3 | 4 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | /* 3 | * Angular 2 decorators and services 4 | */ 5 | import { Component, ViewEncapsulation } from '@angular/core'; 6 | 7 | import { AppState } from './app.service'; 8 | 9 | /* 10 | * App Component 11 | * Top Level Component 12 | */ 13 | @Component({ 14 | selector: 'app', 15 | encapsulation: ViewEncapsulation.None, 16 | styleUrls: [ 17 | './app.style.css' 18 | ], 19 | template: ` 20 | 21 | 22 | {{ name }} 23 | 24 | 25 | Index 26 | 27 | 28 | Home 29 | 30 | 31 | Detail 32 | 33 | 34 | About 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |
this.appState.state = {{ appState.state | json }}
45 | 46 |
47 | 48 |
49 |
50 | ` 51 | }) 52 | export class App { 53 | angularclassLogo = 'assets/img/angularclass-avatar.png'; 54 | loading = false; 55 | name = '{{cookiecutter.github_repository_name}}'; 56 | url = ''; 57 | 58 | constructor( 59 | public appState: AppState) { 60 | 61 | } 62 | 63 | ngOnInit() { 64 | console.log('Initial App State', this.appState.state); 65 | } 66 | 67 | } 68 | 69 | /* 70 | * Please review the https://github.com/AngularClass/angular2-examples/ repo for 71 | * more angular app examples that you may copy/paste 72 | * (The examples may not be updated as quickly. Please open an issue on github for us to update it) 73 | * For help or questions please contact us at @AngularClass on twitter 74 | * or our chat on Slack at https://AngularClass.com/slack-join 75 | */ 76 | 77 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.e2e.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | describe('App', () => { 3 | 4 | beforeEach(() => { 5 | browser.get('/'); 6 | }); 7 | 8 | 9 | it('should have a title', () => { 10 | let subject = browser.getTitle(); 11 | let result = 'Angular2 Webpack Starter by @gdi2290 from @AngularClass'; 12 | expect(subject).toEqual(result); 13 | }); 14 | 15 | it('should have ', () => { 16 | let subject = element(by.css('app md-toolbar')).isPresent(); 17 | let result = true; 18 | expect(subject).toEqual(result); 19 | }); 20 | 21 | it('should have ', () => { 22 | let subject = element(by.css('app md-content')).isPresent(); 23 | let result = true; 24 | expect(subject).toEqual(result); 25 | }); 26 | 27 | it('should have buttons', () => { 28 | let subject = element(by.css('button')).getText(); 29 | let result = 'Submit Value'; 30 | expect(subject).toEqual(result); 31 | }); 32 | 33 | }); 34 | 35 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { NgModule, ApplicationRef } from '@angular/core'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { FormsModule } from '@angular/forms'; 5 | import { HttpModule } from '@angular/http'; 6 | import { RouterModule } from '@angular/router'; 7 | import { removeNgStyles, createNewHosts } from '@angularclass/hmr'; 8 | 9 | /* 10 | * Platform and Environment providers/directives/pipes 11 | */ 12 | import { ENV_PROVIDERS } from './environment'; 13 | import { ROUTES } from './app.routes'; 14 | // App is our top level component 15 | import { App } from './app.component'; 16 | import { MdModule } from './md.module'; 17 | import { APP_RESOLVER_PROVIDERS } from './app.resolver'; 18 | import { AppState } from './app.service'; 19 | import { Home } from './home'; 20 | import { About } from './about'; 21 | import { NoContent } from './no-content'; 22 | 23 | // Import diretives 24 | import { XLarge } from './home/x-large'; 25 | 26 | // Application wide providers 27 | const APP_PROVIDERS = [ 28 | ...APP_RESOLVER_PROVIDERS, 29 | AppState 30 | ]; 31 | 32 | /** 33 | * `AppModule` is the main entry point into Angular2's bootstraping process 34 | */ 35 | @NgModule({ 36 | bootstrap: [ App ], 37 | declarations: [ 38 | App, 39 | About, 40 | Home, 41 | NoContent, 42 | XLarge 43 | ], 44 | imports: [ // import Angular's modules 45 | BrowserModule, 46 | FormsModule, 47 | HttpModule, 48 | RouterModule.forRoot(ROUTES, { useHash: true }), 49 | MdModule.forRoot() 50 | ], 51 | providers: [ // expose our Services and Providers into Angular's dependency injection 52 | ENV_PROVIDERS, 53 | APP_PROVIDERS 54 | ] 55 | }) 56 | export class AppModule { 57 | constructor(public appRef: ApplicationRef, public appState: AppState) {} 58 | hmrOnInit(store) { 59 | if (!store || !store.state) return; 60 | console.log('HMR store', store); 61 | this.appState._state = store.state; 62 | this.appRef.tick(); 63 | delete store.state; 64 | } 65 | hmrOnDestroy(store) { 66 | var cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement); 67 | // recreate elements 68 | var state = this.appState._state; 69 | store.state = state; 70 | store.disposeOldHosts = createNewHosts(cmpLocation) 71 | // remove styles 72 | removeNgStyles(); 73 | } 74 | hmrAfterDestroy(store) { 75 | // display new elements 76 | store.disposeOldHosts() 77 | delete store.disposeOldHosts; 78 | } 79 | } 80 | 81 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.resolver.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; 3 | import { Injectable } from '@angular/core'; 4 | import { Observable } from 'rxjs/Observable'; 5 | import 'rxjs/add/observable/of'; 6 | 7 | @Injectable() 8 | export class DataResolver implements Resolve { 9 | constructor() { 10 | 11 | } 12 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 13 | return Observable.of({ res: 'I am data'}); 14 | } 15 | } 16 | 17 | // an array of services to resolve routes with data 18 | export const APP_RESOLVER_PROVIDERS = [ 19 | DataResolver 20 | ]; 21 | 22 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { Home } from './home'; 4 | import { About } from './about'; 5 | import { NoContent } from './no-content'; 6 | 7 | import { DataResolver } from './app.resolver'; 8 | 9 | 10 | export const ROUTES: Routes = [ 11 | { path: '', component: Home }, 12 | { path: 'home', component: Home }, 13 | { path: 'about', component: About }, 14 | { 15 | path: 'detail', loadChildren: () => System.import('./+detail') 16 | }, 17 | { path: '**', component: NoContent }, 18 | ]; 19 | 20 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.service.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Injectable } from '@angular/core'; 3 | 4 | @Injectable() 5 | export class AppState { 6 | _state = { }; 7 | 8 | constructor() { 9 | 10 | } 11 | 12 | // already return a clone of the current state 13 | get state() { 14 | return this._state = this._clone(this._state); 15 | } 16 | // never allow mutation 17 | set state(value) { 18 | throw new Error('do not mutate the `.state` directly'); 19 | } 20 | 21 | 22 | get(prop?: any) { 23 | // use our state getter for the clone 24 | const state = this.state; 25 | return state.hasOwnProperty(prop) ? state[prop] : state; 26 | } 27 | 28 | set(prop: string, value: any) { 29 | // internally mutate our state 30 | return this._state[prop] = value; 31 | } 32 | 33 | 34 | _clone(object) { 35 | // simple object clone 36 | return JSON.parse(JSON.stringify( object )); 37 | } 38 | } 39 | 40 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.spec.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { 3 | addProviders, 4 | inject 5 | } from '@angular/core/testing'; 6 | 7 | // Load the implementations that should be tested 8 | import { App } from './app.component'; 9 | import { AppState } from './app.service'; 10 | 11 | describe('App', () => { 12 | // provide our implementations or mocks to the dependency injector 13 | beforeEach(() => addProviders([ 14 | AppState, 15 | App 16 | ])); 17 | 18 | it('should have a url', inject([ App ], (app) => { 19 | expect(app.url).toEqual('https://twitter.com/AngularClass'); 20 | })); 21 | 22 | }); 23 | 24 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/app.style.css: -------------------------------------------------------------------------------- 1 | html, body{ 2 | height: 100%; 3 | background: #F4FAFA; 4 | font-family: Arial, Helvetica, sans-serif; 5 | } 6 | button.active{ 7 | background: #fff; 8 | color: #009688; 9 | } 10 | button.active:hover{ 11 | color: #fff; 12 | } 13 | .fill{ 14 | flex: 1 1 auto; 15 | } 16 | .app-state{ 17 | margin: 15px; 18 | flex: 1; 19 | } 20 | .home{ 21 | flex: 1; 22 | } 23 | md-content{ 24 | display: flex; 25 | flex-direction: column; 26 | height: 100%; 27 | } 28 | footer{ 29 | flex: 0 0 60px; 30 | padding: 10px; 31 | display: flex; 32 | align-items: center; 33 | justify-content: center; 34 | background: #fff; 35 | } 36 | 37 | 38 | /** remove when fixed in angular2-material **/ 39 | /** The overlay-container is an invisible element which contains all individual overlays. */ 40 | .md-overlay-container { 41 | position: absolute; 42 | pointer-events: none; 43 | top: 0; 44 | left: 0; 45 | height: 100%; 46 | width: 100%; } 47 | 48 | /** A single overlay pane. */ 49 | .md-overlay-pane { 50 | position: absolute; 51 | pointer-events: auto; 52 | box-sizing: border-box; 53 | z-index: 1000; } 54 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/environment.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | 3 | // Angular 2 4 | // rc2 workaround 5 | import { enableDebugTools, disableDebugTools } from '@angular/platform-browser'; 6 | import { enableProdMode, ApplicationRef } from '@angular/core'; 7 | // Environment Providers 8 | let PROVIDERS = [ 9 | // common env directives 10 | ]; 11 | 12 | // Angular debug tools in the dev console 13 | // https://github.com/angular/angular/blob/86405345b781a9dc2438c0fbe3e9409245647019/TOOLS_JS.md 14 | let _decorateModuleRef = function identity(value) { return value; }; 15 | 16 | if ('production' === ENV) { 17 | // Production 18 | disableDebugTools(); 19 | enableProdMode(); 20 | 21 | PROVIDERS = [ 22 | ...PROVIDERS, 23 | // custom providers in production 24 | ]; 25 | 26 | } else { 27 | 28 | _decorateModuleRef = (modRef: any) => { 29 | var appRef = modRef.injector.get(ApplicationRef); 30 | var cmpRef = appRef.components[0]; 31 | 32 | let _ng = (window).ng; 33 | enableDebugTools(cmpRef); 34 | (window).ng.probe = _ng.probe; 35 | (window).ng.coreTokens = _ng.coreTokens; 36 | return modRef 37 | }; 38 | 39 | // Development 40 | PROVIDERS = [ 41 | ...PROVIDERS, 42 | // custom providers in development 43 | ]; 44 | 45 | } 46 | 47 | export const decorateModuleRef = _decorateModuleRef; 48 | 49 | export const ENV_PROVIDERS = [ 50 | ...PROVIDERS 51 | ]; 52 | 53 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Component } from '@angular/core'; 3 | 4 | import { AppState } from '../app.service'; 5 | import { Title } from './title'; 6 | 7 | @Component({ 8 | // The selector is what angular internally uses 9 | // for `document.querySelectorAll(selector)` in our index.html 10 | // where, in this case, selector is the string 'home' 11 | selector: 'home', // 12 | // We need to tell Angular's Dependency Injection which providers are in our app. 13 | providers: [ 14 | Title 15 | ], 16 | 17 | // Our list of styles in our component. We may add more to compose many styles together 18 | styleUrls: [ './home.style.scss' ], 19 | // Every Angular template is first compiled by the browser before Angular runs it's compiler 20 | templateUrl: './home.template.pug' 21 | }) 22 | export class Home { 23 | // Set our default values 24 | localState = { value: '' }; 25 | // TypeScript public modifiers 26 | constructor(public appState: AppState, public title: Title) { 27 | 28 | } 29 | 30 | static ngOnInit() { 31 | console.log('hello `Home` component'); 32 | // this.title.getData().subscribe(data => this.data = data); 33 | } 34 | 35 | submitState(value) { 36 | console.log('submitState', value); 37 | this.appState.set('value', value); 38 | this.localState.value = ''; 39 | } 40 | 41 | } 42 | 43 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/home.e2e.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | describe('App', () => { 3 | 4 | beforeEach(() => { 5 | // change hash depending on router LocationStrategy 6 | browser.get('/#/home'); 7 | }); 8 | 9 | 10 | it('should have a title', () => { 11 | let subject = browser.getTitle(); 12 | let result = 'Angular2 Webpack Starter by @gdi2290 from @AngularClass'; 13 | expect(subject).toEqual(result); 14 | }); 15 | 16 | it('should have `your content here` x-large', () => { 17 | let subject = element(by.css('[x-large]')).getText(); 18 | let result = 'Your Content Here'; 19 | expect(subject).toEqual(result); 20 | }); 21 | 22 | 23 | }); 24 | 25 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/home.spec.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { 3 | addProviders, 4 | inject 5 | } from '@angular/core/testing'; 6 | import { Component } from '@angular/core'; 7 | import { BaseRequestOptions, Http } from '@angular/http'; 8 | import { MockBackend } from '@angular/http/testing'; 9 | 10 | // Load the implementations that should be tested 11 | import { AppState } from '../app.service'; 12 | import { Home } from './home.component'; 13 | import { Title } from './title'; 14 | 15 | describe('Home', () => { 16 | // provide our implementations or mocks to the dependency injector 17 | beforeEach(() => addProviders([ 18 | BaseRequestOptions, 19 | MockBackend, 20 | { 21 | provide: Http, 22 | useFactory: function(backend, defaultOptions) { 23 | return new Http(backend, defaultOptions); 24 | }, 25 | deps: [MockBackend, BaseRequestOptions] 26 | }, 27 | 28 | AppState, 29 | Title, 30 | Home 31 | ])); 32 | 33 | it('should have default data', inject([ Home ], (home) => { 34 | expect(home.localState).toEqual({ value: '' }); 35 | })); 36 | 37 | it('should have a title', inject([ Home ], (home) => { 38 | expect(!!home.title).toEqual(true); 39 | })); 40 | 41 | it('should log ngOnInit', inject([ Home ], (home) => { 42 | spyOn(console, 'log'); 43 | expect(console.log).not.toHaveBeenCalled(); 44 | 45 | Home.ngOnInit(); 46 | expect(console.log).toHaveBeenCalled(); 47 | })); 48 | 49 | }); 50 | 51 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/home.style.scss: -------------------------------------------------------------------------------- 1 | .card-container { 2 | display: flex; 3 | flex-direction: column; 4 | margin: 15px; 5 | } 6 | 7 | .sample-content { 8 | flex: 1; 9 | } 10 | 11 | .card-container md-card { 12 | margin: 5px; 13 | } 14 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/home.template.pug: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | .card-container 3 | h1.sample-content(x-large='') {{cookiecutter.github_repository_name}} 4 | hr 5 | div 6 | | For hot module reloading run 7 | pre. 8 | npm run start:hmr 9 | hr 10 | div 11 | h4 Local State 12 | form((ngsubmit)='submitState(localState.value)', autocomplete='off') 13 | input([value]='localState.value', (input)='localState.value = $event.target.value', placeholder='Submit Local State to App State', autofocus='') 14 | button(md-raised-button='', color='primary') Submit Value 15 | // 16 | 17 | Rather than wiring up two-way data-binding ourselves with [value] and (input) 18 | we can use Angular's [(ngModel)] syntax 19 | 20 | pre. 21 | \nthis.localState = {{ localState | json }} 22 | md-card 23 | md-card-title Slider with Value 24 | md-card-content 25 | md-slider(value='24') 26 | md-card 27 | md-card-title Tooltips 28 | md-card-content 29 | button(md-raised-button='', md-tooltip='This is a tooltip!') Hello 30 | button(md-raised-button='', md-tooltip='Another tooltip') World 31 | 32 | 33 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/index.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | export * from './home.component'; 3 | 4 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/title/index.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | export * from './title.service'; 3 | 4 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/title/title.service.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Injectable } from '@angular/core'; 3 | import { Http } from '@angular/http'; 4 | 5 | @Injectable() 6 | export class Title { 7 | value = 'Angular 2'; 8 | constructor(public http: Http) { 9 | 10 | } 11 | 12 | getData() { 13 | console.log('Title#getData(): Get Data'); 14 | // return this.http.get('/assets/data.json') 15 | // .map(res => res.json()); 16 | return { 17 | value: 'AngularClass' 18 | }; 19 | } 20 | 21 | } 22 | 23 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/title/title.spec.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { 3 | addProviders, 4 | inject 5 | } from '@angular/core/testing'; 6 | import { TestComponentBuilder } from '@angular/core/testing'; 7 | import { Component } from '@angular/core'; 8 | import { BaseRequestOptions, Http } from '@angular/http'; 9 | import { MockBackend } from '@angular/http/testing'; 10 | 11 | import { Title } from './title.service'; 12 | 13 | describe('Title', () => { 14 | beforeEach(() => addProviders([ 15 | BaseRequestOptions, 16 | MockBackend, 17 | { 18 | provide: Http, 19 | useFactory: function(backend, defaultOptions) { 20 | return new Http(backend, defaultOptions); 21 | }, 22 | deps: [MockBackend, BaseRequestOptions] 23 | }, 24 | 25 | Title 26 | ])); 27 | 28 | 29 | it('should have http', inject([ Title ], (title) => { 30 | expect(!!title.http).toEqual(true); 31 | })); 32 | 33 | it('should get data from the server', inject([ Title ], (title) => { 34 | spyOn(console, 'log'); 35 | expect(console.log).not.toHaveBeenCalled(); 36 | 37 | title.getData(); 38 | expect(console.log).toHaveBeenCalled(); 39 | expect(title.getData()).toEqual({ value: 'AngularClass' }); 40 | })); 41 | 42 | }); 43 | 44 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/x-large/index.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | export * from './x-large.directive'; 3 | 4 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/x-large/x-large.directive.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Component, Directive, ElementRef, Renderer } from '@angular/core'; 3 | /* 4 | * Directive 5 | * XLarge is a simple directive to show how one is made 6 | */ 7 | @Directive({ 8 | selector: '[x-large]' // using [ ] means selecting attributes 9 | }) 10 | export class XLarge { 11 | constructor(element: ElementRef, renderer: Renderer) { 12 | // simple DOM manipulation to set font size to x-large 13 | // `nativeElement` is the direct reference to the DOM element 14 | // element.nativeElement.style.fontSize = 'x-large'; 15 | 16 | // for server/webworker support use the renderer 17 | renderer.setElementStyle(element.nativeElement, 'fontSize', 'x-large'); 18 | } 19 | } 20 | 21 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/home/x-large/x-large.spec.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { 3 | async, 4 | addProviders, 5 | inject 6 | } from '@angular/core/testing'; 7 | import { TestComponentBuilder } from '@angular/core/testing'; 8 | import { Component } from '@angular/core'; 9 | import { BaseRequestOptions, Http } from '@angular/http'; 10 | import { MockBackend } from '@angular/http/testing'; 11 | 12 | // Load the implementations that should be tested 13 | import { XLarge } from './x-large.directive'; 14 | 15 | describe('x-large directive', () => { 16 | // Create a test component to test directives 17 | @Component({ 18 | template: '', 19 | directives: [ XLarge ] 20 | }) 21 | class TestComponent {} 22 | 23 | it('should sent font-size to x-large', async(inject([TestComponentBuilder], (tcb) => { 24 | return tcb.overrideTemplate(TestComponent, '
Content
') 25 | .createAsync(TestComponent).then((fixture: any) => { 26 | fixture.detectChanges(); 27 | let compiled = fixture.debugElement.nativeElement.children[0]; 28 | expect(compiled.style.fontSize).toBe('x-large'); 29 | }); 30 | }))); 31 | 32 | }); 33 | 34 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/index.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | // App 3 | export * from './app.module'; 4 | 5 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/md.module.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | /* This module is an example how you can package all services and components 3 | from Angular2-Material into one Angular2 module, which you can import in other modules 4 | */ 5 | import { NgModule, ModuleWithProviders } from '@angular/core'; 6 | 7 | import { MdButtonModule } from '@angular2-material/button'; 8 | import { MdButtonToggleModule } from '@angular2-material/button-toggle'; 9 | import { MdCardModule } from '@angular2-material/card'; 10 | import { MdCheckboxModule } from '@angular2-material/checkbox'; 11 | import { MdGridListModule } from '@angular2-material/grid-list'; 12 | import { MdIconModule } from '@angular2-material/icon'; 13 | import { MdInputModule } from '@angular2-material/input'; 14 | import { MdListModule } from '@angular2-material/list'; 15 | import { MdMenuModule } from '@angular2-material/menu'; 16 | import { MdProgressBarModule } from '@angular2-material/progress-bar'; 17 | import { MdProgressCircleModule } from '@angular2-material/progress-circle'; 18 | import { MdRadioModule } from '@angular2-material/radio'; 19 | import { MdSidenavModule } from '@angular2-material/sidenav'; 20 | import { MdSliderModule } from '@angular2-material/slider'; 21 | import { MdSlideToggleModule } from '@angular2-material/slide-toggle'; 22 | import { MdTabsModule } from '@angular2-material/tabs'; 23 | import { MdToolbarModule } from '@angular2-material/toolbar'; 24 | import { MdTooltipModule } from '@angular2-material/tooltip'; 25 | 26 | @NgModule({ 27 | 28 | exports: [ 29 | MdButtonModule, 30 | MdButtonToggleModule, 31 | MdCardModule, 32 | MdCheckboxModule, 33 | MdGridListModule, 34 | MdIconModule, 35 | MdInputModule, 36 | MdListModule, 37 | MdMenuModule, 38 | MdProgressBarModule, 39 | MdProgressCircleModule, 40 | MdRadioModule, 41 | MdSidenavModule, 42 | MdSliderModule, 43 | MdSlideToggleModule, 44 | MdTabsModule, 45 | MdToolbarModule, 46 | MdTooltipModule 47 | ] 48 | }) 49 | 50 | export class MdModule { 51 | 52 | static forRoot(): ModuleWithProviders { 53 | return { 54 | ngModule: MdModule 55 | }; 56 | } 57 | } 58 | 59 | 60 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/no-content/index.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | export * from './no-content'; 3 | 4 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/app/no-content/no-content.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | import { Component } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'no-content', 6 | template: ` 7 |
8 |

404: page missing

9 |
10 | ` 11 | }) 12 | export class NoContent { 13 | 14 | } 15 | 16 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/css/.gitkeep: -------------------------------------------------------------------------------- 1 | @AngularClass 2 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": "AngularClass" 3 | } 4 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # TEAM 5 | 6 | -- -- 7 | 8 | # THANKS 9 | 10 | 11 | PatrickJS -- @gdi2290 12 | AngularClass -- @AngularClass 13 | 14 | # TECHNOLOGY COLOPHON 15 | 16 | HTML5, CSS3 17 | Angular2, TypeScript, Webpack 18 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-144x144.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-192x192.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-36x36.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-48x48.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-72x72.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/android-icon-96x96.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-114x114.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-120x120.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-144x144.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-152x152.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-180x180.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-57x57.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-60x60.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-72x72.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-76x76.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon-precomposed.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/apple-icon.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon-16x16.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon-32x32.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon-96x96.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/favicon.ico -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-144x144.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-150x150.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-310x310.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/icon/ms-icon-70x70.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/img/angular-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/img/angular-logo.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/img/angularclass-avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/img/angularclass-avatar.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/img/angularclass-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/frontend/src/assets/img/angularclass-logo.png -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "/assets/icon/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image/png", 8 | "density": 0.75 9 | }, 10 | { 11 | "src": "/assets/icon/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image/png", 14 | "density": 1.0 15 | }, 16 | { 17 | "src": "/assets/icon/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image/png", 20 | "density": 1.5 21 | }, 22 | { 23 | "src": "/assets/icon/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image/png", 26 | "density": 2.0 27 | }, 28 | { 29 | "src": "/assets/icon/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image/png", 32 | "density": 3.0 33 | }, 34 | { 35 | "src": "/assets/icon/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image/png", 38 | "density": 4.0 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/mock-data/mock-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"res": "data"} 3 | ] 4 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/assets/service-worker.js: -------------------------------------------------------------------------------- 1 | // This file is intentionally without code. 2 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/custom-typings.d.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | /* 3 | * Custom Type Definitions 4 | * When including 3rd party modules you also need to include the type definition for the module 5 | * if they don't provide one within the module. You can try to install it with @types 6 | 7 | npm install @types/node 8 | npm install @types/lodash 9 | 10 | * If you can't find the type definition in the registry we can make an ambient/global definition in 11 | * this file for now. For example 12 | 13 | declare module 'my-module' { 14 | export function doesSomething(value: string): string; 15 | } 16 | 17 | * If you are using a CommonJS module that is using module.exports then you will have to write your 18 | * types using export = yourObjectOrFunction with a namespace above it 19 | * notice how we have to create a namespace that is equal to the function we're 20 | * assigning the export to 21 | 22 | declare module 'jwt-decode' { 23 | function jwtDecode(token: string): any; 24 | namespace jwtDecode {} 25 | export = jwtDecode; 26 | } 27 | 28 | * 29 | * If you're prototying and you will fix the types later you can also declare it as type any 30 | * 31 | 32 | declare var assert: any; 33 | declare var _: any; 34 | declare var $: any; 35 | 36 | * 37 | * If you're importing a module that uses Node.js modules which are CommonJS you need to import as 38 | * in the files such as main.browser.ts or any file within app/ 39 | * 40 | 41 | import * as _ from 'lodash' 42 | 43 | * You can include your type definitions in this file until you create one for the @types 44 | * 45 | */ 46 | 47 | // support NodeJS modules without type definitions 48 | declare module '*'; 49 | 50 | // Extra variables that live on Global that will be replaced by webpack DefinePlugin 51 | declare var ENV: string; 52 | declare var HMR: boolean; 53 | declare var System: SystemJS; 54 | 55 | interface SystemJS { 56 | import: (path?: string) => Promise; 57 | } 58 | 59 | interface GlobalEnvironment { 60 | ENV; 61 | HMR; 62 | SystemJS: SystemJS; 63 | System: SystemJS; 64 | } 65 | 66 | interface Es6PromiseLoader { 67 | (id: string): (exportName?: string) => Promise; 68 | } 69 | 70 | type FactoryEs6PromiseLoader = () => Es6PromiseLoader; 71 | type FactoryPromise = () => Promise; 72 | 73 | type AsyncRoutes = { 74 | [component: string]: Es6PromiseLoader | 75 | Function | 76 | FactoryEs6PromiseLoader | 77 | FactoryPromise 78 | }; 79 | 80 | 81 | type IdleCallbacks = Es6PromiseLoader | 82 | Function | 83 | FactoryEs6PromiseLoader | 84 | FactoryPromise ; 85 | 86 | interface WebpackModule { 87 | hot: { 88 | data?: any, 89 | idle: any, 90 | accept(dependencies?: string | string[], callback?: (updatedDependencies?: any) => void): void; 91 | decline(deps?: any | string | string[]): void; 92 | dispose(callback?: (data?: any) => void): void; 93 | addDisposeHandler(callback?: (data?: any) => void): void; 94 | removeDisposeHandler(callback?: (data?: any) => void): void; 95 | check(autoApply?: any, callback?: (err?: Error, outdatedModules?: any[]) => void): void; 96 | apply(options?: any, callback?: (err?: Error, outdatedModules?: any[]) => void): void; 97 | status(callback?: (status?: string) => void): void | string; 98 | removeStatusHandler(callback?: (status?: string) => void): void; 99 | }; 100 | } 101 | 102 | 103 | interface WebpackRequire { 104 | (id: string): any; 105 | (paths: string[], callback: (...modules: any[]) => void): void; 106 | ensure(ids: string[], callback: (req: WebpackRequire) => void, chunkName?: string): void; 107 | context(directory: string, useSubDirectories?: boolean, regExp?: RegExp): WebpackContext; 108 | } 109 | 110 | interface WebpackContext extends WebpackRequire { 111 | keys(): string[]; 112 | } 113 | 114 | interface ErrorStackTraceLimit { 115 | stackTraceLimit: number; 116 | } 117 | 118 | 119 | // Extend typings 120 | interface NodeRequire extends WebpackRequire {} 121 | interface ErrorConstructor extends ErrorStackTraceLimit {} 122 | interface NodeRequireFunction extends Es6PromiseLoader {} 123 | interface NodeModule extends WebpackModule {} 124 | interface Global extends GlobalEnvironment {} 125 | 126 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/index.html: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <%= webpackConfig.metadata.title %> 11 | 12 | 13 | 14 | <% if (webpackConfig.htmlElements.headTags) { %> 15 | 16 | <%= webpackConfig.htmlElements.headTags %> 17 | <% } %> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Loading... 29 | 30 | 31 | 32 | 41 | 42 | <% if (webpackConfig.metadata.isDevServer && webpackConfig.metadata.HMR !== true) { %> 43 | 44 | 45 | <% } %> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/main.browser.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | /* 3 | * Angular bootstraping 4 | */ 5 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 6 | import { decorateModuleRef } from './app/environment'; 7 | import { ApplicationRef } from '@angular/core'; 8 | import { bootloader } from '@angularclass/hmr'; 9 | /* 10 | * App Module 11 | * our top level module that holds all of our components 12 | */ 13 | import { AppModule } from './app'; 14 | 15 | /* 16 | * Bootstrap our Angular app with a top level NgModule 17 | */ 18 | export function main(): Promise { 19 | return platformBrowserDynamic() 20 | .bootstrapModule(AppModule) 21 | .then(decorateModuleRef) 22 | .catch(err => console.error(err)); 23 | 24 | } 25 | 26 | 27 | bootloader(main); 28 | 29 | 30 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/polyfills.browser.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | // TODO(gdi2290): switch to DLLs 3 | 4 | // Polyfills 5 | 6 | // import 'ie-shim'; // Internet Explorer 9 support 7 | 8 | 9 | // import 'core-js/es6'; 10 | // Added parts of es6 which are necessary for your project or your browser support requirements. 11 | import 'core-js/es6/symbol'; 12 | import 'core-js/es6/object'; 13 | import 'core-js/es6/function'; 14 | import 'core-js/es6/parse-int'; 15 | import 'core-js/es6/parse-float'; 16 | import 'core-js/es6/number'; 17 | import 'core-js/es6/math'; 18 | import 'core-js/es6/string'; 19 | import 'core-js/es6/date'; 20 | import 'core-js/es6/array'; 21 | import 'core-js/es6/regexp'; 22 | import 'core-js/es6/map'; 23 | import 'core-js/es6/set'; 24 | import 'core-js/es6/weak-map'; 25 | import 'core-js/es6/weak-set'; 26 | import 'core-js/es6/typed'; 27 | import 'core-js/es6/reflect'; 28 | // see issue https://github.com/AngularClass/angular2-webpack-starter/issues/709 29 | // import 'core-js/es6/promise'; 30 | 31 | import 'core-js/es7/reflect'; 32 | import 'zone.js/dist/zone'; 33 | 34 | // Typescript emit helpers polyfill 35 | import 'ts-helpers'; 36 | 37 | if ('production' === ENV) { 38 | // Production 39 | 40 | 41 | } else { 42 | // Development 43 | 44 | Error.stackTraceLimit = Infinity; 45 | 46 | require('zone.js/dist/long-stack-trace-zone'); 47 | 48 | } 49 | 50 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/src/vendor.browser.ts: -------------------------------------------------------------------------------- 1 | {% raw %} 2 | // For vendors for example jQuery, Lodash, angular2-jwt just import them here unless you plan on 3 | // chunking vendors files for async loading. You would need to import the async loaded vendors 4 | // at the entry point of the async loaded file. Also see custom-typings.d.ts as you also need to 5 | // run `typings install x` where `x` is your module 6 | 7 | // TODO(gdi2290): switch to DLLs 8 | 9 | // Angular 2 10 | import '@angular/platform-browser'; 11 | import '@angular/platform-browser-dynamic'; 12 | import '@angular/core'; 13 | import '@angular/common'; 14 | import '@angular/forms'; 15 | import '@angular/http'; 16 | import '@angular/router'; 17 | 18 | // Hammer.js 19 | // We need to import this library in order for Material to work 20 | // Material needs this for md-tooltips 21 | import 'hammerjs/hammer.js'; 22 | 23 | // AngularClass 24 | import '@angularclass/hmr'; 25 | 26 | // RxJS 27 | import 'rxjs/add/operator/map'; 28 | import 'rxjs/add/operator/mergeMap'; 29 | 30 | if ('production' === ENV) { 31 | // Production 32 | 33 | 34 | } else { 35 | // Development 36 | 37 | } 38 | 39 | {% endraw %} -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "sourceMap": true, 10 | "noEmitHelpers": true, 11 | "strictNullChecks": false, 12 | "baseUrl": "./src", 13 | "paths": [ 14 | ], 15 | "lib": [ 16 | "dom", 17 | "es6" 18 | ], 19 | "types": [ 20 | "core-js", 21 | "hammerjs", 22 | "jasmine", 23 | "node", 24 | "protractor", 25 | "selenium-webdriver", 26 | "source-map", 27 | "uglify-js", 28 | "webpack" 29 | ] 30 | }, 31 | "exclude": [ 32 | "node_modules", 33 | "dist" 34 | ], 35 | "awesomeTypescriptLoaderOptions": { 36 | "forkChecker": true, 37 | "useWebpackText": true 38 | }, 39 | "compileOnSave": false, 40 | "buildOnSave": false, 41 | "atom": { "rewriteTsconfig": false } 42 | } 43 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "member-access": false, 7 | "member-ordering": [ 8 | true, 9 | "public-before-private", 10 | "static-before-instance", 11 | "variables-before-functions" 12 | ], 13 | "no-any": false, 14 | "no-inferrable-types": false, 15 | "no-internal-module": true, 16 | "no-var-requires": false, 17 | "typedef": false, 18 | "typedef-whitespace": [ 19 | true, 20 | { 21 | "call-signature": "nospace", 22 | "index-signature": "nospace", 23 | "parameter": "nospace", 24 | "property-declaration": "nospace", 25 | "variable-declaration": "nospace" 26 | }, 27 | { 28 | "call-signature": "space", 29 | "index-signature": "space", 30 | "parameter": "space", 31 | "property-declaration": "space", 32 | "variable-declaration": "space" 33 | } 34 | ], 35 | 36 | "ban": false, 37 | "curly": false, 38 | "forin": true, 39 | "label-position": true, 40 | "label-undefined": true, 41 | "no-arg": true, 42 | "no-bitwise": true, 43 | "no-conditional-assignment": true, 44 | "no-console": [ 45 | true, 46 | "debug", 47 | "info", 48 | "time", 49 | "timeEnd", 50 | "trace" 51 | ], 52 | "no-construct": true, 53 | "no-debugger": true, 54 | "no-duplicate-key": true, 55 | "no-duplicate-variable": true, 56 | "no-empty": false, 57 | "no-eval": true, 58 | "no-null-keyword": false, 59 | "no-shadowed-variable": true, 60 | "no-string-literal": false, 61 | "no-switch-case-fall-through": true, 62 | "no-unreachable": true, 63 | "no-unused-expression": true, 64 | "no-unused-variable": false, 65 | "no-use-before-declare": true, 66 | "no-var-keyword": true, 67 | "radix": true, 68 | "switch-default": true, 69 | "triple-equals": [ 70 | true, 71 | "allow-null-check" 72 | ], 73 | "use-strict": [ 74 | true, 75 | "check-module" 76 | ], 77 | 78 | "eofline": true, 79 | "indent": [ 80 | true, 81 | "spaces" 82 | ], 83 | "max-line-length": [ 84 | true, 85 | 100 86 | ], 87 | "no-require-imports": false, 88 | "no-trailing-whitespace": true, 89 | "object-literal-sort-keys": false, 90 | "trailing-comma": [ 91 | true, 92 | { 93 | "multiline": false, 94 | "singleline": "never" 95 | } 96 | ], 97 | 98 | "align": false, 99 | "class-name": true, 100 | "comment-format": [ 101 | true, 102 | "check-space" 103 | ], 104 | "interface-name": false, 105 | "jsdoc-format": true, 106 | "no-consecutive-blank-lines": false, 107 | "no-constructor-vars": false, 108 | "one-line": [ 109 | true, 110 | "check-open-brace", 111 | "check-catch", 112 | "check-else", 113 | "check-finally", 114 | "check-whitespace" 115 | ], 116 | "quotemark": [ 117 | true, 118 | "single", 119 | "avoid-escape" 120 | ], 121 | "semicolon": [true, "always"], 122 | "variable-name": [ 123 | true, 124 | "check-format", 125 | "allow-leading-underscore", 126 | "ban-keywords" 127 | ], 128 | "whitespace": [ 129 | true, 130 | "check-branch", 131 | "check-decl", 132 | "check-operator", 133 | "check-separator", 134 | "check-type" 135 | ], 136 | "import-destructuring-spacing": true 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "mode": "modules", 3 | "out": "doc", 4 | "theme": "default", 5 | "ignoreCompilerErrors": "true", 6 | "experimentalDecorators": "true", 7 | "emitDecoratorMetadata": "true", 8 | "target": "ES5", 9 | "moduleResolution": "node", 10 | "preserveConstEnums": "true", 11 | "stripInternal": "true", 12 | "suppressExcessPropertyErrors": "true", 13 | "suppressImplicitAnyIndexErrors": "true", 14 | "module": "commonjs" 15 | } 16 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/frontend/webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: @AngularClass 3 | */ 4 | 5 | // Look in ./config folder for webpack.dev.js 6 | switch (process.env.NODE_ENV) { 7 | case 'prod': 8 | case 'production': 9 | module.exports = require('./config/webpack.prod'); 10 | break; 11 | case 'test': 12 | case 'testing': 13 | module.exports = require('./config/webpack.test'); 14 | break; 15 | case 'dev': 16 | case 'development': 17 | default: 18 | module.exports = require('./config/webpack.dev'); 19 | } 20 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: {{cookiecutter.app_name}} 2 | site_description: {{cookiecutter.description}} 3 | repo_url: https://github.com/{{cookiecutter.github_username}}/{{cookiecutter.github_repository_name}} 4 | site_dir: site 5 | copyright: Copyright © 2015, {{cookiecutter.github_username}}. 6 | 7 | pages: 8 | - Home: 'index.md' 9 | - API: 10 | - Authentication: 'api/authentication.md' 11 | - Users: 'api/users.md' 12 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/requirements.txt: -------------------------------------------------------------------------------- 1 | # Django 2 | Django==1.9.7 3 | 4 | # Environmental var configuration 5 | django-configurations==1.0 6 | 7 | # For the persistence stores 8 | psycopg2==2.6.1 9 | dj-database-url==0.4.0 10 | 11 | # Models 12 | django-model-utils==2.4 13 | 14 | # Rest apis 15 | djangorestframework==3.3.3 16 | Markdown==2.6.6 17 | django-filter==0.13.0 18 | 19 | # Static files 20 | whitenoise==3.0 21 | 22 | # Media files 23 | boto==2.39.0 24 | django_unique_upload==0.2.1 25 | 26 | # Image manipulation 27 | django-versatileimagefield==1.3 28 | 29 | # For asynchronous queuing 30 | django-rq==0.9.0 31 | 32 | # Time zones support 33 | pytz==2016.3 34 | 35 | # Admion Theme 36 | django-suit==0.2.18 37 | 38 | # WSGI Handler 39 | gevent==1.0.2 40 | gunicorn==19.3.0 41 | 42 | # Static and Media Storage 43 | django-storages-redux==1.2.3 44 | 45 | # Caching 46 | hiredis==0.2.0 47 | django-redis-cache==1.6.5 48 | 49 | # Django-secure 50 | django-secure==1.0.1 51 | 52 | # App Monitoring 53 | newrelic==2.50.0.39 54 | 55 | # Debugging 56 | ipdb==0.9.0 57 | ipython==4.1.2 58 | 59 | # Docs 60 | mkdocs==0.15.3 61 | 62 | # Command Utils 63 | Fabric==1.10.2 64 | 65 | # Mocking 66 | mock==1.3.0 67 | 68 | pytest==2.9.1 69 | pytest-django==2.9.1 70 | 71 | # Code Coverage 72 | coverage==4.0.3 73 | 74 | # Style Enforcement 75 | flake8==2.5.4 76 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E226,E302,E41,E702 3 | max-line-length = 160 4 | exclude = migrations 5 | 6 | [pytest] 7 | DJANGO_SETTINGS_MODULE={{cookiecutter.app_name}}.config 8 | DJANGO_CONFIGURATION=Local 9 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name = "{{cookiecutter.app_name}}", 5 | version = "0.1", 6 | author = "{{cookiecutter.github_username}}", 7 | author_email = "{{cookiecutter.email}}", 8 | description = ("{{cookiecutter.description}}"), 9 | packages=find_packages(), 10 | ) 11 | 12 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name = "{{cookiecutter.app_name}}_tests", 5 | version = "0.1", 6 | author = "{{cookiecutter.github_username}}", 7 | author_email = "{{cookiecutter.email}}", 8 | packages=find_packages(), 9 | ) 10 | 11 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/authentication/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/authentication/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/authentication/test_signals.py: -------------------------------------------------------------------------------- 1 | # from django.test import TestCase 2 | # from nose.tools import ok_ 3 | # from {{cookiecutter.app_name}}_tests.users.factories import UserFactory 4 | # 5 | # class AuthTokenTestCase(TestCase): 6 | # 7 | # def setUp(self): 8 | # self.user = UserFactory() 9 | # 10 | # def test_new_users_get_auth_token(self): 11 | # ok_(self.user.auth_token) 12 | 13 | # TODO: rewrite tests in pytest 14 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/users/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/users/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/users/factories.py: -------------------------------------------------------------------------------- 1 | # import uuid 2 | # import factory 3 | # 4 | # class UserFactory(factory.django.DjangoModelFactory): 5 | # 6 | # class Meta: 7 | # model = 'users.User' 8 | # django_get_or_create = ('username',) 9 | # 10 | # id = factory.Sequence(lambda n: uuid.uuid4()) 11 | # username = factory.Sequence(lambda n: 'testuser{}'.format(n)) 12 | # password = factory.Faker('password', length=10, special_chars=True, digits=True, upper_case=True, lower_case=True) 13 | # email = factory.Faker('email') 14 | # first_name = factory.Faker('first_name') 15 | # last_name = factory.Faker('last_name') 16 | # is_active = True 17 | # is_staff = False 18 | 19 | # TODO: rewrite tests in pytest 20 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/users/test_serializers.py: -------------------------------------------------------------------------------- 1 | # from django.test import TestCase 2 | # from django.forms.models import model_to_dict 3 | # from django.contrib.auth.hashers import check_password 4 | # from nose.tools import eq_, ok_ 5 | # from {{cookiecutter.app_name}}_tests.users.factories import UserFactory 6 | # from {{cookiecutter.app_name}}.users.serializers import CreateUserSerializer 7 | # 8 | # 9 | # class TestCreateUserSerializer(TestCase): 10 | # 11 | # def setUp(self): 12 | # self.user_data = model_to_dict(UserFactory.build()) 13 | # 14 | # def test_serializer_with_empty_data(self): 15 | # serializer = CreateUserSerializer(data={}) 16 | # eq_(serializer.is_valid(), False) 17 | # 18 | # def test_serializer_with_valid_data(self): 19 | # serializer = CreateUserSerializer(data=self.user_data) 20 | # ok_(serializer.is_valid()) 21 | # 22 | # def test_serializer_hashes_password(self): 23 | # serializer = CreateUserSerializer(data=self.user_data) 24 | # ok_(serializer.is_valid()) 25 | # 26 | # user = serializer.save() 27 | # ok_(check_password(self.user_data.get('password'), user.password)) 28 | 29 | # TODO: rewrite tests in pytest 30 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/tests/{{cookiecutter.app_name}}_tests/users/test_views.py: -------------------------------------------------------------------------------- 1 | # from django.core.urlresolvers import reverse 2 | # from django.forms.models import model_to_dict 3 | # from django.contrib.auth.hashers import check_password 4 | # from nose.tools import ok_, eq_ 5 | # from rest_framework.test import APITestCase 6 | # from faker import Faker 7 | # from {{cookiecutter.app_name}}.users.models import User 8 | # from {{cookiecutter.app_name}}_tests.users.factories import UserFactory 9 | # 10 | # fake = Faker() 11 | # 12 | # 13 | # class TestUserAPI(APITestCase): 14 | # """ 15 | # Tests the /users endpoint. 16 | # """ 17 | # 18 | # def setUp(self): 19 | # self.url = reverse('user-list') 20 | # self.user_data = model_to_dict(UserFactory.build()) 21 | # 22 | # def test_post_request_with_no_data_fails(self): 23 | # response = self.client.post(self.url, {}) 24 | # eq_(response.status_code, 400) 25 | # 26 | # def test_post_request_with_valid_data_succeeds(self): 27 | # response = self.client.post(self.url, self.user_data) 28 | # eq_(response.status_code, 201) 29 | # 30 | # user = User.objects.get(pk=response.data.get('id')) 31 | # eq_(user.username, self.user_data.get('username')) 32 | # ok_(check_password(self.user_data.get('password'), user.password)) 33 | # 34 | # 35 | # class TestUserDetailAPI(APITestCase): 36 | # 37 | # def setUp(self): 38 | # self.user = UserFactory() 39 | # self.url = reverse('user-detail', kwargs={'pk': self.user.pk}) 40 | # self.client.credentials(HTTP_AUTHORIZATION='Token {}'.format(self.user.auth_token)) 41 | # 42 | # def test_get_request_returns_a_given_user(self): 43 | # response = self.client.get(self.url) 44 | # eq_(response.status_code, 200) 45 | # 46 | # def test_put_request_updates_a_user(self): 47 | # new_first_name = fake.first_name() 48 | # payload = {'first_name': new_first_name} 49 | # response = self.client.put(self.url, payload) 50 | # eq_(response.status_code, 200) 51 | # 52 | # user = User.objects.get(pk=self.user.id) 53 | # eq_(user.first_name, new_first_name) 54 | 55 | # TODO: rewrite tests in pytest 56 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/authentication/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/authentication/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/authentication/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/authentication/migrations/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/authentication/models.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.db.models.signals import post_save 3 | from django.dispatch import receiver 4 | from rest_framework.authtoken.models import Token 5 | 6 | 7 | @receiver(post_save, sender=settings.AUTH_USER_MODEL) 8 | def create_auth_token(sender, instance=None, created=False, **kwargs): 9 | if created: 10 | Token.objects.create(user=instance) 11 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/authentication/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from rest_framework.authtoken.views import obtain_auth_token 3 | from rest_framework import urls 4 | 5 | from rest_framework.urlpatterns import format_suffix_patterns 6 | 7 | from {{cookiecutter.app_name}}.authentication import views 8 | 9 | urlpatterns = [ 10 | url(r'^login/$', views.Login.as_view()), 11 | url(r'^logout/$', views.Logout.as_view()), 12 | url(r'^active-user/$', views.ActiveUser.as_view()), 13 | # url(r'^api-token-auth/', obtain_auth_token), 14 | url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), 15 | ] 16 | 17 | urlpatterns = format_suffix_patterns(urlpatterns) 18 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/authentication/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import login, logout 2 | from django.contrib.auth.forms import AuthenticationForm 3 | from rest_framework.permissions import AllowAny, IsAuthenticated 4 | from rest_framework.response import Response 5 | from rest_framework.views import APIView 6 | from rest_framework.serializers import ValidationError 7 | 8 | from {{cookiecutter.app_name}}.users.serializers import UserSerializer 9 | 10 | 11 | class Login(APIView): 12 | permission_classes = (AllowAny, ) 13 | 14 | def post(self, request, format=None): 15 | form = AuthenticationForm(request, data=request.data) 16 | if not form.is_valid(): 17 | raise ValidationError(form.errors) 18 | 19 | user = form.get_user() 20 | login(request, user) 21 | 22 | return Response(UserSerializer(user).data) 23 | 24 | 25 | class Logout(APIView): 26 | permission_classes = (IsAuthenticated, ) 27 | 28 | def get(self, request, format=None): 29 | logout(request) 30 | 31 | return Response({'status': 'success'}) 32 | 33 | 34 | class ActiveUser(APIView): 35 | permission_classes = (IsAuthenticated, ) 36 | 37 | def get(self, request, format=None): 38 | return Response(UserSerializer(request.user).data) 39 | 40 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/config/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from {{cookiecutter.app_name}}.config.local import Local # noqa 4 | from {{cookiecutter.app_name}}.config.production import Production # noqa 5 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/config/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os.path import join 3 | 4 | from configurations import Configuration, values 5 | 6 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 7 | PROJECT_PATH = os.path.dirname(os.path.dirname(BASE_DIR)) 8 | 9 | 10 | class Common(Configuration): 11 | 12 | INSTALLED_APPS = ( 13 | # Admin templates 14 | 'suit', 15 | 16 | # Django 17 | 'django.contrib.admin', 18 | 'django.contrib.auth', 19 | 'django.contrib.contenttypes', 20 | 'django.contrib.sessions', 21 | 'django.contrib.messages', 22 | 'django.contrib.staticfiles', 23 | 24 | # Third party apps 25 | 'rest_framework', # utilities for rest apis 26 | 'rest_framework.authtoken', # token authentication 27 | 'django_rq', # asynchronous queuing 28 | 'versatileimagefield', # image manipulation 29 | 30 | # Your apps 31 | '{{cookiecutter.app_name}}.authentication', 32 | '{{cookiecutter.app_name}}.users' 33 | 34 | ) 35 | 36 | # https://docs.djangoproject.com/en/1.8/topics/http/middleware/ 37 | MIDDLEWARE_CLASSES = ( 38 | 'django.contrib.sessions.middleware.SessionMiddleware', 39 | 'django.middleware.common.CommonMiddleware', 40 | 'django.middleware.csrf.CsrfViewMiddleware', 41 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 42 | 'django.contrib.messages.middleware.MessageMiddleware', 43 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 44 | 'django.middleware.security.SecurityMiddleware' 45 | ) 46 | 47 | ROOT_URLCONF = 'urls' 48 | 49 | SECRET_KEY = 'Not a secret' 50 | WSGI_APPLICATION = 'wsgi.application' 51 | 52 | # Email 53 | EMAIL_BACKEND = values.Value('django.core.mail.backends.smtp.EmailBackend') 54 | 55 | MANAGERS = ( 56 | ('Author', '{{cookiecutter.email}}'), 57 | ) 58 | 59 | # General 60 | APPEND_SLASH = values.BooleanValue(False) 61 | TIME_ZONE = 'Asia/Jerusalem' 62 | LANGUAGE_CODE = 'en-us' 63 | # If you set this to False, Django will make some optimizations so as not 64 | # to load the internationalization machinery. 65 | USE_I18N = False 66 | USE_L10N = True 67 | USE_TZ = True 68 | LOGIN_REDIRECT_URL = '/' 69 | 70 | # Static Files 71 | STATIC_ROOT = join(PROJECT_PATH, 'static_root', 'static') 72 | STATICFILES_DIRS = [join(PROJECT_PATH, 'client', 'static'), ] 73 | STATIC_URL = '/static/' 74 | STATICFILES_FINDERS = ( 75 | 'django.contrib.staticfiles.finders.FileSystemFinder', 76 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 77 | ) 78 | 79 | # Media files 80 | MEDIA_ROOT = join(PROJECT_PATH, 'client', 'static') 81 | MEDIA_URL = '/media/' 82 | 83 | TEMPLATES = [ 84 | { 85 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 86 | 'DIRS': [join(MEDIA_ROOT, 'build')], 87 | 'OPTIONS': { 88 | 'context_processors': [ 89 | 'django.core.context_processors.request', 90 | 'django.contrib.auth.context_processors.auth', 91 | 'django.template.context_processors.debug', 92 | 'django.template.context_processors.i18n', 93 | 'django.template.context_processors.media', 94 | 'django.template.context_processors.static', 95 | 'django.template.context_processors.tz', 96 | 'django.contrib.messages.context_processors.messages' 97 | ], 98 | 'loaders':[ 99 | ('django.template.loaders.cached.Loader', [ 100 | 'django.template.loaders.filesystem.Loader', 101 | 'django.template.loaders.app_directories.Loader', 102 | ]), 103 | ], 104 | }, 105 | }, 106 | ] 107 | 108 | SUIT_CONFIG = { 109 | # header 110 | 'ADMIN_NAME': '{{cookiecutter.app_name | replace("_", " ") | replace("-", " ") | title}} Admin', 111 | 112 | # menu 113 | 'MENU_ICONS': { 114 | 'sites': 'icon-leaf', 115 | 'auth': 'icon-lock', 116 | }, 117 | 'MENU_OPEN_FIRST_CHILD': False, 118 | 'MENU_EXCLUDE': ('authtoken'), 119 | } 120 | 121 | 122 | # Set DEBUG to False as a default for safety 123 | # https://docs.djangoproject.com/en/dev/ref/settings/#debug 124 | DEBUG = values.BooleanValue(False) 125 | for config in TEMPLATES: 126 | config['OPTIONS']['debug'] = DEBUG 127 | 128 | # Logging 129 | LOGGING = { 130 | 'version': 1, 131 | 'disable_existing_loggers': False, 132 | 'filters': { 133 | 'require_debug_false': { 134 | '()': 'django.utils.log.RequireDebugFalse' 135 | } 136 | }, 137 | 'formatters': { 138 | 'verbose': { 139 | 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' 140 | }, 141 | 'simple': { 142 | 'format': '%(levelname)s %(message)s' 143 | }, 144 | 'rq_console': { 145 | 'format': '%(asctime)s %(message)s', 146 | 'datefmt': '%H:%M:%S', 147 | }, 148 | }, 149 | 'handlers': { 150 | 'mail_admins': { 151 | 'level': 'ERROR', 152 | 'filters': ['require_debug_false'], 153 | 'class': 'django.utils.log.AdminEmailHandler' 154 | }, 155 | 'console': { 156 | 'level': 'DEBUG', 157 | 'class': 'logging.StreamHandler', 158 | 'formatter': 'simple' 159 | }, 160 | 'rq_console': { 161 | 'level': 'DEBUG', 162 | 'class': 'rq.utils.ColorizingStreamHandler', 163 | 'formatter': 'rq_console', 164 | 'exclude': ['%(asctime)s'], 165 | }, 166 | }, 167 | 'loggers': { 168 | 'django.request': { 169 | 'handlers': ['mail_admins'], 170 | 'level': 'ERROR', 171 | 'propagate': True 172 | }, 173 | 'rq.worker': { 174 | 'handlers': ['rq_console'], 175 | 'level': 'DEBUG' 176 | }, 177 | } 178 | } 179 | 180 | # Custom user app 181 | AUTH_USER_MODEL = 'users.User' 182 | 183 | # Django Rest Framework 184 | REST_FRAMEWORK = { 185 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 186 | 'PAGE_SIZE': 100, 187 | 'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S%z', 188 | 'DEFAULT_RENDERER_CLASSES': ( 189 | 'rest_framework.renderers.JSONRenderer', 190 | 'rest_framework.renderers.BrowsableAPIRenderer', 191 | ), 192 | 'DEFAULT_PERMISSION_CLASSES': [ 193 | 'rest_framework.permissions.IsAuthenticated', 194 | ], 195 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 196 | 'rest_framework.authentication.SessionAuthentication', 197 | 'rest_framework.authentication.TokenAuthentication', 198 | ) 199 | } 200 | 201 | # Versatile Image Field 202 | VERSATILEIMAGEFIELD_SETTINGS = { 203 | # The amount of time, in seconds, that references to created images 204 | # should be stored in the cache. Defaults to `2592000` (30 days) 205 | 'cache_length': 2592000, 206 | 'cache_name': 'versatileimagefield_cache', 207 | 'jpeg_resize_quality': 70, 208 | 'sized_directory_name': '__sized__', 209 | 'filtered_directory_name': '__filtered__', 210 | 'placeholder_directory_name': '__placeholder__', 211 | 'create_images_on_demand': False 212 | } 213 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/config/local.py: -------------------------------------------------------------------------------- 1 | import os 2 | from {{cookiecutter.app_name}}.config.common import Common 3 | from configurations import values 4 | 5 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 6 | 7 | 8 | class Local(Common): 9 | 10 | DEBUG = values.BooleanValue(True) 11 | for config in Common.TEMPLATES: 12 | config['OPTIONS']['debug'] = DEBUG 13 | 14 | DATABASES = { 15 | 'default': { 16 | 'ENGINE': 'django.db.backends.sqlite3', 17 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 18 | } 19 | } 20 | 21 | 22 | # Testing 23 | # INSTALLED_APPS = Common.INSTALLED_APPS 24 | # INSTALLED_APPS += ('django_nose',) 25 | # TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' 26 | # NOSE_ARGS = [ 27 | # BASE_DIR, 28 | # '--nologcapture', 29 | # '--with-coverage', 30 | # '--with-progressive', 31 | # '--cover-package={}'.format(BASE_DIR) 32 | # ] 33 | 34 | # Mail 35 | EMAIL_HOST = 'localhost' 36 | EMAIL_PORT = 1025 37 | EMAIL_BACKEND = values.Value('django.core.mail.backends.console.EmailBackend') 38 | 39 | # Django RQ local settings 40 | RQ_QUEUES = { 41 | 'default': { 42 | 'URL': os.getenv('REDISTOGO_URL', 'redis://localhost:6379'), 43 | 'DB': 0, 44 | 'DEFAULT_TIMEOUT': 500, 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/config/production.py: -------------------------------------------------------------------------------- 1 | import os 2 | from configurations import values 3 | from boto.s3.connection import OrdinaryCallingFormat 4 | from {{cookiecutter.app_name}}.config.common import Common 5 | 6 | try: 7 | # Python 2.x 8 | import urlparse 9 | except ImportError: 10 | # Python 3.x 11 | from urllib import parse as urlparse 12 | 13 | 14 | class Production(Common): 15 | 16 | # Honor the 'X-Forwarded-Proto' header for request.is_secure() 17 | # https://devcenter.heroku.com/articles/getting-started-with-django 18 | SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') 19 | 20 | INSTALLED_APPS = Common.INSTALLED_APPS 21 | SECRET_KEY = values.SecretValue() 22 | 23 | # Postgres 24 | DATABASES = values.DatabaseURLValue('postgres://localhost/{{cookiecutter.app_name}}') 25 | 26 | # django-secure 27 | # http://django-secure.readthedocs.org/en/v0.1.2/settings.html 28 | INSTALLED_APPS += ("djangosecure", ) 29 | 30 | SECURE_HSTS_SECONDS = 60 31 | SECURE_HSTS_INCLUDE_SUBDOMAINS = values.BooleanValue(True) 32 | SECURE_FRAME_DENY = values.BooleanValue(True) 33 | SECURE_CONTENT_TYPE_NOSNIFF = values.BooleanValue(True) 34 | SECURE_BROWSER_XSS_FILTER = values.BooleanValue(True) 35 | SESSION_COOKIE_SECURE = values.BooleanValue(False) 36 | SESSION_COOKIE_HTTPONLY = values.BooleanValue(True) 37 | SECURE_SSL_REDIRECT = values.BooleanValue(True) 38 | 39 | # Site 40 | # https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts 41 | ALLOWED_HOSTS = ["*"] 42 | 43 | INSTALLED_APPS += ("gunicorn", ) 44 | 45 | # Template 46 | # https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs 47 | TEMPLATE_LOADERS = ( 48 | ('django.template.loaders.cached.Loader', ( 49 | 'django.template.loaders.filesystem.Loader', 50 | 'django.template.loaders.app_directories.Loader', 51 | )), 52 | ) 53 | 54 | # Media files 55 | # http://django-storages.readthedocs.org/en/latest/index.html 56 | INSTALLED_APPS += ('storages',) 57 | DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage' 58 | AWS_ACCESS_KEY_ID = values.Value('DJANGO_AWS_ACCESS_KEY_ID') 59 | AWS_SECRET_ACCESS_KEY = values.Value('DJANGO_AWS_SECRET_ACCESS_KEY') 60 | AWS_STORAGE_BUCKET_NAME = values.Value('DJANGO_AWS_STORAGE_BUCKET_NAME') 61 | AWS_AUTO_CREATE_BUCKET = True 62 | AWS_QUERYSTRING_AUTH = False 63 | MEDIA_URL = 'https://s3.amazonaws.com/{}/'.format(AWS_STORAGE_BUCKET_NAME) 64 | AWS_S3_CALLING_FORMAT = OrdinaryCallingFormat() 65 | 66 | # https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#cache-control 67 | # Response can be cached by browser and any intermediary caches (i.e. it is "public") for up to 1 day 68 | # 86400 = (60 seconds x 60 minutes x 24 hours) 69 | AWS_HEADERS = { 70 | 'Cache-Control': 'max-age=86400, s-maxage=86400, must-revalidate', 71 | } 72 | 73 | # Static files 74 | STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage' 75 | 76 | # Caching 77 | redis_url = urlparse.urlparse(os.environ.get('REDISTOGO_URL', 'redis://localhost:6379')) 78 | CACHES = { 79 | 'default': { 80 | 'BACKEND': 'redis_cache.RedisCache', 81 | 'LOCATION': '{}:{}'.format(redis_url.hostname, redis_url.port), 82 | 'OPTIONS': { 83 | 'DB': 0, 84 | 'PASSWORD': redis_url.password, 85 | 'PARSER_CLASS': 'redis.connection.HiredisParser', 86 | 'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool', 87 | 'CONNECTION_POOL_CLASS_KWARGS': { 88 | 'max_connections': 50, 89 | 'timeout': 20, 90 | } 91 | } 92 | } 93 | } 94 | 95 | # Django RQ production settings 96 | RQ_QUEUES = { 97 | 'default': { 98 | 'URL': os.getenv('REDISTOGO_URL', 'redis://localhost:6379'), 99 | 'DB': 0, 100 | 'DEFAULT_TIMEOUT': 500, 101 | }, 102 | } 103 | 104 | Common.VERSATILEIMAGEFIELD_SETTINGS['create_images_on_demand'] = False 105 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/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", "{{cookiecutter.app_name}}.config") 7 | os.environ.setdefault("DJANGO_CONFIGURATION", "Local") 8 | 9 | from configurations.management import execute_from_command_line 10 | 11 | execute_from_command_line(sys.argv) 12 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/urls.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.conf import settings 4 | from django.conf.urls import include, url 5 | from django.core.urlresolvers import reverse_lazy 6 | from django.conf.urls.static import static 7 | from django.contrib import admin 8 | from django.contrib.auth import views 9 | from django.views.generic.base import RedirectView 10 | from rest_framework.routers import DefaultRouter 11 | 12 | from {{cookiecutter.app_name}}.users.views import UserViewSet, home 13 | 14 | router = DefaultRouter() 15 | router.register(r'users', UserViewSet) 16 | 17 | urlpatterns = ([ 18 | url(r'^$', home), 19 | 20 | url(r'^admin/', include(admin.site.urls)), 21 | url(r'^api/', include('authentication.urls')), 22 | url(r'^api/', include(router.urls)), 23 | 24 | # the 'api-root' from django rest-frameworks default router 25 | # http://www.django-rest-framework.org/api-guide/routers/#defaultrouter 26 | # url(r'^rest/$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)), 27 | 28 | ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 29 | + [url(r'^.*$', home)]) 30 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/admin.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | from django import forms 4 | from django.contrib import admin 5 | from django.contrib.auth.admin import UserAdmin as AuthUserAdmin 6 | from django.contrib.auth.forms import UserChangeForm, UserCreationForm 7 | 8 | from {{cookiecutter.app_name}}.users.models import User 9 | 10 | 11 | class CustomUserChangeForm(UserChangeForm): 12 | 13 | class Meta(UserChangeForm.Meta): 14 | model = User 15 | 16 | 17 | class CustomUserCreationForm(UserCreationForm): 18 | 19 | # http://james.lin.net.nz/2013/06/08/django-custom-user-model-in-admin-relation-auth_user-does-not-exist/ 20 | def clean_username(self): 21 | # Since User.username is unique, this check is redundant, 22 | # but it sets a nicer error message than the ORM. See #13147. 23 | username = self.cleaned_data["username"] 24 | try: 25 | User._default_manager.get(username=username) 26 | except User.DoesNotExist: 27 | return username 28 | raise forms.ValidationError(self.error_messages['duplicate_username']) 29 | 30 | class Meta(UserCreationForm.Meta): 31 | model = User 32 | 33 | 34 | @admin.register(User) 35 | class UserAdmin(AuthUserAdmin): 36 | form = CustomUserChangeForm 37 | add_form = CustomUserCreationForm 38 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9 on 2016-01-31 23:31 3 | from __future__ import unicode_literals 4 | 5 | import django.contrib.auth.models 6 | import django.core.validators 7 | from django.db import migrations, models 8 | import django.utils.timezone 9 | import uuid 10 | 11 | 12 | class Migration(migrations.Migration): 13 | 14 | initial = True 15 | 16 | dependencies = [ 17 | ('auth', '0007_alter_validators_add_error_messages'), 18 | ] 19 | 20 | operations = [ 21 | migrations.CreateModel( 22 | name='User', 23 | fields=[ 24 | ('password', models.CharField(max_length=128, verbose_name='password')), 25 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last auth')), 26 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 27 | ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')], verbose_name='username')), 28 | ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), 29 | ('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')), 30 | ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), 31 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), 32 | ('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')), 33 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), 34 | ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), 35 | ('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')), 36 | ('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')), 37 | ], 38 | options={ 39 | 'abstract': False, 40 | 'verbose_name': 'user', 41 | 'verbose_name_plural': 'users', 42 | }, 43 | managers=[ 44 | ('objects', django.contrib.auth.models.UserManager()), 45 | ], 46 | ), 47 | ] 48 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitassaraf/angular2-django-boilerplate/8c7c738b7c0202d437be7198b331e3b39bfa14d4/{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/migrations/__init__.py -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | import uuid 4 | from django.db import models 5 | from django.contrib.auth.models import AbstractUser 6 | from django.utils.encoding import python_2_unicode_compatible 7 | # from django.utils.translation import ugettext_lazy as _ 8 | 9 | 10 | @python_2_unicode_compatible 11 | class User(AbstractUser): 12 | id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) 13 | 14 | def __str__(self): 15 | return self.username 16 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | 4 | class IsOwnerOrReadOnly(permissions.BasePermission): 5 | """ 6 | Object-level permission to only allow owners of an object to edit it. 7 | """ 8 | 9 | def has_object_permission(self, request, view, obj): 10 | 11 | if request.method in permissions.SAFE_METHODS: 12 | return True 13 | 14 | return obj == request.user 15 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from {{cookiecutter.app_name}}.users.models import User 4 | 5 | 6 | class UserSerializer(serializers.ModelSerializer): 7 | 8 | class Meta: 9 | model = User 10 | fields = ('username', 'first_name', 'last_name', 'email') 11 | write_only_fields = ('password',) 12 | 13 | def create(self, validated_data): 14 | # call create_user on user object. Without this 15 | # the password will be stored in plain text. 16 | user = User.objects.create_user(**validated_data) 17 | return user 18 | 19 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/users/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.views.decorators.csrf import ensure_csrf_cookie 3 | from rest_framework import viewsets, mixins 4 | from rest_framework.permissions import AllowAny 5 | 6 | from {{cookiecutter.app_name}}.users.models import User 7 | from {{cookiecutter.app_name}}.users.permissions import IsOwnerOrReadOnly 8 | from {{cookiecutter.app_name}}.users.serializers import UserSerializer 9 | 10 | 11 | @ensure_csrf_cookie 12 | def home(request): 13 | return render(request, 'index.html', { 14 | 'USE_LIVE_RELOAD': False # settings.DEBUG 15 | }) 16 | 17 | 18 | class UserViewSet(mixins.CreateModelMixin, 19 | mixins.RetrieveModelMixin, 20 | mixins.UpdateModelMixin, 21 | viewsets.GenericViewSet): 22 | """ 23 | Creates, Updates, and retrives User accounts 24 | """ 25 | queryset = User.objects.all() 26 | serializer_class = UserSerializer 27 | permission_classes = (IsOwnerOrReadOnly,) 28 | 29 | def get_permissions(self): 30 | if self.request.method == 'POST': 31 | return [AllowAny()] 32 | return [IsOwnerOrReadOnly()] 33 | 34 | 35 | -------------------------------------------------------------------------------- /{{cookiecutter.github_repository_name}}/src/{{cookiecutter.app_name}}/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for {{cookiecutter.app_name}} 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/1.8/howto/deployment/wsgi/ 8 | """ 9 | import os 10 | 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config") 12 | os.environ.setdefault("DJANGO_CONFIGURATION", "Production") 13 | 14 | from configurations.wsgi import get_wsgi_application # noqa 15 | from whitenoise.django import DjangoWhiteNoise # noqa 16 | 17 | application = get_wsgi_application() 18 | application = DjangoWhiteNoise(application) 19 | --------------------------------------------------------------------------------