Merge branch 'feat/manager_deploy' into 'staging'
Deploy sibapp with managers See merge request startinblox/applications/sib-app!74
14
.gitignore
vendored
@ -1,9 +1,5 @@
|
||||
/node_modules
|
||||
/src/config.json
|
||||
/www/index.html
|
||||
/www/index.*.html
|
||||
/www/styles/
|
||||
/www/scripts/
|
||||
/www/lib/
|
||||
/www/oidc-client-config.json
|
||||
*.iml
|
||||
**/node_modules
|
||||
**/config.json
|
||||
*.iml
|
||||
*.swp
|
||||
dist
|
||||
|
86
Makefile
@ -1,86 +0,0 @@
|
||||
DIST_DIR := www
|
||||
|
||||
SCRIPT_SRC := $(wildcard src/scripts/*.js)
|
||||
|
||||
SCRIPT_DEST := $(SCRIPT_SRC:src/%=$(DIST_DIR)/%)
|
||||
|
||||
default: build
|
||||
|
||||
build: $(DIST_DIR)/index.html $(DIST_DIR)/styles/index.css $(SCRIPT_DEST)
|
||||
|
||||
watch:
|
||||
@echo 'watching for change'
|
||||
@echo 'press Ctrl+C to stop'
|
||||
@while true; do \
|
||||
$(MAKE) --silent build; \
|
||||
sleep 0.5; \
|
||||
done
|
||||
|
||||
# pug
|
||||
$(DIST_DIR)/index.html: src/index.pug src/config.json $(wildcard src/*.pug src/*/*.pug)
|
||||
@echo pug: $< ➜ $@
|
||||
|
||||
@export ENV="dev"; \
|
||||
node_modules/.bin/pug --pretty $< --out $(dir $@) -O src/config.json || touch $@
|
||||
|
||||
# pug (alpha)
|
||||
$(DIST_DIR)/index.alpha.html: src/index.pug src/config.json $(wildcard src/*.pug src/*/*.pug)
|
||||
@echo pug: $< ➜ $@
|
||||
|
||||
@export ENV="alpha"; \
|
||||
node_modules/.bin/pug --pretty $< --out $(dir $@) -E alpha.html -O src/config.json || touch $@
|
||||
|
||||
# pug (paris)
|
||||
$(DIST_DIR)/index.paris.html: src/index.pug src/config.json $(wildcard src/*.pug src/*/*.pug)
|
||||
@echo pug: $< ➜ $@
|
||||
|
||||
@export ENV="paris"; \
|
||||
node_modules/.bin/pug --pretty $< --out $(dir $@) -E paris.html -O src/config.json || touch $@
|
||||
|
||||
# pug (nantes)
|
||||
$(DIST_DIR)/index.nantes.html: src/index.pug src/config.json $(wildcard src/*.pug src/*/*.pug)
|
||||
@echo pug: $< ➜ $@
|
||||
|
||||
@export ENV="nantes"; \
|
||||
node_modules/.bin/pug --pretty $< --out $(dir $@) -E nantes.html -O src/config.json || touch $@
|
||||
|
||||
# sass
|
||||
$(DIST_DIR)/styles/index.css: src/styles/_index.scss $(wildcard src/*.scss src/*/*.scss src/*/*/*.scss src/*/*/*/*.scss)
|
||||
@echo sass: $< ➜ $@
|
||||
@node_modules/.bin/node-sass $< $@ --source-map true --source-map-contents || touch $@
|
||||
|
||||
# babel
|
||||
$(DIST_DIR)/%.js: src/%.js .babelrc
|
||||
@echo babel: $< ➜ $@
|
||||
@mkdir -p $(dir $@)
|
||||
@node_modules/.bin/babel $< --out-file $@ --source-maps || touch $@
|
||||
|
||||
buildparis: build
|
||||
$(MAKE) $(DIST_DIR)/index.paris.html
|
||||
|
||||
syncparis: buildparis
|
||||
rsync -rv --exclude '*.html' www/* test-paris@ssh-test-paris.happy-dev.fr:~/www/
|
||||
rsync --no-R --no-implied-dirs www/index.paris.html test-paris@ssh-test-paris.happy-dev.fr:~/www/index.html
|
||||
rsync -v www/.htaccess test-paris@ssh-test-paris.happy-dev.fr:~/www/
|
||||
|
||||
buildnantes: build
|
||||
$(MAKE) $(DIST_DIR)/index.nantes.html
|
||||
|
||||
syncnantes: buildnantes
|
||||
rsync -rv --exclude '*.html' www/* test-nantes@ssh-test-nantes.happy-dev.fr:~/www/
|
||||
rsync --no-R --no-implied-dirs www/index.nantes.html test-nantes@ssh-test-nantes.happy-dev.fr:~/www/index.html
|
||||
rsync -v www/.htaccess test-nantes@ssh-test-nantes.happy-dev.fr:~/www/
|
||||
|
||||
buildalpha: build
|
||||
$(MAKE) $(DIST_DIR)/index.alpha.html
|
||||
|
||||
syncalpha: buildalpha
|
||||
rsync -rv --exclude '*.html' www/* alpha@ssh-alpha.happy-dev.fr:~/www/
|
||||
rsync --no-R --no-implied-dirs www/index.alpha.html alpha@ssh-alpha.happy-dev.fr:~/www/index.html
|
||||
rsync -v www/.htaccess alpha@ssh-alpha.happy-dev.fr:~/www/
|
||||
|
||||
sync: syncnantes syncparis
|
||||
|
||||
syncprod: syncalpha
|
||||
|
||||
.PHONY: default build watch sync syncprod
|
185
README.md
@ -4,166 +4,73 @@ SiB App is the magic tool that allows the Happy Dev network to thrive in a decen
|
||||
|
||||
## Getting Started
|
||||
|
||||
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
|
||||
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
To install SiB App, you'll need to have:
|
||||
To install SiB App, you'll need:
|
||||
|
||||
- Python3 & Pip
|
||||
- NodeJS & NPM
|
||||
- A Prosody Server
|
||||
- (Optional) A SMTP Server
|
||||
* A SIB server with the appropriate modules
|
||||
* A Prosody Server (with [appropriate modules](https://git.happy-dev.fr/startinblox/prosody/custom-prosody-modules/)
|
||||
* A SMTP Server (optional)
|
||||
* NodeJS on your machine
|
||||
|
||||
### Installing
|
||||
Before diving in you have to check your SIB server supports the following LDP packages:
|
||||
|
||||
#### At first, you'll need to deploy a `sib-manager` server, then configure it.
|
||||
* djangoldp_account: 0.2.14
|
||||
* djangoldp_circle: 0.1.15
|
||||
* djangoldp_joboffer: 0.1.1
|
||||
* djangoldp_notification: 0.1.4
|
||||
* djangoldp_profile: 0.1.4
|
||||
* djangoldp_project: 0.1.12
|
||||
* djangoldp_skill: 0.1.1
|
||||
* oidc_provider: 'git+https://github.com/jblemee/django-oidc-provider.git@develop'
|
||||
|
||||
#### `sib-manager` installation or update
|
||||
Those packages are given with the last stable version tested.
|
||||
|
||||
```
|
||||
$ pip3 install -U sib-manager
|
||||
Refer to the [documentation to install a SIB server](https://git.happy-dev.fr/startinblox/devops/doc/wikis/install_sib_server) with this configuration.
|
||||
|
||||
## Build the application
|
||||
|
||||
In order to find your server(s) the client application needs to be assembled with the proper configuration.
|
||||
|
||||
Get the code of the SIB app on your machine:
|
||||
|
||||
```bash
|
||||
git clone ...
|
||||
```
|
||||
|
||||
#### `sib-manager` deploy
|
||||
Then create a `config.json` with all the the capabilities the SIB App requires. Which are:
|
||||
|
||||
```
|
||||
$ sib startproject newserver -m djangoldp_project -m oidc_provider@django-oidc-provider -m djangoldp_circle -m djangoldp_joboffer -m djangoldp_profile -m djangoldp_skill -m djangoldp_account -m djangoldp_notification -m djangoldp_conversation
|
||||
$ sib initproject newserver
|
||||
* circles
|
||||
* groups
|
||||
* joboffers
|
||||
* projects
|
||||
* skills
|
||||
* users
|
||||
|
||||
[The documentation](https://git.happy-dev.fr/startinblox/devops/doc/wikis/build_sib_application) explains the details of this file but for convienence a `config.sample.json` exists in the source.
|
||||
|
||||
Then build your new SIB App:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
We're using
|
||||
- `djangoldp_project`,
|
||||
- `django-oidc-provider`,
|
||||
- `djangoldp_circle`,
|
||||
- `djangoldp_joboffer`,
|
||||
- `djangoldp_profile`,
|
||||
- `djangoldp_skill`,
|
||||
- `djangoldp_account`,
|
||||
- `djangoldp_notification`,
|
||||
- `djangoldp_conversation`
|
||||
The application bundle is in the `dist` folder, ready to be deployed everywhere as a static file.
|
||||
|
||||
As dependencies, if you don't want them, just remove the `-m packagename`.
|
||||
## Developpers
|
||||
|
||||
`sibserver` is the name of the folder that `sib-manager` will create, choose it wisely.
|
||||
Serve, watch files & rebuild on change with this command:
|
||||
|
||||
In addition to the `startproject` you can add :
|
||||
|
||||
- `--site-url "http://localhost:8000"`
|
||||
- `--production` to use postgresql instead of sqlite
|
||||
- `--db-host`, `--db-name`, `--db-user` and `--db-pass` are used to configure the database (mandatory with `--production`)
|
||||
- `--smtp-host`, `--smtp-user` and `--smtp-pass` are used to configure the SMTP (optional)
|
||||
|
||||
#### `sibserver` configuration
|
||||
|
||||
You'll have to change some settings on the `sibserver` files.
|
||||
|
||||
- Add your server name to `ALLOWED_HOSTS`
|
||||
- In `settings.py`, add your hostname on `ALLOWED_HOSTS`, eg:
|
||||
```
|
||||
ALLOWED_HOSTS = ['api.myserver.com', 'localhost']
|
||||
```
|
||||
- Around line `96-97` of `settings.py` set your `PROSODY_HTTP_URL`, `JABBER_DEFAULT_HOST`, eg:
|
||||
```
|
||||
PROSODY_HTTP_URL = 'https://jabber.happy-dev.fr'
|
||||
JABBER_DEFAULT_HOST = 'happy-dev.fr'
|
||||
```
|
||||
|
||||
#### `sib-manager` launching
|
||||
|
||||
On the first `sibserver` folder
|
||||
|
||||
```
|
||||
$ ./manage.py runserver
|
||||
```
|
||||
|
||||
#### Create a Client ID for Prosody & Client
|
||||
|
||||
- Go to `localhost:8000/admin/`
|
||||
- Login with previously created account.
|
||||
- If needed you can create another admin account with `./manage.py createsuperadmin`
|
||||
- Add a `Clients` on `OpenID Connect Provider` section
|
||||
- Name it as you wish
|
||||
- `Client type`: `Public`
|
||||
- `Response types`: `id_token token (Implicit Flow)`
|
||||
- `Redirect URIs`:
|
||||
```
|
||||
http://localhost:3000
|
||||
http://127.0.0.1:3000
|
||||
http://0.0.0.0:3000
|
||||
http://localhost:8000
|
||||
https://myserver.com
|
||||
```
|
||||
- Keep the `6-digits` newly create `Client ID` somewhere
|
||||
|
||||
#### Then, you'll have to install the client.
|
||||
|
||||
#### Clone this repository
|
||||
|
||||
```
|
||||
# With SSH
|
||||
$ git clone git@git.happy-dev.fr:startinblox/applications/sib-app.git
|
||||
|
||||
# Or with HTTPS
|
||||
$ git clone https://git.happy-dev.fr/startinblox/applications/sib-app.git
|
||||
```
|
||||
|
||||
#### Install dependencies
|
||||
|
||||
```
|
||||
$ cd sib-app
|
||||
$ npm install
|
||||
```
|
||||
|
||||
#### Configure `config.json`
|
||||
|
||||
On the newly created `./src/config.json` change the `dev` configuration like this:
|
||||
```
|
||||
"dev": {
|
||||
"sdn": "http://api.myserver.com", # Or localhost:8000
|
||||
"cdn": "https://cdn.happy-dev.fr",
|
||||
"xmpp": "https://prosody.myserver.com/http-bind/",
|
||||
"client_id": "000000" # <- Here goes your previously created Client ID
|
||||
},
|
||||
```
|
||||
|
||||
#### That's all! Now let's run it!
|
||||
|
||||
```
|
||||
# For dev
|
||||
$ make watch
|
||||
$ npm run serve
|
||||
|
||||
# Or for prod
|
||||
$ make build
|
||||
# Then publish the www folder
|
||||
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
Deployment will need a registered RSA Key on production servers.
|
||||
|
||||
### On Alpha
|
||||
|
||||
```
|
||||
$ make syncprod
|
||||
```
|
||||
|
||||
### On Staging
|
||||
|
||||
```
|
||||
$ make sync
|
||||
```bash
|
||||
npm run watch
|
||||
```
|
||||
|
||||
## Built With
|
||||
|
||||
* [Sib-Core](https://git.happy-dev.fr/startinblox/framework/sib-core/) - An awesome new framework!
|
||||
|
||||
### Architecture
|
||||
|
||||
Some general schema of the existing StartinBlox applications architecture can be found [here](https://docs.google.com/presentation/d/1iCRGaJpFvZjhjIUnpsn6lRTJJ31ES6n94BNkJygzUwM/edit?usp=sharing).
|
||||
|
||||
<!---
|
||||
## Contributing
|
||||
|
||||
@ -178,4 +85,4 @@ We may add a `LICENSE.md`
|
||||
* Maybe some thanks too
|
||||
* Inspiration
|
||||
* etc
|
||||
--->
|
||||
--->
|
||||
|
13
config.sample.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"xmpp": "https://jabber.happy-dev.fr/http-bind/",
|
||||
"authority": "http://localhost:8000/",
|
||||
"endpoints": {
|
||||
"businessproviders": "http://localhost:8000/businessproviders/",
|
||||
"circles": "http://localhost:8000/circles/",
|
||||
"groups": "http://localhost:8000/groups/",
|
||||
"joboffers": "http://localhost:8000/job-offers/",
|
||||
"projects": "http://localhost:8000/projects/",
|
||||
"skills": "http://localhost:8000/skills/",
|
||||
"users": "http://localhost:8000/users/"
|
||||
}
|
||||
}
|
1
gitlabci.pub
Normal file
@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEw23THoFtbG25dkre20Zx03wTyGtmEiUTANGekdCmCymie9/oGgpwIfsqR3VysaUZqO/ObS8le//mVtQJhkKi4= deploy key
|
@ -1 +0,0 @@
|
||||
node_modules/normalize.css/normalize.css
|
2416
package-lock.json
generated
30
package.json
@ -3,18 +3,28 @@
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"serve": "node server.js",
|
||||
"postinstall": "node postinstall.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.4.4",
|
||||
"@babel/cli": "^7.4.4",
|
||||
"node-sass": "^4.12.0",
|
||||
"pug-cli": "^1.0.0-alpha6",
|
||||
"express": "^4.16.4"
|
||||
"build": "run-p copy:* build:*",
|
||||
"build:css": "node-sass src/styles/index.scss -o dist/styles/",
|
||||
"build:js": "babel 'src/scripts/*.js' -o dist/scripts/index.js",
|
||||
"build:html": "pug src/index.pug -o dist/ --obj config.json",
|
||||
"copy:font": "copyfiles -f src/fonts/* dist/fonts",
|
||||
"copy:image": "copyfiles -f src/images/* dist/images",
|
||||
"serve": "serve -l 3000 dist/",
|
||||
"watch": "run-p copy:* watch:* serve",
|
||||
"watch:css": "npm run build:css && npm run build:css -- -w",
|
||||
"watch:js": "babel --watch 'src/scripts/*.js' -o dist/scripts/index.js",
|
||||
"watch:pug": "pug --watch src/index.pug -o dist/ --obj config.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/cli": "^7.7.0",
|
||||
"@babel/core": "^7.7.0",
|
||||
"copyfiles": "^2.1.1",
|
||||
"include-media": "^1.4.9",
|
||||
"normalize.css": "^8.0.1"
|
||||
"node-sass": "^4.13.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pug": "^2.0.4",
|
||||
"pug-cli": "^1.0.0-alpha6",
|
||||
"serve": "^11.2.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const { exec } = require('child_process');
|
||||
|
||||
if (!fs.existsSync('src/config.json')) {
|
||||
const cmd = `rsync -ru src/config.sample.json src/config.json`;
|
||||
console.log(cmd);
|
||||
exec(cmd);
|
||||
}
|
11
server.js
@ -1,11 +0,0 @@
|
||||
const port = 3000;
|
||||
const distPath = 'www';
|
||||
|
||||
// express server
|
||||
const { join } = require('path');
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
app
|
||||
.use(express.static(distPath))
|
||||
.get(/^[^.]*$/, (req, rep) => rep.sendFile(join(__dirname, distPath, '/index.html')))
|
||||
.listen(port);
|
@ -1,66 +0,0 @@
|
||||
{
|
||||
"dev": {
|
||||
"cdn": "https://cdn.happy-dev.fr",
|
||||
"xmpp": "https://jabber.happy-dev.fr/http-bind/",
|
||||
"authority": "http://127.0.0.1:8000/openid/",
|
||||
"clientName": "SIB App",
|
||||
"endpoints": {
|
||||
"businessproviders": "http://127.0.0.1:8000/businessproviders/",
|
||||
"circles": "http://127.0.0.1:8000/circles/",
|
||||
"groups": "http://127.0.0.1:8000/groups/",
|
||||
"joboffers": "http://127.0.0.1:8000/job-offers/",
|
||||
"projects": "http://127.0.0.1:8000/projects/",
|
||||
"skills": "http://127.0.0.1:8000/skills/",
|
||||
"users": "http://127.0.0.1:8000/users/"
|
||||
}
|
||||
},
|
||||
|
||||
"alpha": {
|
||||
"cdn": "https://cdn.happy-dev.fr",
|
||||
"xmpp": "https://jabber.happy-dev.fr/http-bind/",
|
||||
"authority": "https://api.alpha.happy-dev.fr/openid/",
|
||||
"clientName": "SIB App",
|
||||
"endpoints": {
|
||||
"businessproviders": "https://api.alpha.happy-dev.fr/businessproviders/",
|
||||
"circles": "https://api.alpha.happy-dev.fr/circles/",
|
||||
"groups": "https://api.alpha.happy-dev.fr/groups/",
|
||||
"joboffers": "https://api.alpha.happy-dev.fr/job-offers/",
|
||||
"projects": "https://api.alpha.happy-dev.fr/projects/",
|
||||
"skills": "https://api.alpha.happy-dev.fr/skills/",
|
||||
"users": "https://api.alpha.happy-dev.fr/users/"
|
||||
}
|
||||
},
|
||||
|
||||
"paris": {
|
||||
"sdn": "https://api.test-paris.happy-dev.fr",
|
||||
"cdn": "https://cdn.happy-dev.fr",
|
||||
"xmpp": "https://jabber.happy-dev.fr/http-bind/",
|
||||
"authority": "https://api.test-paris.happy-dev.fr/openid/",
|
||||
"clientName": "SIB App",
|
||||
"endpoints": {
|
||||
"businessproviders": "https://api.test-paris.happy-dev.fr/businessproviders/",
|
||||
"circles": "https://api.test-paris.happy-dev.fr/circles/",
|
||||
"groups": "https://api.test-paris.happy-dev.fr/groups/",
|
||||
"joboffers": "https://api.test-paris.happy-dev.fr/job-offers/",
|
||||
"projects": "https://api.test-paris.happy-dev.fr/projects/",
|
||||
"skills": "https://api.test-paris.happy-dev.fr/skills/",
|
||||
"users": "https://api.test-paris.happy-dev.fr/users/"
|
||||
}
|
||||
},
|
||||
|
||||
"nantes": {
|
||||
"cdn": "https://cdn.happy-dev.fr",
|
||||
"xmpp": "https://jabber.happy-dev.fr/http-bind/",
|
||||
"authority": "https://api.test-nantes.happy-dev.fr/openid/",
|
||||
"clientName": "SIB App",
|
||||
"endpoints": {
|
||||
"businessproviders": "https://api.test-nantes.happy-dev.fr/businessproviders/",
|
||||
"circles": "https://api.test-nantes.happy-dev.fr/circles/",
|
||||
"groups": "https://api.test-nantes.happy-dev.fr/groups/",
|
||||
"joboffers": "https://api.test-nantes.happy-dev.fr/job-offers/",
|
||||
"projects": "https://api.test-nantes.happy-dev.fr/projects/",
|
||||
"skills": "https://api.test-nantes.happy-dev.fr/skills/",
|
||||
"users": "https://api.test-nantes.happy-dev.fr/users/"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
|
||||
{
|
||||
"inbox": "http://happy-dev.fr/owl/#inbox",
|
||||
"object": "http://happy-dev.fr/owl/#object",
|
||||
"author": "http://happy-dev.fr/owl/#author",
|
||||
"account": "http://happy-dev.fr/owl/#account",
|
||||
"jabberID": "foaf:jabberID",
|
||||
"firstName": "http://happy-dev.fr/owl/#first_name",
|
||||
"lastName": "http://happy-dev.fr/owl/#last_name"
|
||||
}
|
@ -25,4 +25,12 @@ script(type="module" src="https://unpkg.com/@startinblox/component-notifications
|
||||
|
||||
//- Context - Fix for LDFlex
|
||||
script(data-default-context, type="application/ld+json")
|
||||
include context.jsonld
|
||||
| {
|
||||
| "inbox": "http://happy-dev.fr/owl/#inbox",
|
||||
| "object": "http://happy-dev.fr/owl/#object",
|
||||
| "author": "http://happy-dev.fr/owl/#author",
|
||||
| "account": "http://happy-dev.fr/owl/#account",
|
||||
| "jabberID": "foaf:jabberID",
|
||||
| "firstName": "http://happy-dev.fr/owl/#first_name",
|
||||
| "lastName": "http://happy-dev.fr/owl/#last_name"
|
||||
| }
|
||||
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 559 B After Width: | Height: | Size: 559 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 583 B After Width: | Height: | Size: 583 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
@ -19,4 +19,4 @@ div#viewport {
|
||||
@import 'layout/project-profile/index';
|
||||
@import 'layout/circle/index';
|
||||
@import 'layout/user/index';
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteRule \. - [L]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule . /index.html [L]
|
||||
</IfModule>
|