1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-07-04 06:42:13 +02:00

Compare commits

..

53 Commits

Author SHA1 Message Date
3eed93e346 Remove unused file 2021-02-23 23:38:54 +01:00
4da523a1ba Merge branch 'faster_ci' of https://gitlab.crans.org/bde/nk20 into faster_ci 2021-02-23 23:38:26 +01:00
e74ff54468 please use the configuration I have written for hadolint 2021-02-23 22:23:16 +00:00
2e49c9ffbd Add CI docker linter for CI Dockerfiles 2021-02-23 22:23:16 +00:00
d20a1038a8 Add CI docker linter for nk20 Dockerfile 2021-02-23 22:23:16 +00:00
f6b711bb1b Add hadolint configuration file 2021-02-23 22:23:16 +00:00
893d87a9e1 Add ansible linting to the CI 2021-02-23 22:23:16 +00:00
9f3323c73e Add docker image for ansible lint to be used in CI 2021-02-23 22:23:16 +00:00
c57f81b920 Add skip list for ansible-lint 2021-02-23 22:23:16 +00:00
0636d84286 Add docker image for tox linting to be used in CI 2021-02-23 22:23:16 +00:00
ed06901fae fix typo (added image: twice) 2021-02-23 22:23:16 +00:00
28932f316b copy paste is a bad practice 2021-02-23 22:23:16 +00:00
9b50ba722c Add custom pre-built docker images to be used for the CI 2021-02-23 22:23:16 +00:00
3e3e61d23f Use prebuilt docker images in the CI 2021-02-23 22:23:16 +00:00
1129815ca3 please use the configuration I have written for hadolint 2021-02-23 23:22:51 +01:00
c13172d3ff Add CI docker linter for CI Dockerfiles 2021-02-23 23:14:35 +01:00
fcc4121225 Add CI docker linter for nk20 Dockerfile 2021-02-23 23:14:00 +01:00
a06f355559 Add hadolint configuration file 2021-02-23 23:10:30 +01:00
08df5fcccd Add ansible linting to the CI 2021-02-23 23:02:51 +01:00
b6c0f9758d Add docker image for ansible lint to be used in CI 2021-02-23 23:02:29 +01:00
a23093851f Add skip list for ansible-lint 2021-02-23 22:57:33 +01:00
d5a9bf175f Add script to force delete a user, in case of duplicates
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-02-22 11:54:23 +01:00
d803ab5ec2 Add docker image for tox linting to be used in CI 2021-02-22 00:17:49 +01:00
d7a537b6b5 fix typo (added image: twice) 2021-02-21 23:52:42 +01:00
0941ee954d copy paste is a bad practice 2021-02-21 23:46:20 +01:00
fd11d96d95 Add custom pre-built docker images to be used for the CI 2021-02-21 23:40:03 +01:00
4bfc057454 Use prebuilt docker images in the CI 2021-02-21 23:39:08 +01:00
b597a6ac5b Fix soge credit deletion when the account is not validated yet
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-02-21 23:05:27 +01:00
a704b92c3d Prez BDE : ajout transaction random + see all buttons 2021-02-20 15:12:08 +01:00
53090b1a21 Fix JS texts
Signed-off-by: ynerant <ynerant@crans.org>
2021-02-14 11:52:37 +01:00
c49af0b83a Merge branch 'beta' into 'master'
Fix memberships

See merge request bde/nk20!147
2021-02-11 20:49:30 +00:00
5a05997d9d Fix date comparison when checking a membership from the parent club
Signed-off-by: ynerant <ynerant@crans.org>
2021-02-11 21:38:44 +01:00
c109cd3ddd Source is not destination
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2021-01-19 15:17:03 +01:00
84304971d7 Add sample translation file for english
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2021-01-19 14:29:12 +01:00
b8b781f9a2 Merge branch 'beta' into 'master'
Beta

Closes #84 et #83

See merge request bde/nk20!146
2021-01-19 12:40:24 +01:00
002128eed2 Merge branch 'fix-js-strings' into 'master'
Fix js strings

Closes #85, #84 et #83

See merge request bde/nk20!144
2021-01-19 12:24:13 +01:00
8d71783c42 Merge branch 'docs' into 'beta'
Docs

See merge request bde/nk20!145
2021-01-19 12:01:45 +01:00
a6f23df7d5 Load the good translation file, fixes #85
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2021-01-19 11:58:19 +01:00
d9c97628e2 Add Clacks Overhead header on each response. Closes #84
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2020-12-31 15:40:18 +01:00
893534955d Use the Debian mirror of Crans
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2020-12-30 00:04:08 +01:00
dfbf9972c2 By default, automatically change directory to /var/www/note_kfet and source the Python virtual environment in the .bashrc file
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2020-12-29 23:27:51 +01:00
b5f3b3ffc1 Use Nginx certbot challenge
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2020-12-29 21:44:28 +01:00
3aad4e7398 Agree Let's Encrypt ToS
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2020-12-29 21:41:29 +01:00
b4a1b513cc Good bye bde3-virt, welcome bde-note-dev!
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
2020-12-29 20:05:15 +01:00
c0c64f225c Merge branch 'ansible-fix' into 'beta'
Ansible fix

See merge request bde/nk20!139
2020-12-29 20:01:43 +01:00
0171f16311 Merge branch 'beta' into 'master'
Translate some words

See merge request bde/nk20!142
2020-11-21 13:55:26 +01:00
e1f647bd02 lesser hardcoded 2020-10-30 21:28:25 +01:00
39fd3a2471 set DB_PASSWORD in env file 2020-10-30 20:54:41 +01:00
1072e227b8 don't copy personal config on prod 2020-10-30 17:07:03 +01:00
cbf7e6fe6c run certbot if necessary 2020-10-30 17:01:47 +01:00
950922d041 do not hardcode mail 2020-10-30 17:01:26 +01:00
78fe070cd3 use debian backport only with debian 2020-10-30 16:59:44 +01:00
51d5733578 less hardcoded ansible config 2020-10-30 16:58:49 +01:00
35 changed files with 406 additions and 83 deletions

3
.ansible-lint Normal file
View File

@ -0,0 +1,3 @@
skip_list:
- command-instead-of-shell # Use shell only when shell functionality is required
- experimental # all rules tagged as experimental

5
.gitignore vendored
View File

@ -47,3 +47,8 @@ backups/
env/ env/
venv/ venv/
db.sqlite3 db.sqlite3
# ansibles customs host
ansible/host_vars/*.yaml
!ansible/host_vars/bde*
ansible/hosts

View File

@ -10,50 +10,22 @@ variables:
# Debian Buster # Debian Buster
py37-django22: py37-django22:
stage: test stage: test
image: debian:buster-backports image: otthorn/nk20_ci_37
before_script:
- >
apt-get update &&
apt-get install --no-install-recommends -t buster-backports -y
python3-django python3-django-crispy-forms
python3-django-extensions python3-django-filters python3-django-polymorphic
python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil
python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache
python3-bs4 python3-setuptools tox texlive-xetex
script: tox -e py37-django22 script: tox -e py37-django22
# Ubuntu 20.04 # Ubuntu 20.04
py38-django22: py38-django22:
stage: test stage: test
image: ubuntu:20.04 image: otthorn/nk20_ci_38
before_script:
# Fix tzdata prompt
- ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime && echo Europe/Paris > /etc/timezone
- >
apt-get update &&
apt-get install --no-install-recommends -y
python3-django python3-django-crispy-forms
python3-django-extensions python3-django-filters python3-django-polymorphic
python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil
python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache
python3-bs4 python3-setuptools tox texlive-xetex
script: tox -e py38-django22 script: tox -e py38-django22
# Debian Bullseye # Debian Bullseye
py39-django22: py39-django22:
stage: test stage: test
image: debian:bullseye image: otthorn/nk20_ci_39
before_script:
- >
apt-get update &&
apt-get install --no-install-recommends -y
python3-django python3-django-crispy-forms
python3-django-extensions python3-django-filters python3-django-polymorphic
python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil
python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache
python3-bs4 python3-setuptools tox texlive-xetex
script: tox -e py39-django22 script: tox -e py39-django22
# Tox linter
linters: linters:
stage: quality-assurance stage: quality-assurance
image: debian:buster-backports image: debian:buster-backports
@ -64,6 +36,20 @@ linters:
# Be nice to new contributors, but please use `tox` # Be nice to new contributors, but please use `tox`
allow_failure: true allow_failure: true
# Ansible linter
ansible-linter:
stage: quality-assurance
image: otthorn/nk20_ci_ansiblelint
script: ansible-lint ansible/
# Docker linter
docker-linter:
stage: quality-assurance
image: hadolint/hadolint
script:
- hadolint -c .hadolint Dockerfile
- hadolint -c .hadolint docker_ci/Dockerfile.*
# Compile documentation # Compile documentation
documentation: documentation:
stage: docs stage: docs

4
.hadolint Normal file
View File

@ -0,0 +1,4 @@
ignored:
- DL3008 # Do not force to pin version in apt (Debian)
- DL3013 # Do not force to pin version in pip (PyPI)
- DL3018 # Do not force to pin version in apk (Alpine)

View File

@ -69,13 +69,31 @@ accessible depuis l'ensemble de votre réseau, pratique pour tester le rendu
de la note sur un téléphone ! de la note sur un téléphone !
## Installation d'une instance de production ## Installation d'une instance de production
Pour déployer facilement la note il est possible d'utiliser le playbook Ansible (sinon vous pouvez toujours le faire a la main, voir plus bas).
### Avec ansible
Il vous faudra un serveur sous debian ou ubuntu connecté à internet et que vous souhaiterez accéder à cette instance de la note sur `note.nomdedomaine.tld`.
0. Installer Ansible sur votre machine personnelle.
0. (bis) cloner le dépot sur votre machine personelle.
1. Copier le fichier `ansible/host_example`
``` bash
$ cp ansible/hosts_example ansible/hosts
```
et ajouter sous [dev] et/ou [prod] les serveurs sur lesquels vous souhaitez installer la note.
2. Créer un fichier `ansible/host_vars/<note.nomdedomaine.tld.yaml>` sur le modèle des fichiers existants dans `ansible/hosts` et compléter les variables nécessaires.
3. lancer `ansible/base.yaml -l <nomdedomaine.tld.yaml>`
4. Aller vous faire un café, ca peux durer un moment.
### Installation manuelle
**En production on souhaite absolument utiliser les modules Python packagées dans le gestionnaire de paquet.** **En production on souhaite absolument utiliser les modules Python packagées dans le gestionnaire de paquet.**
Cela permet de mettre à jour facilement les dépendances critiques telles que Django. Cela permet de mettre à jour facilement les dépendances critiques telles que Django.
L'installation d'une instance de production néccessite **une installation de Debian Buster ou d'Ubuntu 20.04**. L'installation d'une instance de production néccessite **une installation de Debian Buster ou d'Ubuntu 20.04**.
Pour aller vite vous pouvez lancer le Playbook Ansible fournit dans ce dépôt en l'adaptant.
Sinon vous pouvez suivre les étapes décrites ci-dessous. Sinon vous pouvez suivre les étapes décrites ci-dessous.
0. Sous Debian Buster, **activer Debian Backports.** En effet Django 2.2 LTS n'est que disponible dans les backports. 0. Sous Debian Buster, **activer Debian Backports.** En effet Django 2.2 LTS n'est que disponible dans les backports.

View File

@ -7,7 +7,7 @@
prompt: "Password of the database (leave it blank to skip database init)" prompt: "Password of the database (leave it blank to skip database init)"
private: yes private: yes
vars: vars:
mirror: deb.debian.org mirror: mirror.crans.org
roles: roles:
- 1-apt-basic - 1-apt-basic
- 2-nk20 - 2-nk20

View File

@ -3,3 +3,4 @@ note:
server_name: note-beta.crans.org server_name: note-beta.crans.org
git_branch: beta git_branch: beta
cron_enabled: false cron_enabled: false
email: notekfet2020@lists.crans.org

View File

@ -3,3 +3,4 @@ note:
server_name: note-dev.crans.org server_name: note-dev.crans.org
git_branch: beta git_branch: beta
cron_enabled: false cron_enabled: false
email: notekfet2020@lists.crans.org

View File

@ -3,3 +3,4 @@ note:
server_name: note.crans.org server_name: note.crans.org
git_branch: master git_branch: master
cron_enabled: true cron_enabled: true
email: notekfet2020@lists.crans.org

View File

@ -1,5 +1,5 @@
[dev] [dev]
bde3-virt.adh.crans.org bde-note-dev.adh.crans.org
bde-nk20-beta.adh.crans.org bde-nk20-beta.adh.crans.org
[prod] [prod]

View File

@ -3,11 +3,12 @@
apt_repository: apt_repository:
repo: deb http://{{ mirror }}/debian buster-backports main repo: deb http://{{ mirror }}/debian buster-backports main
state: present state: present
when: ansible_facts['distribution'] == "Debian"
- name: Install note_kfet APT dependencies - name: Install note_kfet APT dependencies
apt: apt:
update_cache: true update_cache: true
default_release: buster-backports default_release: "{{ 'buster-backports' if ansible_facts['distribution'] == 'Debian' }}"
install_recommends: false install_recommends: false
name: name:
# Common tools # Common tools

View File

@ -16,7 +16,7 @@
- name: Use default env vars (should be updated!) - name: Use default env vars (should be updated!)
template: template:
src: "env_example" src: "env.j2"
dest: "/var/www/note_kfet/.env" dest: "/var/www/note_kfet/.env"
mode: 0644 mode: 0644
force: false force: false
@ -36,3 +36,13 @@
dest: /etc/cron.d/note dest: /etc/cron.d/note
owner: root owner: root
group: root group: root
- name: Set default directory to /var/www/note_kfet
lineinfile:
path: /etc/skel/.bashrc
line: 'cd /var/www/note_kfet'
- name: Automatically source Python virtual environment
lineinfile:
path: /etc/skel/.bashrc
line: 'source /var/www/note_kfet/env/bin/activate'

View File

@ -0,0 +1,23 @@
DJANGO_APP_STAGE=prod
# Only used in dev mode, change to "postgresql" if you want to use PostgreSQL in dev
DJANGO_DEV_STORE_METHOD=sqlite
DJANGO_DB_HOST=localhost
DJANGO_DB_NAME=note_db
DJANGO_DB_USER=note
DJANGO_DB_PASSWORD={{ DB_PASSWORD }}
DJANGO_DB_PORT=
DJANGO_SECRET_KEY=CHANGE_ME
DJANGO_SETTINGS_MODULE=note_kfet.settings
CONTACT_EMAIL=tresorerie.bde@localhost
NOTE_URL= {{note.server_name}}
# Config for mails. Only used in production
NOTE_MAIL=notekfet@localhost
EMAIL_HOST=smtp.localhost
EMAIL_PORT=25
EMAIL_USER=notekfet@localhost
EMAIL_PASSWORD=CHANGE_ME
# Wiki configuration
WIKI_USER=NoteKfet2020
WIKI_PASSWORD=

View File

@ -9,6 +9,11 @@
retries: 3 retries: 3
until: pkg_result is succeeded until: pkg_result is succeeded
- name: Check if certificate already exists.
stat:
path: /etc/letsencrypt/live/{{note.server_name}}/cert.pem
register: letsencrypt_cert
- name: Create /etc/letsencrypt/conf.d - name: Create /etc/letsencrypt/conf.d
file: file:
path: /etc/letsencrypt/conf.d path: /etc/letsencrypt/conf.d
@ -19,3 +24,17 @@
src: "letsencrypt/conf.d/nk20.ini.j2" src: "letsencrypt/conf.d/nk20.ini.j2"
dest: "/etc/letsencrypt/conf.d/nk20.ini" dest: "/etc/letsencrypt/conf.d/nk20.ini"
mode: 0644 mode: 0644
- name: Stop services to allow certbot to generate a cert.
service:
name: nginx
state: stopped
- name: Generate new certificate if one doesn't exist.
shell: "certbot certonly --non-interactive --agree-tos --config /etc/letsencrypt/conf.d/nk20.ini -d {{note.server_name}}"
when: letsencrypt_cert.stat.exists == False
- name: Restart services to allow certbot to generate a cert.
service:
name: nginx
state: started

View File

@ -10,7 +10,7 @@ rsa-key-size = 4096
# server = https://acme-staging.api.letsencrypt.org/directory # server = https://acme-staging.api.letsencrypt.org/directory
# Uncomment and update to register with the specified e-mail address # Uncomment and update to register with the specified e-mail address
email = notekfet2020@lists.crans.org email = {{ note.email }}
# Uncomment to use a text interface instead of ncurses # Uncomment to use a text interface instead of ncurses
text = True text = True

View File

@ -11,14 +11,14 @@
until: pkg_result is succeeded until: pkg_result is succeeded
- name: Create role note - name: Create role note
when: "DB_PASSWORD|bool" # If the password is not defined, skip the installation when: DB_PASSWORD|length > 0 # If the password is not defined, skip the installation
postgresql_user: postgresql_user:
name: note name: note
password: "{{ DB_PASSWORD }}" password: "{{ DB_PASSWORD }}"
become_user: postgres become_user: postgres
- name: Create NK20 database - name: Create NK20 database
when: "DB_PASSWORD|bool" when: DB_PASSWORD|length >0
postgresql_db: postgresql_db:
name: note_db name: note_db
owner: note owner: note

View File

@ -658,8 +658,8 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView):
if club.name != "Kfet" and club.parent_club and not Membership.objects.filter( if club.name != "Kfet" and club.parent_club and not Membership.objects.filter(
user=form.instance.user, user=form.instance.user,
club=club.parent_club, club=club.parent_club,
date_start__gte=club.parent_club.membership_start, date_start__lte=timezone.now(),
date_end__lte=club.parent_club.membership_end, date_end__gte=club.parent_club.membership_end,
).exists(): ).exists():
form.add_error('user', _('User is not a member of the parent club') + ' ' + club.parent_club.name) form.add_error('user', _('User is not a member of the parent club') + ' ' + club.parent_club.name)
error = True error = True

View File

@ -223,7 +223,8 @@ class Transaction(PolymorphicModel):
# Check that the amounts stay between big integer bounds # Check that the amounts stay between big integer bounds
diff_source, diff_dest = self.validate() diff_source, diff_dest = self.validate()
if not self.source.is_active or not self.destination.is_active: if not (hasattr(self, '_force_save') and self._force_save) \
and (not self.source.is_active or not self.destination.is_active):
raise ValidationError(_("The transaction can't be saved since the source note " raise ValidationError(_("The transaction can't be saved since the source note "
"or the destination note is not active.")) "or the destination note is not active."))
@ -271,7 +272,7 @@ class RecurrentTransaction(Transaction):
) )
def clean(self): def clean(self):
if self.template.destination != self.destination: if self.template.destination != self.destination and not (hasattr(self, '_force_save') and self._force_save):
raise ValidationError( raise ValidationError(
_("The destination of this transaction must equal to the destination of the template.")) _("The destination of this transaction must equal to the destination of the template."))
return super().clean() return super().clean()

View File

@ -43,4 +43,5 @@ def delete_transaction(instance, **_kwargs):
""" """
if not hasattr(instance, "_no_signal"): if not hasattr(instance, "_no_signal"):
instance.valid = False instance.valid = False
instance._force_save = True
instance.save() instance.save()

View File

@ -223,13 +223,14 @@ function consume (source, source_alias, dest, quantity, amount, reason, type, ca
const newBalance = source.balance - quantity * amount const newBalance = source.balance - quantity * amount
if (newBalance <= -5000) { if (newBalance <= -5000) {
addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' + addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' +
'but the emitter note %s is very negative.', [source_alias, source_alias])), 'danger', 30000) 'but the emitter note %s is very negative.'), [source_alias, source_alias]), 'danger', 30000)
} else if (newBalance < 0) { } else if (newBalance < 0) {
addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' + addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' +
'but the emitter note %s is negative.', [source_alias, source_alias])), 'warning', 30000) 'but the emitter note %s is negative.'), [source_alias, source_alias]), 'warning', 30000)
} }
if (source.membership && source.membership.date_end < new Date().toISOString()) { if (source.membership && source.membership.date_end < new Date().toISOString()) {
addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.', [source_alias])), 'danger', 30000) addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source_alias]),
'danger', 30000)
} }
} }
reset() reset()

View File

@ -302,7 +302,7 @@ $('#btn_transfer').click(function () {
addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source.name]), 'danger', 30000) addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source.name]), 'danger', 30000)
} }
if (dest.note.membership && dest.note.membership.date_end < new Date().toISOString()) { if (dest.note.membership && dest.note.membership.date_end < new Date().toISOString()) {
addMsg(interpolate(gettext('Warning, the destination note %s is no more a BDE member.'), [source.name]), 'danger', 30000) addMsg(interpolate(gettext('Warning, the destination note %s is no more a BDE member.'), [dest.name]), 'danger', 30000)
} }
if (!isNaN(source.note.balance)) { if (!isNaN(source.note.balance)) {

View File

@ -3024,7 +3024,9 @@
24, 24,
25, 25,
26, 26,
27 27,
30,
33
] ]
} }
}, },

View File

@ -381,9 +381,14 @@ class SogeCredit(models.Model):
tr.valid = True tr.valid = True
tr.created_at = timezone.now() tr.created_at = timezone.now()
tr.save() tr.save()
self.credit_transaction.valid = False if self.credit_transaction:
self.credit_transaction.reason += " (invalide)" # If the soge credit is deleted while the user is not validated yet,
self.credit_transaction.save() # there is not credit transaction.
# There is a credit transaction iff the user declares that no bank account
# was opened after the validation of the account.
self.credit_transaction.valid = False
self.credit_transaction.reason += " (invalide)"
self.credit_transaction.save()
super().delete(**kwargs) super().delete(**kwargs)
class Meta: class Meta:

18
docker_ci/Dockerfile.37 Normal file
View File

@ -0,0 +1,18 @@
FROM debian:buster-backports
LABEL maintainer="otthorn@crans.org"
LABEL description="Debian Buster backports image with django and tox \
installed for testing purposes"
RUN apt-get update \
&& apt-get install --no-install-recommends -t buster-backports -y \
python3-django python3-django-crispy-forms \
python3-django-extensions python3-django-filters \
python3-django-polymorphic \
python3-djangorestframework python3-django-oauth-toolkit \
python3-psycopg2 python3-pil \
python3-babel python3-lockfile python3-pip python3-phonenumbers \
python3-memcache \
python3-bs4 python3-setuptools tox texlive-xetex \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

22
docker_ci/Dockerfile.38 Normal file
View File

@ -0,0 +1,22 @@
FROM ubuntu:20.04
LABEL maintainer="otthorn@crans.org"
LABEL description="Ubuntu 20.04 image with django and tox \
installed for testing purposes"
# fix tzdata prompt
RUN ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime && echo Europe/Paris > /etc/timezone
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
python3-django python3-django-crispy-forms \
python3-django-extensions python3-django-filters \
python3-django-polymorphic \
python3-djangorestframework python3-django-oauth-toolkit \
python3-psycopg2 python3-pil \
python3-babel python3-lockfile python3-pip python3-phonenumbers \
python3-memcache \
python3-bs4 python3-setuptools tox texlive-xetex \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

18
docker_ci/Dockerfile.39 Normal file
View File

@ -0,0 +1,18 @@
FROM debian:bullseye
LABEL maintainer="otthorn@crans.org"
LABEL description="Debian Bulleye image with django and tox \
installed for testing purposes"
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
python3-django python3-django-crispy-forms \
python3-django-extensions python3-django-filters \
python3-django-polymorphic \
python3-djangorestframework python3-django-oauth-toolkit \
python3-psycopg2 python3-pil \
python3-babel python3-lockfile python3-pip python3-phonenumbers \
python3-memcache \
python3-bs4 python3-setuptools tox texlive-xetex \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@ -0,0 +1,10 @@
FROM python:3.9-alpine
LABEL maintainer="otthorn@crans.org"
LABEL description="Alpine image with ansible-lint and yamllint \
installed for linting purposes"
RUN apk add --no-cache gcc musl-dev python3-dev libffi-dev openssl-dev cargo
RUN pip install --no-cache-dir "yamllint>=1.26.0,<2.0"
RUN pip install --no-cache-dir "ansible-lint==5.0.0"
RUN pip install --no-cache-dir "ansible>=2.10,<2.11"

8
docker_ci/Dockerfile.tox Normal file
View File

@ -0,0 +1,8 @@
FROM alpine:3.13
LABEL maintainer="otthorn@crans.org"
LABEL description="Alpine image with tox \
installed for linting purposes"
RUN apk --no-cache add py3-pip=20.3.4-r0
RUN pip install --no-cache-dir tox==3.22.0

21
docker_ci/README.md Normal file
View File

@ -0,0 +1,21 @@
# Docker CI
Ce dossier contient les images docker à construire pour la CI. L'idée est
d'avoir une image pré-construire, au dessus laquel il y a besoin de faire
tourner uniquement les commandes qui nous intéresse. Cela permet notamment de
réduire drastiquement le temps que nécessite chaque test car seul la dernière
couche (layer) de l'image a besoin d'etre éxécuter.
## Build les images
Pour build les images il suffit de lancer les commandes suivantes
```
cd docker_ci/
docker build -t nk20_ci_37 -f Dockerfile.37 .
docker build -t nk20_ci_38 -f Dockerfile.38 .
docker build -t nk20_ci_39 -f Dockerfile.39 .
```
Elles sont acutellement build et disponible sur dockerhub
https://hub.docker.com/otthorn/nk20_ci_37

View File

@ -142,3 +142,17 @@ class TurbolinksMiddleware(object):
location = request.session.pop('_turbolinks_redirect_to') location = request.session.pop('_turbolinks_redirect_to')
response['Turbolinks-Location'] = location response['Turbolinks-Location'] = location
return response return response
class ClacksMiddleware(object):
"""
Add Clacks Overhead header on each response.
See https://www.gnuterrypratchett.com/
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
response['X-Clacks-Overhead'] = 'GNU Terry Pratchett'
return response

View File

@ -83,6 +83,7 @@ MIDDLEWARE = [
'note_kfet.middlewares.SessionMiddleware', 'note_kfet.middlewares.SessionMiddleware',
'note_kfet.middlewares.LoginByIPMiddleware', 'note_kfet.middlewares.LoginByIPMiddleware',
'note_kfet.middlewares.TurbolinksMiddleware', 'note_kfet.middlewares.TurbolinksMiddleware',
'note_kfet.middlewares.ClacksMiddleware',
] ]
ROOT_URLCONF = 'note_kfet.urls' ROOT_URLCONF = 'note_kfet.urls'

View File

@ -1,5 +1,5 @@
/* /*
* You should never see this file. * If you are not using the main language, you should never see this file.
* It is here only for compatibility reasons in case of the command `compilejsmessages` was never executed. * It is here only for compatibility reasons in case of the command `compilejsmessages` was never executed.
* Please execute this command to generate translation strings. * Please execute this command to generate translation strings.
*/ */
@ -9,14 +9,7 @@
var django = globals.django || (globals.django = {}); var django = globals.django || (globals.django = {});
django.pluralidx = function(n) { django.pluralidx = function(count) { return (count == 1) ? 0 : 1; };
var v=(n != 1);
if (typeof(v) == 'boolean') {
return v ? 1 : 0;
} else {
return v;
}
};
/* gettext library */ /* gettext library */
@ -73,39 +66,41 @@
/* formatting library */ /* formatting library */
django.formats = { django.formats = {
"DATETIME_FORMAT": "j \\d\\e F \\d\\e Y \\a \\l\\a\\s H:i", "DATETIME_FORMAT": "N j, Y, P",
"DATETIME_INPUT_FORMATS": [ "DATETIME_INPUT_FORMATS": [
"%d/%m/%Y %H:%M:%S",
"%d/%m/%Y %H:%M:%S.%f",
"%d/%m/%Y %H:%M",
"%d/%m/%y %H:%M:%S",
"%d/%m/%y %H:%M:%S.%f",
"%d/%m/%y %H:%M",
"%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M:%S.%f", "%Y-%m-%d %H:%M:%S.%f",
"%Y-%m-%d %H:%M", "%Y-%m-%d %H:%M",
"%Y-%m-%d" "%Y-%m-%d",
"%m/%d/%Y %H:%M:%S",
"%m/%d/%Y %H:%M:%S.%f",
"%m/%d/%Y %H:%M",
"%m/%d/%Y",
"%m/%d/%y %H:%M:%S",
"%m/%d/%y %H:%M:%S.%f",
"%m/%d/%y %H:%M",
"%m/%d/%y"
], ],
"DATE_FORMAT": "j \\d\\e F \\d\\e Y", "DATE_FORMAT": "N j, Y",
"DATE_INPUT_FORMATS": [ "DATE_INPUT_FORMATS": [
"%d/%m/%Y", "%Y-%m-%d",
"%d/%m/%y", "%m/%d/%Y",
"%Y-%m-%d" "%m/%d/%y"
], ],
"DECIMAL_SEPARATOR": ",", "DECIMAL_SEPARATOR": ".",
"FIRST_DAY_OF_WEEK": 1, "FIRST_DAY_OF_WEEK": 0,
"MONTH_DAY_FORMAT": "j \\d\\e F", "MONTH_DAY_FORMAT": "F j",
"NUMBER_GROUPING": 3, "NUMBER_GROUPING": 3,
"SHORT_DATETIME_FORMAT": "d/m/Y H:i", "SHORT_DATETIME_FORMAT": "m/d/Y P",
"SHORT_DATE_FORMAT": "d/m/Y", "SHORT_DATE_FORMAT": "m/d/Y",
"THOUSAND_SEPARATOR": ".", "THOUSAND_SEPARATOR": ",",
"TIME_FORMAT": "H:i", "TIME_FORMAT": "P",
"TIME_INPUT_FORMATS": [ "TIME_INPUT_FORMATS": [
"%H:%M:%S", "%H:%M:%S",
"%H:%M:%S.%f", "%H:%M:%S.%f",
"%H:%M" "%H:%M"
], ],
"YEAR_MONTH_FORMAT": "F \\d\\e Y" "YEAR_MONTH_FORMAT": "F Y"
}; };
django.get_format = function(format_type) { django.get_format = function(format_type) {

View File

@ -0,0 +1,134 @@
/*
* You should never see this file.
* It is here only for compatibility reasons in case of the command `compilejsmessages` was never executed.
* Please execute this command to generate translation strings.
*/
(function(globals) {
var django = globals.django || (globals.django = {});
django.pluralidx = function(n) {
var v=(n != 1);
if (typeof(v) == 'boolean') {
return v ? 1 : 0;
} else {
return v;
}
};
/* gettext library */
django.catalog = django.catalog || {};
if (!django.jsi18n_initialized) {
django.gettext = function(msgid) {
var value = django.catalog[msgid];
if (typeof(value) == 'undefined') {
return msgid;
} else {
return (typeof(value) == 'string') ? value : value[0];
}
};
django.ngettext = function(singular, plural, count) {
var value = django.catalog[singular];
if (typeof(value) == 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value.constructor === Array ? value[django.pluralidx(count)] : value;
}
};
django.gettext_noop = function(msgid) { return msgid; };
django.pgettext = function(context, msgid) {
var value = django.gettext(context + '\x04' + msgid);
if (value.indexOf('\x04') != -1) {
value = msgid;
}
return value;
};
django.npgettext = function(context, singular, plural, count) {
var value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
if (value.indexOf('\x04') != -1) {
value = django.ngettext(singular, plural, count);
}
return value;
};
django.interpolate = function(fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
}
};
/* formatting library */
django.formats = {
"DATETIME_FORMAT": "j \\d\\e F \\d\\e Y \\a \\l\\a\\s H:i",
"DATETIME_INPUT_FORMATS": [
"%d/%m/%Y %H:%M:%S",
"%d/%m/%Y %H:%M:%S.%f",
"%d/%m/%Y %H:%M",
"%d/%m/%y %H:%M:%S",
"%d/%m/%y %H:%M:%S.%f",
"%d/%m/%y %H:%M",
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M:%S.%f",
"%Y-%m-%d %H:%M",
"%Y-%m-%d"
],
"DATE_FORMAT": "j \\d\\e F \\d\\e Y",
"DATE_INPUT_FORMATS": [
"%d/%m/%Y",
"%d/%m/%y",
"%Y-%m-%d"
],
"DECIMAL_SEPARATOR": ",",
"FIRST_DAY_OF_WEEK": 1,
"MONTH_DAY_FORMAT": "j \\d\\e F",
"NUMBER_GROUPING": 3,
"SHORT_DATETIME_FORMAT": "d/m/Y H:i",
"SHORT_DATE_FORMAT": "d/m/Y",
"THOUSAND_SEPARATOR": ".",
"TIME_FORMAT": "H:i",
"TIME_INPUT_FORMATS": [
"%H:%M:%S",
"%H:%M:%S.%f",
"%H:%M"
],
"YEAR_MONTH_FORMAT": "F \\d\\e Y"
};
django.get_format = function(format_type) {
var value = django.formats[format_type];
if (typeof(value) == 'undefined') {
return format_type;
} else {
return value;
}
};
/* add to global namespace */
globals.pluralidx = django.pluralidx;
globals.gettext = django.gettext;
globals.ngettext = django.ngettext;
globals.gettext_noop = django.gettext_noop;
globals.pgettext = django.pgettext;
globals.npgettext = django.npgettext;
globals.interpolate = django.interpolate;
globals.get_format = django.get_format;
django.jsi18n_initialized = true;
}
}(this));

View File

@ -39,7 +39,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<script src="{% static "js/konami.js" %}"></script> <script src="{% static "js/konami.js" %}"></script>
{# Translation in javascript files #} {# Translation in javascript files #}
<script src="{% static "js/jsi18n/jsi18n."|add:LANGUAGE_CODE|add:".js" %}"></script> <script src="{% static "js/jsi18n/"|add:LANGUAGE_CODE|add:".js" %}"></script>
{# If extra ressources are needed for a form, load here #} {# If extra ressources are needed for a form, load here #}
{% if form.media %} {% if form.media %}