commit
e790585c3a
86 changed files with 5587 additions and 0 deletions
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
# Browsers that we support |
||||
# see: https://github.com/browserslist/browserslist#readme |
||||
|
||||
>= 1% |
||||
last 1 major version |
||||
not dead |
||||
Chrome >= 45 |
||||
Firefox >= 38 |
||||
Edge >= 12 |
||||
Explorer >= 10 |
||||
iOS >= 9 |
||||
Safari >= 9 |
||||
Android >= 4.4 |
||||
Opera >= 30 |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
# http://editorconfig.org |
||||
|
||||
root = true |
||||
|
||||
[*] |
||||
charset = utf-8 |
||||
end_of_line = lf |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
||||
|
||||
[*.{py,rst,ini}] |
||||
indent_style = space |
||||
indent_size = 4 |
||||
|
||||
[*.py] |
||||
line_length = 80 |
||||
known_first_party = gvot |
||||
multi_line_output = 3 |
||||
default_section = THIRDPARTY |
||||
|
||||
[*.{html,css,scss,js,json,yml}] |
||||
indent_style = space |
||||
indent_size = 2 |
||||
|
||||
[*.md] |
||||
trim_trailing_whitespace = false |
||||
|
||||
[Makefile] |
||||
indent_style = tab |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
{ |
||||
"root": true, |
||||
"parser": "babel-eslint", |
||||
"extends": [ |
||||
"xo/esnext", |
||||
"xo/browser" |
||||
], |
||||
"rules": { |
||||
"capitalized-comments": "off", |
||||
"indent": [ |
||||
"error", |
||||
2, |
||||
{ |
||||
"SwitchCase": 1 |
||||
} |
||||
], |
||||
"max-params": [ |
||||
"warn", |
||||
5 |
||||
], |
||||
"multiline-ternary": [ |
||||
"error", |
||||
"always-multiline" |
||||
], |
||||
"new-cap": "off", |
||||
"object-curly-spacing": [ |
||||
"error", |
||||
"always" |
||||
], |
||||
"prefer-destructuring": "off" |
||||
} |
||||
} |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
gvot/static/** -diff |
||||
assets/img/** -diff |
||||
assets/fonts/** -diff |
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
# Editors |
||||
*~ |
||||
*.sw[po] |
||||
|
||||
# Python |
||||
*.py[cod] |
||||
__pycache__ |
||||
|
||||
# Virtual environment |
||||
.env |
||||
venv |
||||
|
||||
# Logs |
||||
logs |
||||
*.log |
||||
pip-log.txt |
||||
|
||||
# Unit test / coverage reports |
||||
.coverage |
||||
.tox |
||||
nosetests.xml |
||||
htmlcov |
||||
|
||||
# Translations |
||||
*.mo |
||||
*.pot |
||||
|
||||
# NPM |
||||
node_modules/ |
||||
|
||||
# Databases |
||||
sqlite.db |
||||
|
||||
# Local configuration |
||||
config.env |
||||
|
||||
# Local overrides and variable content |
||||
local/ |
||||
var/ |
||||
|
||||
# Asset builds hidden in developp branch |
||||
gvot/static/ |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
{ |
||||
"extends": [ |
||||
"stylelint-config-twbs-bootstrap/scss" |
||||
], |
||||
"rules": { |
||||
"value-list-comma-newline-after": "always-multi-line", |
||||
"value-list-comma-newline-before": "never-multi-line", |
||||
"value-list-comma-space-after": "always-single-line", |
||||
"scss/at-function-named-arguments": null, |
||||
"scss/dollar-variable-default": null |
||||
} |
||||
} |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
# Changelog |
||||
All notable changes to GvoT will be documented in this file. |
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/) |
||||
and this project adheres to [Semantic Versioning](http://semver.org/). |
||||
|
||||
## [Unreleased] |
||||
### Added |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
This software is developped by Cliss XXI. |
@ -0,0 +1,162 @@
@@ -0,0 +1,162 @@
|
||||
# -*- mode: makefile-gmake -*-
|
||||
## Définition des variables
|
||||
# Le nom de l'exécutable Python à utiliser ou son chemin absolu
|
||||
# (ex. : python ou python3).
|
||||
PYTHON_EXE := python3 |
||||
# S'il faut utiliser un environnement virtuel (y ou n).
|
||||
USE_VENV := y |
||||
# Configuration de l'environnement virtuel.
|
||||
VENV_DIR := venv |
||||
VENV_OPT := --system-site-packages |
||||
|
||||
# Définis les chemins et options des exécutables.
|
||||
PYTHON_EXE_BASENAME := $(shell basename $(PYTHON_EXE)) |
||||
VENV_PYTHON := --python=$(PYTHON_EXE_BASENAME) |
||||
ifeq ($(USE_VENV), y) |
||||
PYTHON := $(VENV_DIR)/bin/$(PYTHON_EXE_BASENAME) |
||||
PIP := $(VENV_DIR)/bin/pip |
||||
else |
||||
PYTHON := $(shell which $(PYTHON_EXE)) |
||||
PIP := $(shell which pip) |
||||
endif |
||||
|
||||
# Détermine si black est présent.
|
||||
USE_BLACK := $(shell $(PYTHON) -c 'import black; print("1")' 2>/dev/null) |
||||
|
||||
# Détermine s'il faut charger le fichier de configuration.
|
||||
ifneq ($(READ_CONFIG_FILE), 0) |
||||
READ_CONFIG_FILE := 1 |
||||
else |
||||
READ_CONFIG_FILE := 0 |
||||
endif |
||||
|
||||
# Détermine l'environnement à utiliser.
|
||||
DEFAULT_ENV := production |
||||
ifndef ENV |
||||
ifeq ($(READ_CONFIG_FILE), 1) |
||||
# Commence par chercher la dernière valeur de DJANGO_SETTINGS_MODULE, |
||||
# puis de ENV s'il n'y en a pas, ou utilise l'environnement par défaut. |
||||
ENV = $(shell \
|
||||
sed -n -e '/^DJANGO_SETTINGS_MODULE/s/[^.]*\.settings\.\([^.]*\)/\1/p' \
|
||||
-e '/^ENV/s/[^=]*=\(.*\)/\1/p' config.env 2> /dev/null \
|
||||
| tail -n 1 | grep -Ee '^..*' || echo "$(DEFAULT_ENV)") |
||||
else |
||||
ifdef DJANGO_SETTINGS_MODULE |
||||
ENV = $(shell echo $(DJANGO_SETTINGS_MODULE) | cut -d. -f3) |
||||
else |
||||
ENV := $(DEFAULT_ENV) |
||||
endif # ifdef DJANGO_SETTINGS_MODULE |
||||
endif # ifeq READ_CONFIG_FILE |
||||
endif # ifndef ENV
|
||||
|
||||
# Définis EDITOR pour l'édition interactive.
|
||||
ifndef EDITOR |
||||
ifdef VISUAL |
||||
EDITOR := $(VISUAL) |
||||
else |
||||
EDITOR := vi |
||||
endif |
||||
endif |
||||
|
||||
# Définition des cibles -------------------------------------------------------
|
||||
|
||||
.PHONY: clean-pyc clean-build clean-static clear-venv help check check-config |
||||
.DEFAULT_GOAL := help |
||||
|
||||
# Commentaire d'une cible : #-> interne ##-> aide production+dev ###-> aide dev
|
||||
help: ## affiche cette aide
|
||||
ifeq ($(ENV), production) |
||||
@perl -nle'print $& if m{^[a-zA-Z_-]+:[^#]*?## .*$$}' $(MAKEFILE_LIST) \
|
||||
| sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' |
||||
else |
||||
@perl -nle'print $& if m{^[a-zA-Z_-]+:[^#]*?###? .*$$}' $(MAKEFILE_LIST) \
|
||||
| sort | awk 'BEGIN {FS = ":.*?###? "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' |
||||
endif |
||||
|
||||
clean: clean-build clean-pyc clean-static ## nettoie tous les fichiers temporaires
|
||||
|
||||
clean-build: ### nettoie les fichiers de construction du paquet
|
||||
rm -rf build/ |
||||
rm -rf dist/ |
||||
rm -rf *.egg-info |
||||
|
||||
clean-pyc: ### nettoie les fichiers temporaires python
|
||||
find gvot/ \
|
||||
\( -name '*.pyc' -o -name '*.pyo' -o -name '*~' \) -exec rm -f {} + |
||||
|
||||
clean-static: ### nettoie les fichiers "static" collectés
|
||||
rm -rf var/static |
||||
|
||||
init: create-venv config.env update ## initialise l'environnement et l'application
|
||||
|
||||
config.env: |
||||
ifeq ($(READ_CONFIG_FILE), 1) |
||||
cp config.env.example config.env |
||||
chmod go-rwx config.env |
||||
$(EDITOR) config.env |
||||
endif |
||||
|
||||
update: check-config install-deps migrate static ## mets à jour l'application et ses dépendances
|
||||
touch gvot/wsgi.py |
||||
|
||||
check: check-config ## vérifie la configuration de l'instance
|
||||
$(PYTHON) manage.py check |
||||
|
||||
check-config: |
||||
@find . -maxdepth 1 -name config.env -perm /o+rwx -exec false {} + || \
|
||||
{ echo "\033[31mErreur :\033[0m les permissions de config.env ne sont pas bonnes, \
|
||||
vous devriez au moins faire : chmod o-rwx config.env"; false; }
|
||||
|
||||
install-deps: ## installe les dépendances de l'application
|
||||
$(PIP) install --upgrade --requirement requirements/$(ENV).txt |
||||
|
||||
migrate: ## mets à jour le schéma de la base de données
|
||||
$(PYTHON) manage.py migrate |
||||
|
||||
static: ## collecte les fichiers statiques
|
||||
ifeq ($(ENV), production) |
||||
@echo "Collecte des fichiers statiques..." |
||||
$(PYTHON) manage.py collectstatic --no-input --verbosity 0 |
||||
endif |
||||
|
||||
## Cibles liées à l'environnement virtuel
|
||||
|
||||
create-venv: $(PYTHON) |
||||
|
||||
$(PYTHON): |
||||
ifeq ($(USE_VENV), y) |
||||
virtualenv $(VENV_OPT) $(VENV_PYTHON) $(VENV_DIR) |
||||
else |
||||
@echo "\033[31mErreur !\033[0m Impossible de trouver l'exécutable Python $(PYTHON)" |
||||
@exit 1 |
||||
endif |
||||
|
||||
clear-venv: ## supprime l'environnement virtuel
|
||||
-rm -rf $(VENV_DIR) |
||||
|
||||
## Cibles pour le développement
|
||||
|
||||
serve: ### démarre un serveur local pour l'application
|
||||
$(PYTHON) manage.py runserver |
||||
|
||||
test: ### lance les tests de l'application
|
||||
$(PYTHON) -m pytest --cov --cov-report=term:skip-covered |
||||
|
||||
cov: test ### vérifie la couverture de code
|
||||
$(PYTHON) -m coverage html |
||||
@echo open htmlcov/index.html |
||||
|
||||
lint: ### vérifie la syntaxe et le code python
|
||||
@$(PYTHON) -m flake8 gvot \
|
||||
|| echo "\033[31m[flake8]\033[0m Veuillez corriger les erreurs ci-dessus." |
||||
@$(PYTHON) -m isort --check --recursive gvot \
|
||||
|| echo "\033[31m[isort]\033[0m Veuillez corriger l'ordre des imports avec : make fix-lint" |
||||
ifdef USE_BLACK |
||||
@$(PYTHON) -m black --check gvot |
||||
endif |
||||
|
||||
fix-lint: ### corrige la syntaxe et ordonne les imports python
|
||||
$(PYTHON) -m isort --recursive gvot |
||||
ifdef USE_BLACK |
||||
$(PYTHON) -m black gvot |
||||
endif |
@ -0,0 +1,258 @@
@@ -0,0 +1,258 @@
|
||||
# GvoT |
||||
|
||||
Logiciel de votation |
||||
|
||||
**Table of content** |
||||
|
||||
- [Give a try](#give-a-try) |
||||
- [Installation](#installation) |
||||
- [Deployment](#deployment) |
||||
- [Structure](#structure) |
||||
- [Development](#development) |
||||
|
||||
## Give a try |
||||
|
||||
On a Debian-based host - running at least Debian Stretch: |
||||
|
||||
``` |
||||
$ sudo apt install python3 virtualenv git make |
||||
$ git clone https://forge.cliss21.org/cliss21/gvot |
||||
$ cd gvot/ |
||||
$ make init |
||||
|
||||
A configuration will be created interactively; uncomment |
||||
ENV=development |
||||
|
||||
$ make test # optional |
||||
$ make serve |
||||
``` |
||||
|
||||
Then visit [http://127.0.0.1:8000/](http://127.0.0.1:8000/) in your web browser. |
||||
|
||||
## Installation |
||||
### Requirements |
||||
|
||||
On a Debian-based host - running at least Debian Stretch, you will need the |
||||
following packages: |
||||
- python3 |
||||
- virtualenv |
||||
- make |
||||
- git (recommended for getting the source) |
||||
- python3-mysqldb (optional, in case of a MySQL / MariaDB database) |
||||
- python3-psycopg2 (optional, in case of a PostgreSQL database) |
||||
|
||||
### Quick start |
||||
|
||||
It assumes that you already have the application source code locally - the best |
||||
way is by cloning this repository - and that you are in this folder. |
||||
|
||||
1. Define your local configuration in a file named `config.env`, which can be |
||||
copied from `config.env.example` and edited to suits your needs. |
||||
|
||||
Depending on your environment, you will have to create your database and the |
||||
user at first. |
||||
|
||||
2. Run `make init`. |
||||
|
||||
Note that if there is no `config.env` file, it will be created interactively. |
||||
|
||||
That's it! Your environment is now initialized with the application installed. |
||||
To update it, once the source code is checked out, simply run `make update`. |
||||
|
||||
You can also check that your application is well configured by running |
||||
`make check`. |
||||
|
||||
### Manual installation |
||||
|
||||
If you don't want to use the `Makefile` facilities, here is what is done behind the scene. |
||||
|
||||
It assumes that you have downloaded the last release of GvoT, |
||||
extracted it and that you moved to that folder. |
||||
|
||||
1. Start by creating a new virtual environment under `./venv` and activate it: |
||||
|
||||
$ virtualenv --system-site-packages ./venv |
||||
$ source ./venv/bin/activate |
||||
|
||||
2. Install the required Python packages depending on your environment: |
||||
|
||||
$ pip install -r requirements/production.txt |
||||
... or ... |
||||
$ pip install -r requirements/development.txt |
||||
|
||||
3. Configure the application by setting the proper environment variables |
||||
depending on your environment. You can use the `config.env.example` which |
||||
give you the main variables with example values. |
||||
|
||||
$ cp config.env.example config.env |
||||
$ nano config.env |
||||
$ chmod go-rwx config.env |
||||
|
||||
Note that this `./config.env` file will be loaded by default when the |
||||
application starts. If you don't want that, just move this file away or set |
||||
the `READ_CONFIG_FILE` environment variable to `0`. |
||||
|
||||
4. Create the database tables - it assumes that you have created the database |
||||
and set the proper configuration to use it: |
||||
|
||||
$ ./manage.py migrate |
||||
|
||||
That's it! You should now be able to start the Django development server to |
||||
check that everything is working fine with: |
||||
|
||||
$ ./manage.py runserver |
||||
|
||||
## Deployment |
||||
|
||||
Here is an example deployment using NGINX - as the Web server - and uWSGI - as |
||||
the application server. |
||||
|
||||
The uWSGI configuration doesn't require a special configuration, except that we |
||||
are using Python 3 and a virtual environment. Note that if you serve the |
||||
application on a sub-location, you will have to add `route-run = fixpathinfo:` |
||||
to your uWSGI configuration (from |
||||
[v2.0.11](https://uwsgi-docs.readthedocs.io/en/latest/Changelog-2.0.11.html#fixpathinfo-routing-action)). |
||||
|
||||
In the `server` block of your NGINX configuration, add the following blocks and |
||||
set the path to your application instance and to the uWSGI socket: |
||||
|
||||
``` |
||||
location / { |
||||
include uwsgi_params; |
||||
uwsgi_pass unix:<uwsgi_socket_path>; |
||||
} |
||||
location /media { |
||||
alias <app_instance_path>/var/media; |
||||
} |
||||
location /static { |
||||
alias <app_instance_path>/var/static; |
||||
# Optional: don't log access to assets |
||||
access_log off; |
||||
} |
||||
location = /favicon.ico { |
||||
alias <app_instance_path>/var/static/favicon/favicon.ico; |
||||
# Optional: don't log access to the favicon |
||||
access_log off; |
||||
} |
||||
``` |
||||
|
||||
## Structure |
||||
### Overview |
||||
|
||||
All the application files - e.g. Django code including settings, templates and |
||||
statics - are located into `gvot/`. |
||||
|
||||
Two environments are defined - either for requirements and settings: |
||||
- `development`: for local application development and testing. It uses a |
||||
SQLite3 database and enable debugging by default, add some useful settings |
||||
and applications for development purpose - i.e. the `django-debug-toolbar`. |
||||
- `production`: for production. It checks that configuration is set and |
||||
correct, try to optimize performances and enforce some settings - i.e. HTTPS |
||||
related ones. |
||||
|
||||
### Local changes |
||||
|
||||
You can override and extend statics and templates locally. This can be useful |
||||
if you have to change the logo for a specific instance for example. For that, |
||||
just put your files under the `local/static/` and `local/templates/` folders. |
||||
|
||||
Regarding the statics, do not forget to collect them after that. Note also that |
||||
the `local/` folder is ignored by *git*. |
||||
|
||||
### Variable content |
||||
|
||||
All the variable content - e.g. user-uploaded media, collected statics - are |
||||
stored inside the `var/` folder. It is also ignored by *git* as it's specific |
||||
to each application installation. |
||||
|
||||
So, you will have to configure your Web server to serve the `var/media/` and |
||||
`var/static/` folders, which should point to `/media/` and `/static/`, |
||||
respectively. |
||||
|
||||
## Development |
||||
|
||||
The easiest way to deploy a development environment is by using the `Makefile`. |
||||
|
||||
Before running `make init`, ensure that you have either set `ENV=development` |
||||
in the `config.env` file or have this environment variable. Note that you can |
||||
still change this variable later and run `make init` again. |
||||
|
||||
There is some additional rules when developing, which are mainly wrappers for |
||||
`manage.py`. You can list all of them by running `make help`. Here are the main ones: |
||||
- `make serve`: run a development server |
||||
- `make test`: test the whole application |
||||
- `make lint`: check the Python code syntax |
||||
|
||||
### Assets |
||||
|
||||
The assets - e.g. CSS, JavaScript, images, fonts - are generated using a |
||||
[Gulp](https://gulpjs.com/)-powered build system with these features: |
||||
- SCSS compilation and prefixing |
||||
- JavaScript module bundling with webpack |
||||
- Styleguide and components preview |
||||
- Built-in BrowserSync server |
||||
- Compression for production builds |
||||
|
||||
The source files live in `assets/`, and the styleguide in `styleguide/`. |
||||
|
||||
#### Requirements |
||||
|
||||
You will need to have [npm](https://www.npmjs.com/) installed on your system. |
||||
If you are running Debian, do not rely on the npm package which is either |
||||
outdated or removed - starting from Debian Stretch. Instead, here is a way |
||||
to install the last version as a regular user: |
||||
|
||||
1. Ensure that you have the following Debian packages installed, from at least |
||||
`stretch-backports`: |
||||
- nodejs |
||||
- node-rimraf |
||||
|
||||
2. Set the npm's installation prefix as an environment variable: |
||||
|
||||
$ export npm_config_prefix=~/.node_modules |
||||
|
||||
3. Retrieve and execute the last npm's installation script: |
||||
|
||||
$ curl -L https://www.npmjs.com/install.sh | sh |
||||
|
||||
4. Add the npm's binary folder to your environment variables: |
||||
|
||||
$ export PATH="${HOME}/.node_modules/bin:${PATH}" |
||||
|
||||
In order to keep those environment variables the next time you will log in, |
||||
you can append the following lines to the end of your `~/.profile` file: |
||||
|
||||
```bash |
||||
if [ -d "${HOME}/.node_modules/bin" ] ; then |
||||
PATH="${HOME}/.node_modules/bin:${PATH}" |
||||
export npm_config_prefix=~/.node_modules |
||||
fi |
||||
``` |
||||
|
||||
5. That's it! You can check that npm is now installed by running the following: |
||||
|
||||
$ npm --version |
||||
|
||||
#### Usage |
||||
|
||||
Start by installing the application dependencies - which are defined in |
||||
`package.json` - by running: `npm install`. |
||||
|
||||
The following tasks are then available: |
||||
- `npm run build`: build all the assets for development and production use, |
||||
and put them in the static folder - e.g `gvot/static`. |
||||
- `npm run styleguide`: run a server with the styleguide and watch for file |
||||
changes. |
||||
- `npm run serve`: run a proxy server to the app - which must already be served on |
||||
`localhost:8000` - with the styleguide on `/styleguide` and watch for file |
||||
changes. |
||||
- `npm run lint`: lint the JavaScript and the SCSS code. |
||||
|
||||
In production, only the static files will be used. It is recommended to commit |
||||
the compiled assets just before a new release only. This will prevent to have a |
||||
growing repository due to the minified files. |
||||
|
||||
## License |
||||
|
||||
GvoT is developed by Cliss XXI and licensed under the |
||||
[AGPLv3+](LICENSE). |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
import $ from 'jquery'; |
||||
|
||||
import './vendor/bootstrap'; |
||||
|
||||
// Export jQuery for external usage
|
||||
window.jQuery = window.$ = $; // eslint-disable-line no-multi-assign
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Main application
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
$(() => { |
||||
$('.no-js').removeClass('no-js'); |
||||
|
||||
// Initialize Popover and Tooltip on the whole page
|
||||
$('[data-toggle="popover"]').popover(); |
||||
$('[data-toggle="tooltip"]').tooltip(); |
||||
}); |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// Bootstrap 4
|
||||
// -----------------------------------------------------------------------------
|
||||
// see: ../../node_modules/bootstrap/js/src/index.js
|
||||
|
||||
// Import all Bootstrap components
|
||||
|
||||
import 'bootstrap'; |
||||
|
||||
// ... or import them individually
|
||||
|
||||
// import 'bootstrap/js/dist/util';
|
||||
// import 'bootstrap/js/dist/alert';
|
||||
// import 'bootstrap/js/dist/button';
|
||||
// import 'bootstrap/js/dist/carousel';
|
||||
// import 'bootstrap/js/dist/collapse';
|
||||
// import 'bootstrap/js/dist/dropdown';
|
||||
// import 'bootstrap/js/dist/modal';
|
||||
// import 'bootstrap/js/dist/popover';
|
||||
// import 'bootstrap/js/dist/scrollspy';
|
||||
// import 'bootstrap/js/dist/tab';
|
||||
// import 'bootstrap/js/dist/toast';
|
||||
// import 'bootstrap/js/dist/tooltip';
|
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
// ----------------------------------------------------------------------------- |
||||
// Bootstrap's configuration for the application |
||||
// ----------------------------------------------------------------------------- |
||||
// see: ../../node_modules/bootstrap/scss/_variables.scss |
||||
|
||||
// Color system |
||||
|
||||
// You can generate a color scheme with: |
||||
// https://palx.jxnblk.com/ |
||||
$blue: #007bff; |
||||
$indigo: #6610f2; |
||||
$purple: #6f42c1; |
||||
$pink: #e83e8c; |
||||
$red: #dc3545; |
||||
$orange: #fd7e14; |
||||
$yellow: #ffc107; |
||||
$green: #28a745; |
||||
$teal: #20c997; |
||||
$cyan: #17a2b8; |
||||
|
||||
// Add 'error' as an alternative to 'danger' since it is used by Django. |
||||
$theme-colors: ( |
||||
"error": $red |
||||
); |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
// ----------------------------------------------------------------------------- |
||||
// Application-wide variables |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
/// Path to fonts and images folders, relative to css/app.css. |
||||
/// @type String |
||||
$font-path: "../fonts"; |
||||
$img-path: "../img"; |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
@charset "utf-8"; |
||||
|
||||
// Configuration and helpers |
||||
@import "abstracts/variables"; |
||||
@import "abstracts/variables-bootstrap"; |
||||
|
||||
// Vendors |
||||
@import "vendor/bootstrap"; |
||||
|
||||
// Base styles |
||||
@import "base/fonts"; |
||||
|
||||
// Layout-related sections |
||||
//@import "layout/header"; |
||||
//@import "layout/footer"; |
||||
|
||||
// Components |
||||
@import "components/forms"; |
||||
|
||||
// Page-specific styles |
||||
//@import "pages/home"; |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
// ----------------------------------------------------------------------------- |
||||
// Font faces declarations |
||||
// ----------------------------------------------------------------------------- |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
// ----------------------------------------------------------------------------- |
||||
// Forms component's extension |
||||
// ----------------------------------------------------------------------------- |
||||
|
||||
// Indicate that a form field is required. |
||||
.required { |
||||
font-size: 90%; |
||||
color: $danger; |
||||
} |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
@charset "utf-8"; |
||||
|
||||
// Configuration and helpers |
||||
@import "abstracts/variables"; |
||||
|
||||
// Fork Awesome |
||||
// ------------ |
||||
// @link https://forkawesome.github.io/ |
||||
|
||||
$fa-font-path: "#{$font-path}/fork-awesome"; |
||||
|
||||
@import "fork-awesome/scss/fork-awesome"; |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
// ---------------------------------------------------------------------------- |
||||
// Bootstrap 4 |
||||
// ---------------------------------------------------------------------------- |
||||
// see: ../../node_modules/bootstrap/scss/bootstrap.scss |
||||
|
||||
/// Import all Bootstrap components |
||||
|
||||
@import "bootstrap/scss/bootstrap"; |
||||
|
||||
/// ... or import them individually |
||||
|
||||
//@import "bootstrap/scss/functions"; |
||||
//@import "bootstrap/scss/variables"; |
||||
//@import "bootstrap/scss/mixins"; |
||||
//@import "bootstrap/scss/root"; |
||||
//@import "bootstrap/scss/reboot"; |
||||
//@import "bootstrap/scss/type"; |
||||
//@import "bootstrap/scss/images"; |
||||
//@import "bootstrap/scss/code"; |
||||
//@import "bootstrap/scss/grid"; |
||||
//@import "bootstrap/scss/tables"; |
||||
//@import "bootstrap/scss/forms"; |
||||
//@import "bootstrap/scss/buttons"; |
||||
//@import "bootstrap/scss/transitions"; |
||||
//@import "bootstrap/scss/dropdown"; |
||||
//@import "bootstrap/scss/button-group"; |
||||
//@import "bootstrap/scss/input-group"; |
||||
//@import "bootstrap/scss/custom-forms"; |
||||
//@import "bootstrap/scss/nav"; |
||||
//@import "bootstrap/scss/navbar"; |
||||
//@import "bootstrap/scss/card"; |
||||
//@import "bootstrap/scss/breadcrumb"; |
||||
//@import "bootstrap/scss/pagination"; |
||||
//@import "bootstrap/scss/badge"; |
||||
//@import "bootstrap/scss/jumbotron"; |
||||
//@import "bootstrap/scss/alert"; |
||||
//@import "bootstrap/scss/progress"; |
||||
//@import "bootstrap/scss/media"; |
||||
//@import "bootstrap/scss/list-group"; |
||||
//@import "bootstrap/scss/close"; |
||||
//@import "bootstrap/scss/toasts"; |
||||
//@import "bootstrap/scss/modal"; |
||||
//@import "bootstrap/scss/tooltip"; |
||||
//@import "bootstrap/scss/popover"; |
||||
//@import "bootstrap/scss/carousel"; |
||||
//@import "bootstrap/scss/spinners"; |
||||
//@import "bootstrap/scss/utilities"; |
||||
//@import "bootstrap/scss/print"; |
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
########################################################### |
||||
# # |
||||
# Edit the following configuration to suits your needs. # |
||||
# # |
||||
########################################################### |
||||
|
||||
############################################################################### |
||||
# MAINS SETTINGS |
||||
############################################################################### |
||||
|
||||
# Environment to use within the application. |
||||
# |
||||
# The environment is used to load the proper settings for your application |
||||
# instance. There is two ways for defining it, with the following precedence: |
||||
# - DJANGO_SETTINGS_MODULE: the Python path to the settings module to use. It |
||||
# allows you to define and use your own settings module. Use it with care! |
||||
# Note: the module name will be used as the environment. |
||||
# - ENV: the environment to use, which is one of 'production' or 'development'. |
||||
# |
||||
# Default is the 'production' environment. |
||||
#ENV=production |
||||
#ENV=development |
||||
|
||||
# The secret key used to provide cryptographic signing. |
||||
# |
||||
# It should be set to a unique, unpredictable value. On a GNU/Linux system, you |
||||
# could generate a new one with: |
||||
# |
||||
# $ head -c50 /dev/urandom | base64 |
||||
# |
||||
# /!\ Required in production. |
||||
#DJANGO_SECRET_KEY=CHANGEME!!! |
||||
|
||||
# A coma-separated string representing the host/domain names that this |
||||
# application instance can serve. |
||||
# |
||||
# /!\ Required in production. |
||||
#DJANGO_ALLOWED_HOSTS=example.org, |
||||
|
||||
############################################################################### |
||||
# DATABASE SETTINGS |
||||
############################################################################### |
||||
|
||||
# Database configuration, as an URI. |
||||
# |
||||
# In production, the recommended database backend for better performances is |
||||
# PostgreSQL - or MySQL if you prefer. |
||||
# |
||||
# Default is a SQLite database in development only. |
||||
# |
||||
# /!\ Required in production. |
||||
#DJANGO_DATABASE_URL=postgres://user:password@127.0.0.1:5432/gvot |
||||
#DJANGO_DATABASE_URL=mysql://user:password@127.0.0.1:3306/gvot |
||||
|
||||
############################################################################### |
||||
# EMAILS SETTINGS |
||||
############################################################################### |
||||
|
||||
# Email configuration for sending messages, as an URI. |
||||
# |
||||
# In production, you should either use a local SMTP server or a relay one. The |
||||
# URI will be in that case of the form: |
||||
# |
||||
# PROTOCOL://[USER:PASSWORD@]HOST[:PORT] |
||||
# |
||||
# PROTOCOL can be smtp, smtp+ssl or smtp+tls. Note that special characters |
||||
# in USER and PASSWORD - e.g. @ - must be escaped. It can be achieve with: |
||||
# |
||||
# $ python3 -c 'from urllib.parse import quote as q;print(q("USER")+":"+q("PASSWORD"))' |
||||
# |
||||
# Default is the local SMTP server in production and the console in development. |
||||
#DJANGO_EMAIL_URL=smtp://localhost:25 |
||||
|
||||
# Default email address to use for various automated correspondence. |
||||
# |
||||
# /!\ Required in production. |
||||
#DEFAULT_FROM_EMAIL=webmaster@example.org |
||||
|
||||
# A comma separated list of all the people who get production error |
||||
# notifications, following rfc2822 format |
||||
#ADMINS='Cliss XXI <francois.poulain@cliss21.org>' |
||||
|
||||
############################################################################### |
||||
# MISC SETTINGS |
||||
############################################################################### |
||||
|
||||
# URL prefix on which the application is served. |
||||
# |
||||
# This is used to generate the static and media URLs, but also links to the |
||||
# application which require an absolute URL. |
||||
# |
||||
# Default is '/', e.g. at the domain root. |
||||
#APP_LOCATION=/ |
||||
|
||||
# Base directory of the app instance, where the local and var folders are |
||||
# located. |
||||
# |
||||
# Default is the current directory. |
||||
#BASE_DIR= |
||||
|
||||
# Turn on/off debug mode. |
||||
# |
||||
# Note that it's always disabled in production. |
||||
#DJANGO_DEBUG=off |
||||
#DJANGO_DEBUG_TOOLBAR=on |
@ -0,0 +1,273 @@
@@ -0,0 +1,273 @@
|
||||
const gulp = require('gulp'); |
||||
const plugins = require('gulp-load-plugins'); |
||||
const merge = require('merge-stream'); |
||||
const sherpa = require('style-sherpa'); |
||||
const named = require('vinyl-named'); |
||||
const webpack = require('webpack'); |
||||
const webpackStream = require('webpack-stream'); |
||||
|
||||
const browser = require('browser-sync').create(); |
||||
|
||||
// Load all Gulp plugins into one variable
|
||||
const $ = plugins({ |
||||
rename: { |
||||
'gulp-touch-fd': 'touch' |
||||
} |
||||
}); |
||||
|
||||
/// Configuration -------------------------------------------------------------
|
||||
|
||||
const CONFIG = { |
||||
// Proxy target of the BrowserSync'server
|
||||
SERVER_PROXY: 'http://127.0.0.1:8000', |
||||
|
||||
// Port on which the BrowserSync'server will listen
|
||||
SERVER_PORT: 8090, |
||||
|
||||
// Paths to other assets which will be copied
|
||||
ASSETS_FILES: [ |
||||
{ |
||||
src: [ |
||||
'assets/**/*', |
||||
'!assets/{img,js,scss}', |
||||
'!assets/{img,js,scss}/**/*' |
||||
], |
||||
dest: '' |
||||
}, |
||||
{ |
||||
// ForkAwesome
|
||||
src: 'node_modules/fork-awesome/fonts/*', |
||||
dest: 'fonts/fork-awesome' |
||||
} |
||||
], |
||||
|
||||
// Paths to images which will be compressed and copied
|
||||
IMAGES_FILES: [ |
||||
'assets/img/**/*' |
||||
], |
||||
|
||||
// Paths to JavaScript entries which will be bundled
|
||||
JS_ENTRIES: [ |
||||
'assets/js/app.js' |
||||
], |
||||
|
||||
// Paths to Sass files which will be compiled
|
||||
SASS_ENTRIES: [ |
||||
'assets/scss/app.scss', |
||||
'assets/scss/fork-awesome.scss' |
||||
], |
||||
|
||||
// Paths to Sass libraries, which can then be loaded with @import
|
||||
SASS_INCLUDE_PATHS: [ |
||||
'node_modules' |
||||
], |
||||
|
||||
// Path to the build output, which will never be cleaned
|
||||
BUILD_PATH: 'gvot/static' |
||||
}; |
||||
|
||||
/// CSS -----------------------------------------------------------------------
|
||||
|
||||
// Compile Sass into CSS.
|
||||
gulp.task('sass', function() { |
||||
return gulp.src(CONFIG.SASS_ENTRIES) |
||||
.pipe($.sourcemaps.init()) |
||||
.pipe($.sass({ |
||||
includePaths: CONFIG.SASS_INCLUDE_PATHS |
||||
}).on('error', $.sass.logError)) |
||||
.pipe($.autoprefixer()) |
||||
.pipe($.sourcemaps.write('.')) |
||||
.pipe(gulp.dest(`${CONFIG.BUILD_PATH}/css`)) |
||||
.pipe($.touch()) |
||||
.pipe(browser.reload({ stream: true })); |
||||
}); |
||||
|
||||
// Lint Sass files.
|
||||
gulp.task('lint:sass', function() { |
||||
return gulp.src('assets/scss/**/*.scss') |
||||
.pipe($.stylelint({ |
||||
failAfterError: true, |
||||
reporters: [ |
||||
{ formatter: 'verbose', console: true } |
||||
] |
||||
})); |
||||
}); |
||||
|
||||
// Compress CSS files.
|
||||
gulp.task('compress:css', function() { |
||||
return gulp.src([ |
||||
`${CONFIG.BUILD_PATH}/css/*.css`, |
||||
`!${CONFIG.BUILD_PATH}/css/*.min.css` |
||||
]) |
||||
.pipe($.cleanCss()) |
||||
.pipe($.rename({ suffix: '.min' })) |
||||
.pipe(gulp.dest(`${CONFIG.BUILD_PATH}/css`)); |
||||
}); |
||||
|
||||
gulp.task('css', |
||||
gulp.series('sass', 'compress:css')); |
||||
|
||||
/// JavaScript ----------------------------------------------------------------
|
||||
|
||||
let webpackConfig = { |
||||
devtool: 'source-map', |
||||
mode: 'development', |
||||
module: { |
||||
rules: [ |
||||
{ |
||||
test: /.js$/, |
||||
use: { |
||||
loader: 'babel-loader', |
||||
options: { |
||||
presets: ['@babel/preset-env'], |
||||
compact: false |
||||
} |
||||
} |
||||
} |
||||
] |
||||
}, |
||||
stats: { |
||||
chunks: false, |
||||
entrypoints: false, |
||||
} |
||||
} |
||||
|
||||
// Bundle JavaScript module.
|
||||
gulp.task('javascript', function() { |
||||
return gulp.src(CONFIG.JS_ENTRIES) |
||||
.pipe(named()) |
||||
.pipe(webpackStream(webpackConfig, webpack)) |
||||
.pipe(gulp.dest(`${CONFIG.BUILD_PATH}/js`)); |
||||
}); |
||||
|
||||
// Lint JavaScript source files.
|
||||
gulp.task('lint:javascript', function() { |
||||
return gulp.src('assets/js/**/*.js') |
||||
.pipe($.eslint()) |
||||
.pipe($.eslint.format()) |
||||
.pipe($.eslint.failAfterError()); |
||||
}); |
||||
|
||||
// Compress JavaScript files.
|
||||
gulp.task('compress:javascript', function() { |
||||
return gulp.src([ |
||||
`${CONFIG.BUILD_PATH}/js/*.js`, |
||||
`!${CONFIG.BUILD_PATH}/js/*.min.js` |
||||
]) |
||||
.pipe($.terser().on('error', e => { console.log(e); })) |
||||
.pipe($.rename({ suffix: '.min' })) |
||||
.pipe(gulp.dest(`${CONFIG.BUILD_PATH}/js`)); |
||||
}); |
||||
|
||||
gulp.task('scripts', |
||||
gulp.series('javascript', 'compress:javascript')); |
||||
|
||||
/// Other assets --------------------------------------------------------------
|
||||
|
||||
// Compress and copy images.
|
||||
gulp.task('images', function() { |
||||
return gulp.src(CONFIG.IMAGES_FILES) |
||||
.pipe($.imagemin({ progressive: true })) |
||||
.pipe(gulp.dest(`${CONFIG.BUILD_PATH}/img`)); |
||||
}); |
||||
|
||||
// Copy other assets files.
|
||||
gulp.task('copy', function() { |
||||
return merge(CONFIG.ASSETS_FILES.map( |
||||
item => gulp.src(item.src) |
||||
.pipe(gulp.dest(`${CONFIG.BUILD_PATH}/${item.dest}`)) |
||||
)); |
||||
}); |
||||
|
||||
/// HTML files ----------------------------------------------------------------
|
||||
|
||||
// Generate a style guide from the Markdown content.
|
||||
gulp.task('styleguide', done => { |
||||
sherpa('styleguide/index.md', { |
||||
output: 'styleguide/index.html', |
||||
template: 'styleguide/template.html' |
||||
}, done); |
||||
}); |
||||
|
||||
/// General tasks -------------------------------------------------------------
|
||||
|
||||
// Build and compress CSS, JavaScript and other assets.
|
||||
gulp.task('build', |
||||
gulp.parallel('css', 'scripts', 'images', 'copy', 'styleguide')); |
||||
|
||||
// Watch for changes to static assets, Sass and JavaScript.
|
||||
gulp.task('watch', function() { |
||||
gulp.watch([].concat.apply([], CONFIG.ASSETS_FILES.map(a => a.src)), |
||||
gulp.series('copy', reload)); |
||||
|
||||
gulp.watch('assets/scss/**/*.scss', |
||||
gulp.series('sass')); |
||||
gulp.watch('assets/js/**/*.js', |
||||
gulp.series('javascript', reload)); |
||||
gulp.watch('assets/img/**/*', |
||||
gulp.series('images', reload)); |
||||
|
||||
gulp.watch(['styleguide/*', '!styleguide/index.html'], |
||||
gulp.series('styleguide', reload)); |
||||
}); |
||||
|
||||
// Run a development server and watch for file changes.
|
||||
gulp.task('serve', |
||||
gulp.series(proxyServer, 'watch')); |
||||
|
||||
// Run a preview server and watch for file changes.
|
||||
gulp.task('serve:styleguide', |
||||
gulp.series(styleguideServer, 'watch')); |
||||
|
||||
// Lint Sass and JavaScript sources.
|
||||
gulp.task('lint', |
||||
gulp.parallel('lint:sass', 'lint:javascript')); |
||||
|
||||
// An alias to the 'build' task.
|
||||
gulp.task('default', |
||||
gulp.parallel('build')); |
||||
|
||||
/// Internal tasks ------------------------------------------------------------
|
||||
|
||||
// Start a server with BrowserSync and proxify the application in.
|
||||
function proxyServer(done) { |
||||
browser.init({ |
||||
proxy: CONFIG.SERVER_PROXY, |
||||
port: CONFIG.SERVER_PORT, |
||||
serveStatic: [ |
||||
{ |
||||
route: '/static', |
||||
dir: CONFIG.BUILD_PATH |
||||
}, |
||||
{ |
||||
route: '/styleguide', |
||||
dir: './styleguide' |
||||
} |
||||
], |
||||
ghostMode: false, |
||||
notify: false |
||||
}); |
||||
done(); |
||||
} |
||||
|
||||
// Start a server with BrowserSync with the styleguide.
|
||||
function styleguideServer(done) { |
||||
browser.init({ |
||||
server: { |
||||
baseDir: './styleguide', |
||||
routes: { |
||||
'/static': CONFIG.BUILD_PATH |
||||
} |
||||
}, |
||||
port: CONFIG.SERVER_PORT, |
||||
ghostMode: false, |
||||
notify: false |
||||
}); |
||||
done(); |
||||
} |
||||
|
||||
// Reload the BrowserSync server.
|
||||
function reload(done) { |
||||
browser.reload(); |
||||
done(); |
||||
} |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
default_app_config = 'gvot.base.apps.BaseConfig' |
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class BaseConfig(AppConfig): |
||||
name = 'gvot.base' |
||||
verbose_name = "Base" |
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
from django.conf import settings |
||||
from django.utils.text import camel_case_to_spaces, slugify |
||||
|
||||
from wagtail.core import blocks |
||||
from wagtail.documents.blocks import DocumentChooserBlock |
||||
from wagtail.images.blocks import ImageChooserBlock |
||||
|
||||
# Mixins |
||||
######## |
||||
|
||||
|
||||
class TemplatedBlock(blocks.StructBlock): |
||||
def get_template(self, *args, **kwargs): |
||||
return "blocks/{}.html".format(slugify(self.name)) |
||||
|
||||
|
||||
class LinkMixin: |
||||
def links_blocklist(): |
||||
return [ |
||||
('page', blocks.PageChooserBlock(target_model='base.SitePage')), |
||||
('document', DocumentChooserBlock()), |
||||
('image', ImageChooserBlock()), |
||||
( |
||||
'lien_externe', |
||||
blocks.URLBlock( |
||||
icon='link', help_text="Lien vers un site externe." |
||||
), |
||||
), |
||||
( |
||||
'ancre', |
||||
blocks.TextBlock( |
||||
icon='fa fa-anchor', |
||||
help_text="Ancre dans la page. Ex : #infos", |
||||
), |
||||
), |
||||
] |
||||
|
||||
def get_context(self, value, parent_context=None): |
||||
context = super().get_context(value, parent_context=parent_context) |
||||
lien = value['lien'] |
||||
context['href'] = None |
||||
try: |
||||
if lien: |
||||
if hasattr(lien[0].value, 'file') and hasattr( |
||||
lien[0].value.file, 'url' |
||||
): |
||||
context['href'] = lien[0].value.file.url |
||||
elif hasattr(lien[0].value, 'url'): |
||||
context['href'] = lien[0].value.url |
||||
else: |
||||
context['href'] = lien[0].value |
||||
except Exception as e: |
||||
if settings.DEBUG: |
||||
raise e |
||||
if not context['href']: |
||||
context['href'] = '#' |
||||
return context |
||||
|
||||
|
||||
# Management |
||||
############ |
||||
|
||||
|
||||
REGISTERED_BLOCKS = {} |
||||
|
||||
|
||||
def register_block(): |
||||
""" |
||||
Macro hygiénique pour conserver une liste des blocs décrits, |
||||
groupés par type. |
||||
""" |
||||
|
||||
class Wrapper: |
||||
def __init__(self, cls, *args, **kwargs): |
||||
self.wrapped = cls(*args, **kwargs) |
||||
title = camel_case_to_spaces(cls.__name__).replace(' ', '_') |
||||
group = cls._meta_class.group |
||||
if group not in REGISTERED_BLOCKS: |
||||
REGISTERED_BLOCKS[group] = [] |
||||
REGISTERED_BLOCKS[group].append((title, cls)) |
||||
|
||||
def __call__(self, *args, **kwargs): |
||||
return self.wrapped |
||||
|
||||
return Wrapper |
||||
|
||||
|
||||
def all_registered(): |
||||
return [ |
||||
(name, bloc()) |
||||
for group in REGISTERED_BLOCKS |
||||
for name, bloc in REGISTERED_BLOCKS[group] |
||||
] |
@ -0,0 +1,107 @@
@@ -0,0 +1,107 @@
|
||||
from wagtail.core import blocks |
||||
from wagtail.embeds.blocks import EmbedBlock |
||||
from wagtail.images.blocks import ImageChooserBlock |
||||
|
||||
from .block_utils import ( |
||||
LinkMixin, |
||||
TemplatedBlock, |
||||
all_registered, |
||||
register_block, |
||||
) |
||||
|
||||
# Contenu texte |
||||
# ^^^^^^^^^^^^^ |
||||
|
||||
|
||||
@register_block() |
||||
class Titre(TemplatedBlock): |
||||
class Meta: |
||||
icon = 'title' |
||||
group = 'Contenu texte' |
||||
|
||||
niveau = blocks.ChoiceBlock( |
||||
default='h2', |
||||
choices=[ |
||||
('h{}'.format(i), 'Titre de niveau {}'.format(i)) |
||||
for i in range(2, 7) |
||||
], |
||||
icon='title', |
||||
) |
||||
texte = blocks.TextBlock(icon='pilcrow') |
||||
|
||||
|
||||
@register_block() |
||||
class Paragraphe(TemplatedBlock): |
||||
class Meta: |
||||
icon = 'pilcrow' |
||||
group = 'Contenu texte' |
||||
|
||||
texte = blocks.RichTextBlock(icon='pilcrow') |
||||
|
||||
|
||||
@register_block() |
||||
class Bouton(LinkMixin, TemplatedBlock): |
||||
class Meta: |
||||
label = "Bouton" |
||||
icon = 'link' |
||||
group = 'Contenu texte' |
||||
|
||||
outline = blocks.BooleanBlock( |
||||
label="Bordures colorées uniquement", required=False, default=False |
||||
) |
||||
|
||||
texte = blocks.TextBlock(icon='pilcrow') |
||||
|
||||
lien = blocks.StreamBlock( |
||||
LinkMixin.links_blocklist(), |
||||
icon='link', |
||||
help_text="Lien associé au bouton ; optionnel", |
||||
required=False, |
||||
max_num=1, |
||||
) |
||||
|
||||
|
||||
# Contenu media |
||||
# ^^^^^^^^^^^^^ |
||||
|
||||
|
||||
@register_block() |
||||
class Image(LinkMixin, TemplatedBlock): |
||||
class Meta: |
||||
icon = 'image' |
||||
group = 'Contenu média' |
||||
|
||||
image = ImageChooserBlock(icon='image') |
||||
|
||||
legende = blocks.RichTextBlock( |
||||
icon='pilcrow', |
||||
label="légende", |
||||
features=['ol', 'ul', 'bold', 'italic', 'link', 'document-link'], |
||||
required=False, |
||||
) |
||||
|
||||
lien = blocks.StreamBlock( |
||||
LinkMixin.links_blocklist(), |
||||
icon='link', |
||||
help_text="Lien associé à l'image ; optionnel", |
||||
required=False, |
||||
max_num=1, |
||||
) |
||||
|
||||
|
||||
@register_block() |
||||
class Embarque(TemplatedBlock): |
||||
class Meta: |
||||
icon = 'media' |
||||
group = 'Contenu média' |
||||
label = 'média embarqué' |
||||
|
||||
media = EmbedBlock(icon='link', help_text='Lien vers le média embarqué.') |
||||
|
||||
|
||||
# Contenu de page |
||||
# ^^^^^^^^^^^^^^^ |
||||
|
||||
|
||||
def main_body_blocklist(): |
||||
return all_registered() |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 2.1.13 on 2019-10-11 15:51 |
||||
|
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
('wagtailcore', '0040_page_draft_title'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='SitePage', |
||||
fields=[ |
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), |
||||
], |
||||
options={ |
||||
'verbose_name': 'page standard', |
||||
'verbose_name_plural': 'pages standard', |
||||
}, |
||||
bases=('wagtailcore.page',), |
||||
), |
||||
] |
@ -0,0 +1,55 @@
@@ -0,0 +1,55 @@
|
||||
# Generated by Django 2.1.13 on 2019-10-11 16:02 |
||||
|
||||
from django.db import migrations |
||||
|
||||
|
||||
def reset_home_page(apps, schema_editor): |
||||
ContentType = apps.get_model('contenttypes.ContentType') |
||||
WagtailPage = apps.get_model('wagtailcore.Page') |
||||
Site = apps.get_model('wagtailcore.Site') |
||||
SitePage = apps.get_model('base.SitePage') |
||||
|
||||
# Create page content type |
||||
sitepage_content_type, created = ContentType.objects.get_or_create( |
||||
model='sitepage', |
||||
app_label='base' |
||||
) |
||||
|
||||
# Create home page |
||||
homepage = SitePage.objects.create( |
||||
title="Bienvenue sur votre nouveau site Wagtail !", |
||||
slug='homepage', |
||||
content_type=sitepage_content_type, |
||||
path='00010002', |
||||
depth=2, |
||||
numchild=0, |
||||
url_path='/', |
||||
) |
||||
|
||||
# Update default site |
||||
site = Site.objects.get(is_default_site=True) |
||||
old_root = site.root_page |
||||
site.root_page_id=homepage.id |
||||
site.save() |
||||
|
||||
# Delete unwanted root |
||||
wagtailpage_content_type = ContentType.objects.get( |
||||
model='page', |
||||
app_label='wagtailcore' |
||||
) |
||||
if old_root.content_type == wagtailpage_content_type: |
||||
old_root.delete() |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('wagtailadmin', '0001_create_admin_access_permissions'), |
||||
('base', '0001_initial'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.RunPython( |
||||
reset_home_page, |
||||
), |
||||
] |
File diff suppressed because one or more lines are too long
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
# Generated by Django 2.1.13 on 2020-02-20 17:53 |
||||
|
||||
import gvot.base.mixins |
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
import modelcluster.fields |
||||
import wagtail.core.fields |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('wagtailcore', '0041_group_collection_permissions_verbose_name_plural'), |
||||
('base', '0003_sitepage_body'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='FormField', |
||||
fields=[ |
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)), |
||||
('label', models.CharField(help_text='The label of the form field', max_length=255, verbose_name='label')), |
||||
('required', models.BooleanField(default=True, verbose_name='required')), |
||||
('choices', models.TextField(blank=True, help_text='Comma separated list of choices. Only applicable in checkboxes, radio and dropdown.', verbose_name='choices')), |
||||
('default_value', models.CharField(blank=True, help_text='Default value. Comma separated values supported for checkboxes.', max_length=255, verbose_name='default value')), |
||||
('help_text', models.CharField(blank=True, max_length=255, verbose_name='help text')), |
||||
('field_type', models.CharField(choices=[('singleline', 'Single line text'), ('multiline', 'Multi-line text'), ('email', 'Email'), ('number', 'Number'), ('url', 'URL'), ('checkbox', 'Checkbox'), ('checkboxes', 'Choix multiples'), ('dropdown', 'Drop down'), ('multiselect', 'Multiple select'), ('radio', 'Radio buttons'), ('date', 'Date')], max_length=16, verbose_name='field type')), |
||||
], |
||||
options={ |
||||
'ordering': ['sort_order'], |
||||
'abstract': False, |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='Formulaire', |
||||
fields=[ |
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), |
||||
('to_address', models.CharField(blank=True, help_text='Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma.', max_length=255, verbose_name='to address')), |
||||
('from_address', models.CharField(blank=True, max_length=255, verbose_name='from address')), |
||||
('subject', models.CharField(blank=True, max_length=255, verbose_name='subject')), |
||||
('peremption', models.DateField(help_text='Uniquement destiné à avoir un point repère en vue de la suppression future des données', verbose_name='Date de péremption')), |
||||
('prescription', wagtail.core.fields.RichTextField(default='Ces données sont recueillies dans le seul but décrit en introduction du formulaire. Les données recueillies dans le cadre de cette campagne ne seront pas utilisées à d’autres fins ni transmises à un tiers. Vous disposez d’un droit d’accès, de modification, de rectification et de suppression des données vous concernant (loi « Informatique et Liberté » du 6 janvier 1978).', help_text="Texte destiné à avertir de l'utilisation qui sera faite des données recueillies.")), |
||||
('introduction', wagtail.core.fields.RichTextField(blank=True)), |
||||
('action', models.TextField(default='Envoyer', help_text='Texte du bouton du formulaire.')), |
||||
('confirmation', wagtail.core.fields.RichTextField(blank=True)), |
||||
], |
||||
options={ |
||||
'abstract': False, |
||||
}, |
||||
bases=('wagtailcore.page',), |
||||
), |
||||
migrations.CreateModel( |
||||
name='FormulaireIndex', |
||||
fields=[ |
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), |
||||
], |
||||
options={ |
||||