Compare commits
128 Commits
feature/ea
...
feature/im
Author | SHA1 | Date | |
---|---|---|---|
46fa14ed12 | |||
18dffb0053 | |||
6e47d1471e | |||
b5146569e1 | |||
acde993352 | |||
8852ef990e | |||
87295ad9b7 | |||
5ab5ef681c | |||
c9e70889dd | |||
b30ee0a27a | |||
ef968f3673 | |||
96dede5077 | |||
66fcb76cb5 | |||
63c8e51137 | |||
12bec5c553 | |||
08460a6964 | |||
b5a40cfda9 | |||
c78953b036 | |||
427f7ceaff | |||
1055385bcc | |||
c1022642a2 | |||
910a6f8b34 | |||
06253f029c | |||
fa6527b24f | |||
0501e6417a | |||
a198f5252d | |||
d83842af27 | |||
f605f7dcc6 | |||
e638bc04ed | |||
4830c3ea2d | |||
8e7c025e47 | |||
1bfe929ab3 | |||
93cc2c883e | |||
44290a20a6 | |||
1f10a284f2 | |||
28f397574f | |||
6c1fa6de0b | |||
f0a08afd31 | |||
982fc09908 | |||
9e0b5b0b82 | |||
b12e8dc147 | |||
25c5a3297c | |||
dd3ad42eb5 | |||
5ea181829e | |||
0cf203669f | |||
559bfcac60 | |||
db8a1ed0ab | |||
16150905a0 | |||
9a376887ac | |||
773808fa59 | |||
c1e59a0676 | |||
05febc60bd | |||
a73fe598ef | |||
b7f20fed6c | |||
585923c827 | |||
394e17d599 | |||
59136850b8 | |||
d726f4b1e8 | |||
705b9b1e6a | |||
31e8ad8a3e | |||
99827e005b | |||
751c8a8bc6 | |||
73305c0b28 | |||
37216cd16b | |||
dae68638cf | |||
7cadc0bc28 | |||
cce686f3a8 | |||
4fe46fbcef | |||
fe8b8f46aa | |||
310f1a2283 | |||
7079761ffe | |||
f681c981c6 | |||
5d97146d14 | |||
7b56bd697d | |||
14cd268d69 | |||
754be1c9c9 | |||
da2c155254 | |||
ceb2888f82 | |||
ce3e2bb32b | |||
26c94c9ec6 | |||
7b6eed9a47 | |||
639197f4c8 | |||
13bae8d2fa | |||
6b2027550c | |||
022b365bb2 | |||
d8867fc9ea | |||
118c58b5fa | |||
faccc1367f | |||
22b83b0814 | |||
1d82e2a7d9 | |||
823bd578f2 | |||
3e5c36b39e | |||
8fb0897160 | |||
b8a72c57e1 | |||
6a0a8e8ab4 | |||
9188565a86 | |||
4d7d22c337 | |||
b58116b023 | |||
fe9e5ce861 | |||
e43d53e564 | |||
d4a5039efc | |||
35506e0175 | |||
1c27831f92 | |||
cdbf07a835 | |||
b92580943a | |||
60eff1000f | |||
96510b270d | |||
1281104d96 | |||
3c1724fa81 | |||
1630af4fbd | |||
e76e2b1537 | |||
6c276dc596 | |||
d3c115e3f9 | |||
c245ef7149 | |||
8b09ba2924 | |||
52eb310f95 | |||
5bff38fc7b | |||
2813a59323 | |||
eef33fa263 | |||
241d3cea53 | |||
89d6db4208 | |||
e0ad288cf4 | |||
f4d7fae8ca | |||
95a7493fc1 | |||
8243dbcbef | |||
c3a4071627 | |||
cef3f22e0d | |||
c206b965ad |
8
.github/actions/compile_messages/action.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
name: "Compile messages"
|
||||||
|
description: "Compile the gettext translation messages"
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Setup project
|
||||||
|
run: poetry run ./manage.py compilemessages
|
||||||
|
shell: bash
|
53
.github/actions/setup_project/action.yml
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
name: "Setup project"
|
||||||
|
description: "Setup Python and Poetry"
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Install apt packages
|
||||||
|
uses: awalsh128/cache-apt-pkgs-action@latest
|
||||||
|
with:
|
||||||
|
packages: gettext libxapian-dev libgraphviz-dev
|
||||||
|
version: 1.0 # increment to reset cache
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install gettext libxapian-dev libgraphviz-dev
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Set up python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
|
||||||
|
- name: Load cached Poetry installation
|
||||||
|
id: cached-poetry
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.local
|
||||||
|
key: poetry-0 # increment to reset cache
|
||||||
|
|
||||||
|
- name: Install Poetry
|
||||||
|
if: steps.cached-poetry.outputs.cache-hit != 'true'
|
||||||
|
shell: bash
|
||||||
|
run: curl -sSL https://install.python-poetry.org | python3 -
|
||||||
|
|
||||||
|
- name: Check pyproject.toml syntax
|
||||||
|
shell: bash
|
||||||
|
run: poetry check
|
||||||
|
|
||||||
|
- name: Load cached dependencies
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pypoetry
|
||||||
|
key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-poetry-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: poetry install -E testing -E docs
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Compile gettext messages
|
||||||
|
run: poetry run ./manage.py compilemessages
|
||||||
|
shell: bash
|
10
.github/actions/setup_xapian/action.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
name: "Setup xapian"
|
||||||
|
description: "Setup the xapian indexes"
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Setup xapian index
|
||||||
|
run: |
|
||||||
|
mkdir -p /dev/shm/search_indexes
|
||||||
|
ln -s /dev/shm/search_indexes sith/search_indexes
|
||||||
|
shell: bash
|
18
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "pip" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
# Raise pull requests for version updates
|
||||||
|
# to pip against the `develop` branch
|
||||||
|
target-branch: "taiste"
|
||||||
|
reviewers:
|
||||||
|
- "ae-utbm/developpers-v3"
|
||||||
|
commit-message:
|
||||||
|
prefix: "[UPDATE] "
|
43
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
name: Sith 3 CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- taiste
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- taiste
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
black:
|
||||||
|
name: Black format
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Setup Project
|
||||||
|
uses: ./.github/actions/setup_project
|
||||||
|
- run: poetry run black --check .
|
||||||
|
|
||||||
|
tests:
|
||||||
|
name: Run tests and generate coverage report
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- uses: ./.github/actions/setup_project
|
||||||
|
- uses: ./.github/actions/setup_xapian
|
||||||
|
- uses: ./.github/actions/compile_messages
|
||||||
|
- name: Run tests
|
||||||
|
run: poetry run coverage run ./manage.py test
|
||||||
|
- name: Generate coverage report
|
||||||
|
run: |
|
||||||
|
poetry run coverage report
|
||||||
|
poetry run coverage html
|
||||||
|
- name: Archive code coverage results
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: coverage-report
|
||||||
|
path: coverage_report
|
4
.github/workflows/deploy.yml
vendored
@ -33,11 +33,11 @@ jobs:
|
|||||||
|
|
||||||
# See https://github.com/ae-utbm/sith3/wiki/GitHub-Actions#deployment-action
|
# See https://github.com/ae-utbm/sith3/wiki/GitHub-Actions#deployment-action
|
||||||
script: |
|
script: |
|
||||||
export PATH="$HOME/.poetry/bin:$PATH"
|
export PATH="/home/sith/.local/bin:$PATH"
|
||||||
pushd ${{secrets.SITH_PATH}}
|
pushd ${{secrets.SITH_PATH}}
|
||||||
|
|
||||||
git pull
|
git pull
|
||||||
poetry update
|
poetry install
|
||||||
poetry run ./manage.py migrate
|
poetry run ./manage.py migrate
|
||||||
echo "yes" | poetry run ./manage.py collectstatic
|
echo "yes" | poetry run ./manage.py collectstatic
|
||||||
poetry run ./manage.py compilestatic
|
poetry run ./manage.py compilestatic
|
||||||
|
62
.github/workflows/taiste.yml
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
name: Sith3 taiste
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ taiste ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deployment:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: taiste
|
||||||
|
timeout-minutes: 30
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: SSH Remote Commands
|
||||||
|
uses: appleboy/ssh-action@dce9d565de8d876c11d93fa4fe677c0285a66d78
|
||||||
|
with:
|
||||||
|
# Proxy
|
||||||
|
proxy_host : ${{secrets.PROXY_HOST}}
|
||||||
|
proxy_port : ${{secrets.PROXY_PORT}}
|
||||||
|
proxy_username : ${{secrets.PROXY_USER}}
|
||||||
|
proxy_passphrase: ${{secrets.PROXY_PASSPHRASE}}
|
||||||
|
proxy_key: ${{secrets.PROXY_KEY}}
|
||||||
|
|
||||||
|
# Serveur web
|
||||||
|
host: ${{secrets.HOST}}
|
||||||
|
port : ${{secrets.PORT}}
|
||||||
|
username : ${{secrets.USER}}
|
||||||
|
key: ${{secrets.KEY}}
|
||||||
|
|
||||||
|
script_stop: true
|
||||||
|
|
||||||
|
# See https://github.com/ae-utbm/sith3/wiki/GitHub-Actions#deployment-action
|
||||||
|
script: |
|
||||||
|
export PATH="$HOME/.poetry/bin:$PATH"
|
||||||
|
pushd ${{secrets.SITH_PATH}}
|
||||||
|
|
||||||
|
git pull
|
||||||
|
poetry install
|
||||||
|
poetry run ./manage.py migrate
|
||||||
|
echo "yes" | poetry run ./manage.py collectstatic
|
||||||
|
poetry run ./manage.py compilestatic
|
||||||
|
poetry run ./manage.py compilemessages
|
||||||
|
|
||||||
|
sudo systemctl restart uwsgi
|
||||||
|
|
||||||
|
sentry:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: taiste
|
||||||
|
timeout-minutes: 30
|
||||||
|
needs: deployment
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Sentry Release
|
||||||
|
uses: getsentry/action-release@v1.2.0
|
||||||
|
env:
|
||||||
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
|
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||||
|
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||||
|
SENTRY_URL: ${{ secrets.SENTRY_URL }}
|
||||||
|
with:
|
||||||
|
environment: taiste
|
83
.github/workflows/unittests.yml
vendored
@ -1,83 +0,0 @@
|
|||||||
name: Sith3 CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
unittests:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 30
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Skip unit testing if no diff on .py files
|
|
||||||
- name: Check file diff
|
|
||||||
uses: technote-space/get-diff-action@v6
|
|
||||||
id: git-diff
|
|
||||||
with:
|
|
||||||
PATTERNS: |
|
|
||||||
**/*.py
|
|
||||||
|
|
||||||
- name: Set up python
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.8'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install gettext libxapian-dev libgraphviz-dev
|
|
||||||
|
|
||||||
- name: Install poetry
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
python -m pip install poetry
|
|
||||||
|
|
||||||
- name: Checking pyproject.toml syntax
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
run: poetry check
|
|
||||||
|
|
||||||
- name: Install project
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
run: poetry install -E testing
|
|
||||||
|
|
||||||
- name: Setup xapian index
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
run: |
|
|
||||||
mkdir -p /dev/shm/search_indexes
|
|
||||||
ln -s /dev/shm/search_indexes sith/search_indexes
|
|
||||||
|
|
||||||
- name: Setup project
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
run: poetry run ./manage.py compilemessages
|
|
||||||
|
|
||||||
- name: Launch tests and generate coverage report
|
|
||||||
if: steps.git-diff.outputs.diff
|
|
||||||
run: |
|
|
||||||
poetry run coverage run ./manage.py test
|
|
||||||
poetry run coverage report
|
|
||||||
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Set up python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.8'
|
|
||||||
|
|
||||||
- name: Install black
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
python -m pip install black==22.6.0
|
|
||||||
|
|
||||||
- name: Check linting
|
|
||||||
run: black --check .
|
|
2
.gitignore
vendored
@ -7,9 +7,11 @@ db.sqlite3
|
|||||||
pyrightconfig.json
|
pyrightconfig.json
|
||||||
dist/
|
dist/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.idea/
|
||||||
env/
|
env/
|
||||||
doc/html
|
doc/html
|
||||||
data/
|
data/
|
||||||
|
galaxy/test_galaxy_state.json
|
||||||
/static/
|
/static/
|
||||||
sith/settings_custom.py
|
sith/settings_custom.py
|
||||||
sith/search_indexes/
|
sith/search_indexes/
|
||||||
|
3
.mailmap
@ -15,4 +15,5 @@ Vial <robin.trioux@utbm.fr>
|
|||||||
Zar <antoine.charmeau@utbm.fr> <antoine.charmeau@laposte.net>
|
Zar <antoine.charmeau@utbm.fr> <antoine.charmeau@laposte.net>
|
||||||
root <root@localhost.localdomain>
|
root <root@localhost.localdomain>
|
||||||
tleb <tleb@openmailbox.org> <theo.lebrun@live.fr>
|
tleb <tleb@openmailbox.org> <theo.lebrun@live.fr>
|
||||||
tleb <tleb@openmailbox.org> <theo.lebrun@utbm.fr>
|
tleb <tleb@openmailbox.org> <theo.lebrun@utbm.fr>
|
||||||
|
Maréchal <thgirod@hotmail.com>
|
@ -18,7 +18,7 @@ formats: all
|
|||||||
|
|
||||||
# Optionally set the version of Python and requirements required to build your docs
|
# Optionally set the version of Python and requirements required to build your docs
|
||||||
python:
|
python:
|
||||||
version: 3.8
|
version: "3.8"
|
||||||
install:
|
install:
|
||||||
- method: pip
|
- method: pip
|
||||||
path: .
|
path: .
|
||||||
|
21
LICENSE.old
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Skia
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -9,7 +9,7 @@
|
|||||||
<img src="https://img.shields.io/readthedocs/sith-ae?logo=readthedocs&style=for-the-badge">
|
<img src="https://img.shields.io/readthedocs/sith-ae?logo=readthedocs&style=for-the-badge">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://discord.gg/XK9WfPsUFm">
|
<a href="https://discord.gg/XK9WfPsUFm">
|
||||||
<img src="https://img.shields.io/discord/889796155523874847?label=Discord&logo=discord&style=for-the-badge">
|
<img src="https://img.shields.io/discord/971448179075731476?label=Discord&logo=discord&style=for-the-badge">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -37,5 +37,4 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
> This project is licenced under GNU GPL, see the LICENSE file at the top of the repository for more details.
|
> This project is licensed under GNU GPL, see the LICENSE file at the top of the repository for more details.
|
||||||
|
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -6,7 +6,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("club", "0001_initial"),
|
("club", "0001_initial"),
|
||||||
("accounting", "0001_initial"),
|
("accounting", "0001_initial"),
|
||||||
|
@ -6,7 +6,6 @@ import phonenumber_field.modelfields
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("accounting", "0002_auto_20160824_2152")]
|
dependencies = [("accounting", "0002_auto_20160824_2152")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -6,7 +6,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("accounting", "0003_auto_20160824_2203")]
|
dependencies = [("accounting", "0003_auto_20160824_2203")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("accounting", "0004_auto_20161005_1505")]
|
dependencies = [("accounting", "0004_auto_20161005_1505")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -74,7 +66,7 @@ class Company(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -125,7 +117,9 @@ class BankAccount(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
m = self.club.get_membership_for(user)
|
m = self.club.get_membership_for(user)
|
||||||
if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
@ -162,7 +156,9 @@ class ClubAccount(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -233,7 +229,9 @@ class GeneralJournal(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
if self.club_account.can_be_edited_by(user):
|
if self.club_account.can_be_edited_by(user):
|
||||||
return True
|
return True
|
||||||
@ -243,7 +241,7 @@ class GeneralJournal(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
if self.club_account.can_be_edited_by(user):
|
if self.club_account.can_be_edited_by(user):
|
||||||
return True
|
return True
|
||||||
@ -422,7 +420,9 @@ class Operation(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
if self.journal.closed:
|
if self.journal.closed:
|
||||||
return False
|
return False
|
||||||
@ -435,7 +435,7 @@ class Operation(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
if self.journal.closed:
|
if self.journal.closed:
|
||||||
return False
|
return False
|
||||||
@ -491,7 +491,9 @@ class AccountingType(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -562,6 +564,8 @@ class Label(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
return self.club_account.is_owned_by(user)
|
return self.club_account.is_owned_by(user)
|
||||||
|
|
||||||
def can_be_edited_by(self, user):
|
def can_be_edited_by(self, user):
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
<h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2>
|
<h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2>
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and not object.club_accounts.exists() %}
|
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and not object.club_accounts.exists() %}
|
||||||
<a href="{{ url('accounting:bank_delete', b_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
<a href="{{ url('accounting:bank_delete', b_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h4>{% trans %}Infos{% endtrans %}</h4>
|
<h4>{% trans %}Infos{% endtrans %}</h4>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<h4>
|
<h4>
|
||||||
{% trans %}Accounting{% endtrans %}
|
{% trans %}Accounting{% endtrans %}
|
||||||
</h4>
|
</h4>
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||||
<p><a href="{{ url('accounting:simple_type_list') }}">{% trans %}Manage simplified types{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:simple_type_list') }}">{% trans %}Manage simplified types{% endtrans %}</a></p>
|
||||||
<p><a href="{{ url('accounting:type_list') }}">{% trans %}Manage accounting types{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:type_list') }}">{% trans %}Manage accounting types{% endtrans %}</a></p>
|
||||||
<p><a href="{{ url('accounting:bank_new') }}">{% trans %}New bank account{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:bank_new') }}">{% trans %}New bank account{% endtrans %}</a></p>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
{% if user.is_root and not object.journals.exists() %}
|
{% if user.is_root and not object.journals.exists() %}
|
||||||
<a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
<a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p>
|
||||||
@ -56,7 +56,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<td> <a href="{{ url('accounting:journal_details', j_id=j.id) }}">{% trans %}View{% endtrans %}</a>
|
<td> <a href="{{ url('accounting:journal_details', j_id=j.id) }}">{% trans %}View{% endtrans %}</a>
|
||||||
<a href="{{ url('accounting:journal_edit', j_id=j.id) }}">{% trans %}Edit{% endtrans %}</a>
|
<a href="{{ url('accounting:journal_edit', j_id=j.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and j.operations.count() == 0 %}
|
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and j.operations.count() == 0 %}
|
||||||
<a href="{{ url('accounting:journal_delete', j_id=j.id) }}">{% trans %}Delete{% endtrans %}</a>
|
<a href="{{ url('accounting:journal_delete', j_id=j.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
@ -6,11 +6,12 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="accounting">
|
<div id="accounting">
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root %}
|
{% if user.is_root
|
||||||
|
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||||
|
%}
|
||||||
<p><a href="{{ url('accounting:co_new') }}">{% trans %}Create new company{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:co_new') }}">{% trans %}Create new company{% endtrans %}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<br/>
|
||||||
</br>
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -84,10 +84,13 @@
|
|||||||
<td>-</td>
|
<td>-</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td>
|
<td>
|
||||||
{% if o.journal.club_account.bank_account.name != "AE TI" and o.journal.club_account.bank_account.name != "TI" or user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
{%
|
||||||
{% if not o.journal.closed %}
|
if o.journal.club_account.bank_account.name not in ["AE TI", "TI"]
|
||||||
<a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a>
|
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||||
{% endif %}
|
%}
|
||||||
|
{% if not o.journal.closed %}
|
||||||
|
<a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td>
|
<td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p><a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{% trans %}Back to club account{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{% trans %}Back to club account{% endtrans %}</a></p>
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if object.labels.all() %}
|
{% if object.labels.all() %}
|
||||||
@ -21,7 +21,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{% for l in object.labels.all() %}
|
{% for l in object.labels.all() %}
|
||||||
<li><a href="{{ url('accounting:label_edit', label_id=l.id) }}">{{ l }}</a>
|
<li><a href="{{ url('accounting:label_edit', label_id=l.id) }}">{{ l }}</a>
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||||
-
|
-
|
||||||
<a href="{{ url('accounting:label_delete', label_id=l.id) }}">{% trans %}Delete{% endtrans %}</a>
|
<a href="{{ url('accounting:label_delete', label_id=l.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -39,7 +31,6 @@ from accounting.models import (
|
|||||||
|
|
||||||
class RefoundAccountTest(TestCase):
|
class RefoundAccountTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
|
||||||
self.skia = User.objects.filter(username="skia").first()
|
self.skia = User.objects.filter(username="skia").first()
|
||||||
# reffil skia's account
|
# reffil skia's account
|
||||||
self.skia.customer.amount = 800
|
self.skia.customer.amount = 800
|
||||||
@ -81,7 +72,6 @@ class RefoundAccountTest(TestCase):
|
|||||||
|
|
||||||
class JournalTest(TestCase):
|
class JournalTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
|
||||||
self.journal = GeneralJournal.objects.filter(id=1).first()
|
self.journal = GeneralJournal.objects.filter(id=1).first()
|
||||||
|
|
||||||
def test_permission_granted(self):
|
def test_permission_granted(self):
|
||||||
@ -109,7 +99,6 @@ class JournalTest(TestCase):
|
|||||||
|
|
||||||
class OperationTest(TestCase):
|
class OperationTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
|
||||||
self.tomorrow_formatted = (date.today() + timedelta(days=1)).strftime(
|
self.tomorrow_formatted = (date.today() + timedelta(days=1)).strftime(
|
||||||
"%d/%m/%Y"
|
"%d/%m/%Y"
|
||||||
)
|
)
|
||||||
|
@ -1,154 +1,140 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.urls import re_path
|
from django.urls import path
|
||||||
|
|
||||||
from accounting.views import *
|
from accounting.views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Accounting types
|
# Accounting types
|
||||||
re_path(
|
path(
|
||||||
r"^simple_type$",
|
"simple_type/",
|
||||||
SimplifiedAccountingTypeListView.as_view(),
|
SimplifiedAccountingTypeListView.as_view(),
|
||||||
name="simple_type_list",
|
name="simple_type_list",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^simple_type/create$",
|
"simple_type/create/",
|
||||||
SimplifiedAccountingTypeCreateView.as_view(),
|
SimplifiedAccountingTypeCreateView.as_view(),
|
||||||
name="simple_type_new",
|
name="simple_type_new",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^simple_type/(?P<type_id>[0-9]+)/edit$",
|
"simple_type/<int:type_id>/edit/",
|
||||||
SimplifiedAccountingTypeEditView.as_view(),
|
SimplifiedAccountingTypeEditView.as_view(),
|
||||||
name="simple_type_edit",
|
name="simple_type_edit",
|
||||||
),
|
),
|
||||||
# Accounting types
|
# Accounting types
|
||||||
re_path(r"^type$", AccountingTypeListView.as_view(), name="type_list"),
|
path("type/", AccountingTypeListView.as_view(), name="type_list"),
|
||||||
re_path(r"^type/create$", AccountingTypeCreateView.as_view(), name="type_new"),
|
path("type/create/", AccountingTypeCreateView.as_view(), name="type_new"),
|
||||||
re_path(
|
path(
|
||||||
r"^type/(?P<type_id>[0-9]+)/edit$",
|
"type/<int:type_id>/edit/",
|
||||||
AccountingTypeEditView.as_view(),
|
AccountingTypeEditView.as_view(),
|
||||||
name="type_edit",
|
name="type_edit",
|
||||||
),
|
),
|
||||||
# Bank accounts
|
# Bank accounts
|
||||||
re_path(r"^$", BankAccountListView.as_view(), name="bank_list"),
|
path("", BankAccountListView.as_view(), name="bank_list"),
|
||||||
re_path(r"^bank/create$", BankAccountCreateView.as_view(), name="bank_new"),
|
path("bank/create", BankAccountCreateView.as_view(), name="bank_new"),
|
||||||
re_path(
|
path(
|
||||||
r"^bank/(?P<b_account_id>[0-9]+)$",
|
"bank/<int:b_account_id>/",
|
||||||
BankAccountDetailView.as_view(),
|
BankAccountDetailView.as_view(),
|
||||||
name="bank_details",
|
name="bank_details",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^bank/(?P<b_account_id>[0-9]+)/edit$",
|
"bank/<int:b_account_id>/edit/",
|
||||||
BankAccountEditView.as_view(),
|
BankAccountEditView.as_view(),
|
||||||
name="bank_edit",
|
name="bank_edit",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^bank/(?P<b_account_id>[0-9]+)/delete$",
|
"bank/<int:b_account_id>/delete/",
|
||||||
BankAccountDeleteView.as_view(),
|
BankAccountDeleteView.as_view(),
|
||||||
name="bank_delete",
|
name="bank_delete",
|
||||||
),
|
),
|
||||||
# Club accounts
|
# Club accounts
|
||||||
re_path(r"^club/create$", ClubAccountCreateView.as_view(), name="club_new"),
|
path("club/create/", ClubAccountCreateView.as_view(), name="club_new"),
|
||||||
re_path(
|
path(
|
||||||
r"^club/(?P<c_account_id>[0-9]+)$",
|
"club/<int:c_account_id>/",
|
||||||
ClubAccountDetailView.as_view(),
|
ClubAccountDetailView.as_view(),
|
||||||
name="club_details",
|
name="club_details",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^club/(?P<c_account_id>[0-9]+)/edit$",
|
"club/<int:c_account_id>/edit/",
|
||||||
ClubAccountEditView.as_view(),
|
ClubAccountEditView.as_view(),
|
||||||
name="club_edit",
|
name="club_edit",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^club/(?P<c_account_id>[0-9]+)/delete$",
|
"club/<int:c_account_id>/delete/",
|
||||||
ClubAccountDeleteView.as_view(),
|
ClubAccountDeleteView.as_view(),
|
||||||
name="club_delete",
|
name="club_delete",
|
||||||
),
|
),
|
||||||
# Journals
|
# Journals
|
||||||
re_path(r"^journal/create$", JournalCreateView.as_view(), name="journal_new"),
|
path("journal/create/", JournalCreateView.as_view(), name="journal_new"),
|
||||||
re_path(
|
path(
|
||||||
r"^journal/(?P<j_id>[0-9]+)$",
|
"journal/<int:j_id>/",
|
||||||
JournalDetailView.as_view(),
|
JournalDetailView.as_view(),
|
||||||
name="journal_details",
|
name="journal_details",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^journal/(?P<j_id>[0-9]+)/edit$",
|
"journal/<int:j_id>/edit/",
|
||||||
JournalEditView.as_view(),
|
JournalEditView.as_view(),
|
||||||
name="journal_edit",
|
name="journal_edit",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^journal/(?P<j_id>[0-9]+)/delete$",
|
"journal/<int:j_id>/delete/",
|
||||||
JournalDeleteView.as_view(),
|
JournalDeleteView.as_view(),
|
||||||
name="journal_delete",
|
name="journal_delete",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^journal/(?P<j_id>[0-9]+)/statement/nature$",
|
"journal/<int:j_id>/statement/nature/",
|
||||||
JournalNatureStatementView.as_view(),
|
JournalNatureStatementView.as_view(),
|
||||||
name="journal_nature_statement",
|
name="journal_nature_statement",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^journal/(?P<j_id>[0-9]+)/statement/person$",
|
"journal/<int:j_id>/statement/person/",
|
||||||
JournalPersonStatementView.as_view(),
|
JournalPersonStatementView.as_view(),
|
||||||
name="journal_person_statement",
|
name="journal_person_statement",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^journal/(?P<j_id>[0-9]+)/statement/accounting$",
|
"journal/<int:j_id>/statement/accounting/",
|
||||||
JournalAccountingStatementView.as_view(),
|
JournalAccountingStatementView.as_view(),
|
||||||
name="journal_accounting_statement",
|
name="journal_accounting_statement",
|
||||||
),
|
),
|
||||||
# Operations
|
# Operations
|
||||||
re_path(
|
path(
|
||||||
r"^operation/create/(?P<j_id>[0-9]+)$",
|
"operation/create/<int:j_id>/",
|
||||||
OperationCreateView.as_view(),
|
OperationCreateView.as_view(),
|
||||||
name="op_new",
|
name="op_new",
|
||||||
),
|
),
|
||||||
re_path(
|
path("operation/<int:op_id>/", OperationEditView.as_view(), name="op_edit"),
|
||||||
r"^operation/(?P<op_id>[0-9]+)$", OperationEditView.as_view(), name="op_edit"
|
path("operation/<int:op_id>/pdf/", OperationPDFView.as_view(), name="op_pdf"),
|
||||||
),
|
|
||||||
re_path(
|
|
||||||
r"^operation/(?P<op_id>[0-9]+)/pdf$", OperationPDFView.as_view(), name="op_pdf"
|
|
||||||
),
|
|
||||||
# Companies
|
# Companies
|
||||||
re_path(r"^company/list$", CompanyListView.as_view(), name="co_list"),
|
path("company/list/", CompanyListView.as_view(), name="co_list"),
|
||||||
re_path(r"^company/create$", CompanyCreateView.as_view(), name="co_new"),
|
path("company/create/", CompanyCreateView.as_view(), name="co_new"),
|
||||||
re_path(r"^company/(?P<co_id>[0-9]+)$", CompanyEditView.as_view(), name="co_edit"),
|
path("company/<int:co_id>/", CompanyEditView.as_view(), name="co_edit"),
|
||||||
# Labels
|
# Labels
|
||||||
re_path(r"^label/new$", LabelCreateView.as_view(), name="label_new"),
|
path("label/new/", LabelCreateView.as_view(), name="label_new"),
|
||||||
re_path(
|
path(
|
||||||
r"^label/(?P<clubaccount_id>[0-9]+)$",
|
"label/<int:clubaccount_id>/",
|
||||||
LabelListView.as_view(),
|
LabelListView.as_view(),
|
||||||
name="label_list",
|
name="label_list",
|
||||||
),
|
),
|
||||||
re_path(
|
path("label/<int:label_id>/edit/", LabelEditView.as_view(), name="label_edit"),
|
||||||
r"^label/(?P<label_id>[0-9]+)/edit$", LabelEditView.as_view(), name="label_edit"
|
path(
|
||||||
),
|
"label/<int:label_id>/delete/",
|
||||||
re_path(
|
|
||||||
r"^label/(?P<label_id>[0-9]+)/delete$",
|
|
||||||
LabelDeleteView.as_view(),
|
LabelDeleteView.as_view(),
|
||||||
name="label_delete",
|
name="label_delete",
|
||||||
),
|
),
|
||||||
# User account
|
# User account
|
||||||
re_path(r"^refound/account$", RefoundAccountView.as_view(), name="refound_account"),
|
path("refound/account/", RefoundAccountView.as_view(), name="refound_account"),
|
||||||
]
|
]
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -899,7 +891,7 @@ class RefoundAccountView(FormView):
|
|||||||
form_class = CloseCustomerAccountForm
|
form_class = CloseCustomerAccountForm
|
||||||
|
|
||||||
def permission(self, user):
|
def permission(self, user):
|
||||||
if user.is_root or user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
24
api/admin.py
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
24
api/tests.py
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
24
api/urls.py
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -32,7 +24,6 @@ from api.views import RightModelViewSet
|
|||||||
|
|
||||||
|
|
||||||
class CounterSerializer(serializers.ModelSerializer):
|
class CounterSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
is_open = serializers.BooleanField(read_only=True)
|
is_open = serializers.BooleanField(read_only=True)
|
||||||
barman_list = serializers.ListField(
|
barman_list = serializers.ListField(
|
||||||
child=serializers.IntegerField(), read_only=True
|
child=serializers.IntegerField(), read_only=True
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -32,7 +24,6 @@ from api.views import RightModelViewSet
|
|||||||
|
|
||||||
|
|
||||||
class LaunderettePlaceSerializer(serializers.ModelSerializer):
|
class LaunderettePlaceSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
machine_list = serializers.ListField(
|
machine_list = serializers.ListField(
|
||||||
child=serializers.IntegerField(), read_only=True
|
child=serializers.IntegerField(), read_only=True
|
||||||
)
|
)
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -1,31 +1,36 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
from ajax_select import make_ajax_form
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from club.models import Club, Membership
|
from club.models import Club, Membership
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Club)
|
@admin.register(Club)
|
||||||
admin.site.register(Membership)
|
class ClubAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("name", "unix_name", "parent", "is_active")
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Membership)
|
||||||
|
class MembershipAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("user", "club", "role", "start_date", "end_date")
|
||||||
|
search_fields = (
|
||||||
|
"user__username",
|
||||||
|
"user__first_name",
|
||||||
|
"user__last_name",
|
||||||
|
"club__name",
|
||||||
|
)
|
||||||
|
form = make_ajax_form(Membership, {"user": "users"})
|
||||||
|
@ -167,7 +167,6 @@ class SellingsForm(forms.Form):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, club, *args, **kwargs):
|
def __init__(self, club, *args, **kwargs):
|
||||||
|
|
||||||
super(SellingsForm, self).__init__(*args, **kwargs)
|
super(SellingsForm, self).__init__(*args, **kwargs)
|
||||||
self.fields["products"] = forms.ModelMultipleChoiceField(
|
self.fields["products"] = forms.ModelMultipleChoiceField(
|
||||||
club.products.order_by("name").filter(archived=False).all(),
|
club.products.order_by("name").filter(archived=False).all(),
|
||||||
@ -230,9 +229,7 @@ class ClubMemberForm(forms.Form):
|
|||||||
id__in=[
|
id__in=[
|
||||||
ms.user.id
|
ms.user.id
|
||||||
for ms in self.club_members
|
for ms in self.club_members
|
||||||
if ms.can_be_edited_by(
|
if ms.can_be_edited_by(self.request_user)
|
||||||
self.request_user, self.request_user_membership
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
).all(),
|
).all(),
|
||||||
label=_("Mark as old"),
|
label=_("Mark as old"),
|
||||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
("club", "0001_initial"),
|
("club", "0001_initial"),
|
||||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0002_auto_20160824_2152")]
|
dependencies = [("club", "0002_auto_20160824_2152")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0003_auto_20160902_2042")]
|
dependencies = [("club", "0003_auto_20160902_2042")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -6,7 +6,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0004_auto_20160915_1057")]
|
dependencies = [("club", "0004_auto_20160915_1057")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -6,7 +6,6 @@ import django.utils.timezone
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0005_auto_20161120_1149")]
|
dependencies = [("club", "0005_auto_20161120_1149")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0006_auto_20161229_0040")]
|
dependencies = [("club", "0006_auto_20161229_0040")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0007_auto_20170324_0917")]
|
dependencies = [("club", "0007_auto_20170324_0917")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -9,7 +9,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
("club", "0008_auto_20170515_2214"),
|
("club", "0008_auto_20170515_2214"),
|
||||||
|
@ -19,7 +19,6 @@ def generate_club_pages(apps, schema_editor):
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("core", "0024_auto_20170906_1317"), ("club", "0010_club_logo")]
|
dependencies = [("core", "0024_auto_20170906_1317"), ("club", "0010_club_logo")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0009_auto_20170822_2232")]
|
dependencies = [("club", "0009_auto_20170822_2232")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("club", "0010_auto_20170912_2028")]
|
dependencies = [("club", "0010_auto_20170912_2028")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
216
club/models.py
@ -22,10 +22,14 @@
|
|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from django.core.cache import cache
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError, ObjectDoesNotExist
|
from django.core.exceptions import ValidationError, ObjectDoesNotExist
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
@ -72,6 +76,7 @@ class Club(models.Model):
|
|||||||
_("short description"), max_length=1000, default="", blank=True, null=True
|
_("short description"), max_length=1000, default="", blank=True, null=True
|
||||||
)
|
)
|
||||||
address = models.CharField(_("address"), max_length=254)
|
address = models.CharField(_("address"), max_length=254)
|
||||||
|
|
||||||
# This function prevents generating migration upon settings change
|
# This function prevents generating migration upon settings change
|
||||||
def get_default_owner_group():
|
def get_default_owner_group():
|
||||||
return settings.SITH_GROUP_ROOT_ID
|
return settings.SITH_GROUP_ROOT_ID
|
||||||
@ -122,12 +127,22 @@ class Club(models.Model):
|
|||||||
def clean(self):
|
def clean(self):
|
||||||
self.check_loop()
|
self.check_loop()
|
||||||
|
|
||||||
def _change_unixname(self, new_name):
|
def _change_unixname(self, old_name, new_name):
|
||||||
c = Club.objects.filter(unix_name=new_name).first()
|
c = Club.objects.filter(unix_name=new_name).first()
|
||||||
if c is None:
|
if c is None:
|
||||||
|
# Update all the groups names
|
||||||
|
Group.objects.filter(name=old_name).update(name=new_name)
|
||||||
|
Group.objects.filter(name=old_name + settings.SITH_BOARD_SUFFIX).update(
|
||||||
|
name=new_name + settings.SITH_BOARD_SUFFIX
|
||||||
|
)
|
||||||
|
Group.objects.filter(name=old_name + settings.SITH_MEMBER_SUFFIX).update(
|
||||||
|
name=new_name + settings.SITH_MEMBER_SUFFIX
|
||||||
|
)
|
||||||
|
|
||||||
if self.home:
|
if self.home:
|
||||||
self.home.name = new_name
|
self.home.name = new_name
|
||||||
self.home.save()
|
self.home.save()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValidationError(_("A club with that unix_name already exists"))
|
raise ValidationError(_("A club with that unix_name already exists"))
|
||||||
|
|
||||||
@ -171,29 +186,34 @@ class Club(models.Model):
|
|||||||
self.page.parent = self.parent.page
|
self.page.parent = self.parent.page
|
||||||
self.page.save(force_lock=True)
|
self.page.save(force_lock=True)
|
||||||
|
|
||||||
|
@transaction.atomic()
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
with transaction.atomic():
|
old = Club.objects.filter(id=self.id).first()
|
||||||
creation = False
|
creation = old is None
|
||||||
old = Club.objects.filter(id=self.id).first()
|
if not creation and old.unix_name != self.unix_name:
|
||||||
if not old:
|
self._change_unixname(self.unix_name)
|
||||||
creation = True
|
super(Club, self).save(*args, **kwargs)
|
||||||
else:
|
if creation:
|
||||||
if old.unix_name != self.unix_name:
|
board = MetaGroup(name=self.unix_name + settings.SITH_BOARD_SUFFIX)
|
||||||
self._change_unixname(self.unix_name)
|
board.save()
|
||||||
super(Club, self).save(*args, **kwargs)
|
member = MetaGroup(name=self.unix_name + settings.SITH_MEMBER_SUFFIX)
|
||||||
if creation:
|
member.save()
|
||||||
board = MetaGroup(name=self.unix_name + settings.SITH_BOARD_SUFFIX)
|
subscribers = Group.objects.filter(
|
||||||
board.save()
|
name=settings.SITH_MAIN_MEMBERS_GROUP
|
||||||
member = MetaGroup(name=self.unix_name + settings.SITH_MEMBER_SUFFIX)
|
).first()
|
||||||
member.save()
|
self.make_home()
|
||||||
subscribers = Group.objects.filter(
|
self.home.edit_groups.set([board])
|
||||||
name=settings.SITH_MAIN_MEMBERS_GROUP
|
self.home.view_groups.set([member, subscribers])
|
||||||
).first()
|
self.home.save()
|
||||||
self.make_home()
|
self.make_page()
|
||||||
self.home.edit_groups.set([board])
|
cache.set(f"sith_club_{self.unix_name}", self)
|
||||||
self.home.view_groups.set([member, subscribers])
|
|
||||||
self.home.save()
|
def delete(self, *args, **kwargs):
|
||||||
self.make_page()
|
super().delete(*args, **kwargs)
|
||||||
|
# Invalidate the cache of this club and of its memberships
|
||||||
|
for membership in self.members.ongoing().select_related("user"):
|
||||||
|
cache.delete(f"membership_{self.id}_{membership.user.id}")
|
||||||
|
cache.delete(f"sith_club_{self.unix_name}")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -208,7 +228,9 @@ class Club(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be super edited by the given user
|
Method to see if that object can be super edited by the given user
|
||||||
"""
|
"""
|
||||||
return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
return user.is_board_member
|
||||||
|
|
||||||
def get_full_logo_url(self):
|
def get_full_logo_url(self):
|
||||||
return "https://%s%s" % (settings.SITH_URL, self.logo.url)
|
return "https://%s%s" % (settings.SITH_URL, self.logo.url)
|
||||||
@ -228,28 +250,89 @@ class Club(models.Model):
|
|||||||
return False
|
return False
|
||||||
return sub.was_subscribed
|
return sub.was_subscribed
|
||||||
|
|
||||||
_memberships = {}
|
def get_membership_for(self, user: User) -> Optional["Membership"]:
|
||||||
|
|
||||||
def get_membership_for(self, user):
|
|
||||||
"""
|
"""
|
||||||
Returns the current membership the given user
|
Return the current membership the given user.
|
||||||
|
The result is cached.
|
||||||
"""
|
"""
|
||||||
try:
|
if user.is_anonymous:
|
||||||
return Club._memberships[self.id][user.id]
|
return None
|
||||||
except:
|
membership = cache.get(f"membership_{self.id}_{user.id}")
|
||||||
m = self.members.filter(user=user.id).filter(end_date=None).first()
|
if membership == "not_member":
|
||||||
try:
|
return None
|
||||||
Club._memberships[self.id][user.id] = m
|
if membership is None:
|
||||||
except:
|
membership = self.members.filter(user=user, end_date=None).first()
|
||||||
Club._memberships[self.id] = {}
|
if membership is None:
|
||||||
Club._memberships[self.id][user.id] = m
|
cache.set(f"membership_{self.id}_{user.id}", "not_member")
|
||||||
return m
|
else:
|
||||||
|
cache.set(f"membership_{self.id}_{user.id}", membership)
|
||||||
|
return membership
|
||||||
|
|
||||||
def has_rights_in_club(self, user):
|
def has_rights_in_club(self, user):
|
||||||
m = self.get_membership_for(user)
|
m = self.get_membership_for(user)
|
||||||
return m is not None and m.role > settings.SITH_MAXIMUM_FREE_ROLE
|
return m is not None and m.role > settings.SITH_MAXIMUM_FREE_ROLE
|
||||||
|
|
||||||
|
|
||||||
|
class MembershipQuerySet(models.QuerySet):
|
||||||
|
def ongoing(self) -> "MembershipQuerySet":
|
||||||
|
"""
|
||||||
|
Filter all memberships which are not finished yet
|
||||||
|
"""
|
||||||
|
# noinspection PyTypeChecker
|
||||||
|
return self.filter(Q(end_date=None) | Q(end_date__gte=timezone.now()))
|
||||||
|
|
||||||
|
def board(self) -> "MembershipQuerySet":
|
||||||
|
"""
|
||||||
|
Filter all memberships where the user is/was in the board.
|
||||||
|
|
||||||
|
Be aware that users who were in the board in the past
|
||||||
|
are included, even if there are no more members.
|
||||||
|
|
||||||
|
If you want to get the users who are currently in the board,
|
||||||
|
mind combining this with the :meth:`ongoing` queryset method
|
||||||
|
"""
|
||||||
|
# noinspection PyTypeChecker
|
||||||
|
return self.filter(role__gt=settings.SITH_MAXIMUM_FREE_ROLE)
|
||||||
|
|
||||||
|
def update(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Work just like the default Django's update() method,
|
||||||
|
but add a cache refresh for the elements of the queryset.
|
||||||
|
|
||||||
|
Be aware that this adds a db query to retrieve the updated objects
|
||||||
|
"""
|
||||||
|
nb_rows = super().update(**kwargs)
|
||||||
|
if nb_rows > 0:
|
||||||
|
# if at least a row was affected, refresh the cache
|
||||||
|
for membership in self.all():
|
||||||
|
if membership.end_date is not None:
|
||||||
|
cache.set(
|
||||||
|
f"membership_{membership.club_id}_{membership.user_id}",
|
||||||
|
"not_member",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cache.set(
|
||||||
|
f"membership_{membership.club_id}_{membership.user_id}",
|
||||||
|
membership,
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
"""
|
||||||
|
Work just like the default Django's delete() method,
|
||||||
|
but add a cache invalidation for the elements of the queryset
|
||||||
|
before the deletion.
|
||||||
|
|
||||||
|
Be aware that this adds a db query to retrieve the deleted element.
|
||||||
|
As this first query take place before the deletion operation,
|
||||||
|
it will be performed even if the deletion fails.
|
||||||
|
"""
|
||||||
|
ids = list(self.values_list("club_id", "user_id"))
|
||||||
|
nb_rows, _ = super().delete()
|
||||||
|
if nb_rows > 0:
|
||||||
|
for club_id, user_id in ids:
|
||||||
|
cache.set(f"membership_{club_id}_{user_id}", "not_member")
|
||||||
|
|
||||||
|
|
||||||
class Membership(models.Model):
|
class Membership(models.Model):
|
||||||
"""
|
"""
|
||||||
The Membership class makes the connection between User and Clubs
|
The Membership class makes the connection between User and Clubs
|
||||||
@ -289,6 +372,8 @@ class Membership(models.Model):
|
|||||||
_("description"), max_length=128, null=False, blank=True
|
_("description"), max_length=128, null=False, blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = MembershipQuerySet.as_manager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (
|
return (
|
||||||
self.club.name
|
self.club.name
|
||||||
@ -303,24 +388,34 @@ class Membership(models.Model):
|
|||||||
"""
|
"""
|
||||||
Method to see if that object can be super edited by the given user
|
Method to see if that object can be super edited by the given user
|
||||||
"""
|
"""
|
||||||
return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
return user.is_board_member
|
||||||
|
|
||||||
def can_be_edited_by(self, user, membership=None):
|
def can_be_edited_by(self, user: User) -> bool:
|
||||||
"""
|
"""
|
||||||
Method to see if that object can be edited by the given user
|
Check if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
if user.memberships:
|
if user.is_root or user.is_board_member:
|
||||||
if membership: # This is for optimisation purpose
|
return True
|
||||||
ms = membership
|
membership = self.club.get_membership_for(user)
|
||||||
else:
|
if membership is not None and membership.role >= self.role:
|
||||||
ms = user.memberships.filter(club=self.club, end_date=None).first()
|
return True
|
||||||
return (ms and ms.role >= self.role) or user.is_in_group(
|
return False
|
||||||
settings.SITH_MAIN_BOARD_GROUP
|
|
||||||
)
|
|
||||||
return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("club:club_members", kwargs={"club_id": self.club.id})
|
return reverse("club:club_members", kwargs={"club_id": self.club_id})
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
if self.end_date is None:
|
||||||
|
cache.set(f"membership_{self.club_id}_{self.user_id}", self)
|
||||||
|
else:
|
||||||
|
cache.set(f"membership_{self.club_id}_{self.user_id}", "not_member")
|
||||||
|
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
super().delete(*args, **kwargs)
|
||||||
|
cache.delete(f"membership_{self.club_id}_{self.user_id}")
|
||||||
|
|
||||||
|
|
||||||
class Mailing(models.Model):
|
class Mailing(models.Model):
|
||||||
@ -373,14 +468,12 @@ class Mailing(models.Model):
|
|||||||
return self.email + "@" + settings.SITH_MAILING_DOMAIN
|
return self.email + "@" + settings.SITH_MAILING_DOMAIN
|
||||||
|
|
||||||
def can_moderate(self, user):
|
def can_moderate(self, user):
|
||||||
return user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return user.is_root or user.is_com_admin
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return (
|
if user.is_anonymous:
|
||||||
user.is_in_group(self)
|
return False
|
||||||
or user.is_root
|
return user.is_root or user.is_com_admin
|
||||||
or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
|
||||||
)
|
|
||||||
|
|
||||||
def can_view(self, user):
|
def can_view(self, user):
|
||||||
return self.club.has_rights_in_club(user)
|
return self.club.has_rights_in_club(user)
|
||||||
@ -388,9 +481,8 @@ class Mailing(models.Model):
|
|||||||
def can_be_edited_by(self, user):
|
def can_be_edited_by(self, user):
|
||||||
return self.club.has_rights_in_club(user)
|
return self.club.has_rights_in_club(user)
|
||||||
|
|
||||||
def delete(self):
|
def delete(self, *args, **kwargs):
|
||||||
for sub in self.subscriptions.all():
|
self.subscriptions.all().delete()
|
||||||
sub.delete()
|
|
||||||
super(Mailing, self).delete()
|
super(Mailing, self).delete()
|
||||||
|
|
||||||
def fetch_format(self):
|
def fetch_format(self):
|
||||||
@ -463,10 +555,12 @@ class MailingSubscription(models.Model):
|
|||||||
super(MailingSubscription, self).clean()
|
super(MailingSubscription, self).clean()
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
return (
|
return (
|
||||||
self.mailing.club.has_rights_in_club(user)
|
self.mailing.club.has_rights_in_club(user)
|
||||||
or user.is_root
|
or user.is_root
|
||||||
or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
or self.user.is_com_admin
|
||||||
)
|
)
|
||||||
|
|
||||||
def can_be_edited_by(self, user):
|
def can_be_edited_by(self, user):
|
||||||
|
@ -13,13 +13,15 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<td>{% trans %}User{% endtrans %}</td>
|
<tr>
|
||||||
<td>{% trans %}Role{% endtrans %}</td>
|
<td>{% trans %}User{% endtrans %}</td>
|
||||||
<td>{% trans %}Description{% endtrans %}</td>
|
<td>{% trans %}Role{% endtrans %}</td>
|
||||||
<td>{% trans %}Since{% endtrans %}</td>
|
<td>{% trans %}Description{% endtrans %}</td>
|
||||||
{% if users_old %}
|
<td>{% trans %}Since{% endtrans %}</td>
|
||||||
<td>{% trans %}Mark as old{% endtrans %}</td>
|
{% if users_old %}
|
||||||
{% endif %}
|
<td>{% trans %}Mark as old{% endtrans %}</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for m in members %}
|
{% for m in members %}
|
||||||
|
795
club/tests.py
@ -1,396 +1,576 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.cache import cache
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import timezone, html
|
from django.utils import timezone, html
|
||||||
|
from django.utils.timezone import now, localtime
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
|
|
||||||
|
|
||||||
from core.models import User
|
from core.models import User, AnonymousUser
|
||||||
from club.models import Club, Membership, Mailing
|
from club.models import Club, Membership, Mailing
|
||||||
from club.forms import MailingForm
|
from club.forms import MailingForm
|
||||||
|
from sith.settings import SITH_BAR_MANAGER, SITH_MAIN_CLUB_ID
|
||||||
# Create your tests here.
|
|
||||||
|
|
||||||
|
|
||||||
class ClubTest(TestCase):
|
class ClubTest(TestCase):
|
||||||
|
"""
|
||||||
|
Set up data for test cases related to clubs and membership
|
||||||
|
The generated dataset is the one created by the populate command,
|
||||||
|
plus the following modifications :
|
||||||
|
|
||||||
|
- `self.club` is a dummy club recreated for each test
|
||||||
|
- `self.club` has two board members : skia (role 3) and comptable (role 10)
|
||||||
|
- `self.club` has one regular member : richard
|
||||||
|
- `self.club` has one former member : sli (who had role 2)
|
||||||
|
- None of the `self.club` members are in the AE club.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
# subscribed users - initial members
|
||||||
|
cls.skia = User.objects.get(username="skia")
|
||||||
|
cls.richard = User.objects.get(username="rbatsbak")
|
||||||
|
cls.comptable = User.objects.get(username="comptable")
|
||||||
|
cls.sli = User.objects.get(username="sli")
|
||||||
|
|
||||||
|
# subscribed users - not initial members
|
||||||
|
cls.krophil = User.objects.get(username="krophil")
|
||||||
|
cls.subscriber = User.objects.get(username="subscriber")
|
||||||
|
|
||||||
|
# old subscriber
|
||||||
|
cls.old_subscriber = User.objects.get(username="old_subscriber")
|
||||||
|
|
||||||
|
# not subscribed
|
||||||
|
cls.public = User.objects.get(username="public")
|
||||||
|
|
||||||
|
cls.ae = Club.objects.filter(pk=SITH_MAIN_CLUB_ID)[0]
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
# by default, Skia is in the AE, which creates side effect
|
||||||
self.skia = User.objects.filter(username="skia").first()
|
self.skia.memberships.all().delete()
|
||||||
self.rbatsbak = User.objects.filter(username="rbatsbak").first()
|
|
||||||
self.guy = User.objects.filter(username="guy").first()
|
|
||||||
self.bdf = Club.objects.filter(unix_name="bdf").first()
|
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_root_ok(self):
|
# create a fake club
|
||||||
self.client.login(username="root", password="plop")
|
self.club = Club.objects.create(
|
||||||
self.client.post(
|
name="Fake Club",
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
unix_name="fake-club",
|
||||||
{"users": self.skia.id, "start_date": "12/06/2016", "role": 3},
|
address="5 rue de la République, 90000 Belfort",
|
||||||
)
|
)
|
||||||
response = self.client.get(
|
self.members_url = reverse(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
"club:club_members", kwargs={"club_id": self.club.id}
|
||||||
)
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
a_month_ago = now() - timedelta(days=30)
|
||||||
self.assertTrue(
|
yesterday = now() - timedelta(days=1)
|
||||||
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
Membership.objects.create(
|
||||||
in str(response.content)
|
club=self.club, user=self.skia, start_date=a_month_ago, role=3
|
||||||
|
)
|
||||||
|
Membership.objects.create(club=self.club, user=self.richard, role=1)
|
||||||
|
Membership.objects.create(
|
||||||
|
club=self.club, user=self.comptable, start_date=a_month_ago, role=10
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_add_multiple_user_to_club_from_root_ok(self):
|
# sli was a member but isn't anymore
|
||||||
|
Membership.objects.create(
|
||||||
|
club=self.club,
|
||||||
|
user=self.sli,
|
||||||
|
start_date=a_month_ago,
|
||||||
|
end_date=yesterday,
|
||||||
|
role=2,
|
||||||
|
)
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
|
|
||||||
|
class MembershipQuerySetTest(ClubTest):
|
||||||
|
def test_ongoing(self):
|
||||||
|
"""
|
||||||
|
Test that the ongoing queryset method returns the memberships that
|
||||||
|
are not ended.
|
||||||
|
"""
|
||||||
|
current_members = self.club.members.ongoing()
|
||||||
|
expected = [
|
||||||
|
self.skia.memberships.get(club=self.club),
|
||||||
|
self.comptable.memberships.get(club=self.club),
|
||||||
|
self.richard.memberships.get(club=self.club),
|
||||||
|
]
|
||||||
|
self.assertEqual(len(current_members), len(expected))
|
||||||
|
for member in current_members:
|
||||||
|
self.assertIn(member, expected)
|
||||||
|
|
||||||
|
def test_board(self):
|
||||||
|
"""
|
||||||
|
Test that the board queryset method returns the memberships
|
||||||
|
of user in the club board
|
||||||
|
"""
|
||||||
|
board_members = list(self.club.members.board())
|
||||||
|
expected = [
|
||||||
|
self.skia.memberships.get(club=self.club),
|
||||||
|
self.comptable.memberships.get(club=self.club),
|
||||||
|
# sli is no more member, but he was in the board
|
||||||
|
self.sli.memberships.get(club=self.club),
|
||||||
|
]
|
||||||
|
self.assertEqual(len(board_members), len(expected))
|
||||||
|
for member in board_members:
|
||||||
|
self.assertIn(member, expected)
|
||||||
|
|
||||||
|
def test_ongoing_board(self):
|
||||||
|
"""
|
||||||
|
Test that combining ongoing and board returns users
|
||||||
|
who are currently board members of the club
|
||||||
|
"""
|
||||||
|
members = list(self.club.members.ongoing().board())
|
||||||
|
expected = [
|
||||||
|
self.skia.memberships.get(club=self.club),
|
||||||
|
self.comptable.memberships.get(club=self.club),
|
||||||
|
]
|
||||||
|
self.assertEqual(len(members), len(expected))
|
||||||
|
for member in members:
|
||||||
|
self.assertIn(member, expected)
|
||||||
|
|
||||||
|
def test_update_invalidate_cache(self):
|
||||||
|
"""
|
||||||
|
Test that the `update` queryset method properly invalidate cache
|
||||||
|
"""
|
||||||
|
mem_skia = self.skia.memberships.get(club=self.club)
|
||||||
|
cache.set(f"membership_{mem_skia.club_id}_{mem_skia.user_id}", mem_skia)
|
||||||
|
self.skia.memberships.update(end_date=localtime(now()).date())
|
||||||
|
self.assertEqual(
|
||||||
|
cache.get(f"membership_{mem_skia.club_id}_{mem_skia.user_id}"), "not_member"
|
||||||
|
)
|
||||||
|
|
||||||
|
mem_richard = self.richard.memberships.get(club=self.club)
|
||||||
|
cache.set(
|
||||||
|
f"membership_{mem_richard.club_id}_{mem_richard.user_id}", mem_richard
|
||||||
|
)
|
||||||
|
self.richard.memberships.update(role=5)
|
||||||
|
new_mem = self.richard.memberships.get(club=self.club)
|
||||||
|
self.assertNotEqual(new_mem, "not_member")
|
||||||
|
self.assertEqual(new_mem.role, 5)
|
||||||
|
|
||||||
|
def test_delete_invalidate_cache(self):
|
||||||
|
"""
|
||||||
|
Test that the `delete` queryset properly invalidate cache
|
||||||
|
"""
|
||||||
|
|
||||||
|
mem_skia = self.skia.memberships.get(club=self.club)
|
||||||
|
mem_comptable = self.comptable.memberships.get(club=self.club)
|
||||||
|
cache.set(f"membership_{mem_skia.club_id}_{mem_skia.user_id}", mem_skia)
|
||||||
|
cache.set(
|
||||||
|
f"membership_{mem_comptable.club_id}_{mem_comptable.user_id}", mem_comptable
|
||||||
|
)
|
||||||
|
|
||||||
|
# should delete the subscriptions of skia and comptable
|
||||||
|
self.club.members.ongoing().board().delete()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
cache.get(f"membership_{mem_skia.club_id}_{mem_skia.user_id}"), "not_member"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
cache.get(f"membership_{mem_comptable.club_id}_{mem_comptable.user_id}"),
|
||||||
|
"not_member",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ClubModelTest(ClubTest):
|
||||||
|
def assert_membership_just_started(self, user: User, role: int):
|
||||||
|
"""
|
||||||
|
Assert that the given membership is active and started today
|
||||||
|
"""
|
||||||
|
membership = user.memberships.ongoing().filter(club=self.club).first()
|
||||||
|
self.assertIsNotNone(membership)
|
||||||
|
self.assertEqual(localtime(now()).date(), membership.start_date)
|
||||||
|
self.assertIsNone(membership.end_date)
|
||||||
|
self.assertEqual(membership.role, role)
|
||||||
|
self.assertEqual(membership.club.get_membership_for(user), membership)
|
||||||
|
member_group = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
|
||||||
|
board_group = self.club.unix_name + settings.SITH_BOARD_SUFFIX
|
||||||
|
self.assertTrue(user.is_in_group(name=member_group))
|
||||||
|
self.assertTrue(user.is_in_group(name=board_group))
|
||||||
|
|
||||||
|
def assert_membership_just_ended(self, user: User):
|
||||||
|
"""
|
||||||
|
Assert that the given user have a membership which ended today
|
||||||
|
"""
|
||||||
|
today = localtime(now()).date()
|
||||||
|
self.assertIsNotNone(
|
||||||
|
user.memberships.filter(club=self.club, end_date=today).first()
|
||||||
|
)
|
||||||
|
self.assertIsNone(self.club.get_membership_for(user))
|
||||||
|
|
||||||
|
def test_access_unauthorized(self):
|
||||||
|
"""
|
||||||
|
Test that users who never subscribed and anonymous users
|
||||||
|
cannot see the page
|
||||||
|
"""
|
||||||
|
response = self.client.post(self.members_url)
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
self.client.login(username="public", password="plop")
|
||||||
|
response = self.client.post(self.members_url)
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
def test_display(self):
|
||||||
|
"""
|
||||||
|
Test that a GET request return a page where the requested
|
||||||
|
information are displayed.
|
||||||
|
"""
|
||||||
|
self.client.login(username=self.skia.username, password="plop")
|
||||||
|
response = self.client.get(self.members_url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
expected_html = (
|
||||||
|
"<table><thead><tr>"
|
||||||
|
"<td>Utilisateur</td><td>Rôle</td><td>Description</td>"
|
||||||
|
"<td>Depuis</td><td>Marquer comme ancien</td>"
|
||||||
|
"</tr></thead><tbody>"
|
||||||
|
)
|
||||||
|
memberships = self.club.members.ongoing().order_by("-role")
|
||||||
|
input_id = 0
|
||||||
|
for membership in memberships.select_related("user"):
|
||||||
|
user = membership.user
|
||||||
|
expected_html += (
|
||||||
|
f"<tr><td><a href=\"{reverse('core:user_profile', args=[user.id])}\">"
|
||||||
|
f"{user.get_display_name()}</a></td>"
|
||||||
|
f"<td>{settings.SITH_CLUB_ROLES[membership.role]}</td>"
|
||||||
|
f"<td>{membership.description}</td>"
|
||||||
|
f"<td>{membership.start_date}</td><td>"
|
||||||
|
)
|
||||||
|
if membership.role <= 3: # 3 is the role of skia
|
||||||
|
expected_html += (
|
||||||
|
'<input type="checkbox" name="users_old" '
|
||||||
|
f'value="{user.id}" '
|
||||||
|
f'id="id_users_old_{input_id}">'
|
||||||
|
)
|
||||||
|
input_id += 1
|
||||||
|
expected_html += "</td></tr>"
|
||||||
|
expected_html += "</tbody></table>"
|
||||||
|
self.assertInHTML(expected_html, response.content.decode())
|
||||||
|
|
||||||
|
def test_root_add_one_club_member(self):
|
||||||
|
"""
|
||||||
|
Test that root users can add members to clubs, one at a time
|
||||||
|
"""
|
||||||
self.client.login(username="root", password="plop")
|
self.client.login(username="root", password="plop")
|
||||||
self.client.post(
|
response = self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
|
{"users": self.subscriber.id, "role": 3},
|
||||||
|
)
|
||||||
|
self.assertRedirects(response, self.members_url)
|
||||||
|
self.subscriber.refresh_from_db()
|
||||||
|
self.assert_membership_just_started(self.subscriber, role=3)
|
||||||
|
|
||||||
|
def test_root_add_multiple_club_member(self):
|
||||||
|
"""
|
||||||
|
Test that root users can add multiple members at once to clubs
|
||||||
|
"""
|
||||||
|
self.client.login(username="root", password="plop")
|
||||||
|
response = self.client.post(
|
||||||
|
self.members_url,
|
||||||
{
|
{
|
||||||
"users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
|
"users": f"|{self.subscriber.id}|{self.krophil.id}|",
|
||||||
"start_date": "12/06/2016",
|
|
||||||
"role": 3,
|
"role": 3,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
response = self.client.get(
|
self.assertRedirects(response, self.members_url)
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
self.subscriber.refresh_from_db()
|
||||||
)
|
self.assert_membership_just_started(self.subscriber, role=3)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assert_membership_just_started(self.krophil, role=3)
|
||||||
content = str(response.content)
|
|
||||||
self.assertTrue(
|
|
||||||
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in content
|
|
||||||
)
|
|
||||||
self.assertTrue(
|
|
||||||
"Richard Batsbak</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in content
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_root_fail_not_subscriber(self):
|
def test_add_unauthorized_members(self):
|
||||||
|
"""
|
||||||
|
Test that users who are not currently subscribed
|
||||||
|
cannot be members of clubs.
|
||||||
|
"""
|
||||||
self.client.login(username="root", password="plop")
|
self.client.login(username="root", password="plop")
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{"users": self.guy.id, "start_date": "12/06/2016", "role": 3},
|
{"users": self.public.id, "role": 1},
|
||||||
)
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertIsNone(self.public.memberships.filter(club=self.club).first())
|
||||||
self.assertTrue('<ul class="errorlist"><li>' in str(response.content))
|
self.assertTrue('<ul class="errorlist"><li>' in str(response.content))
|
||||||
response = self.client.get(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
|
||||||
)
|
|
||||||
self.assertFalse(
|
|
||||||
"Guy Carlier</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in str(response.content)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_root_fail_already_in_club(self):
|
response = self.client.post(
|
||||||
|
self.members_url,
|
||||||
|
{"users": self.old_subscriber.id, "role": 1},
|
||||||
|
)
|
||||||
|
self.assertIsNone(self.public.memberships.filter(club=self.club).first())
|
||||||
|
self.assertIsNone(self.club.get_membership_for(self.public))
|
||||||
|
self.assertTrue('<ul class="errorlist"><li>' in str(response.content))
|
||||||
|
|
||||||
|
def test_add_members_already_members(self):
|
||||||
|
"""
|
||||||
|
Test that users who are already members of a club
|
||||||
|
cannot be added again to this club
|
||||||
|
"""
|
||||||
self.client.login(username="root", password="plop")
|
self.client.login(username="root", password="plop")
|
||||||
|
current_membership = self.skia.memberships.ongoing().get(club=self.club)
|
||||||
|
nb_memberships = self.skia.memberships.count()
|
||||||
self.client.post(
|
self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{"users": self.skia.id, "start_date": "12/06/2016", "role": 3},
|
{"users": self.skia.id, "role": current_membership.role + 1},
|
||||||
)
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
|
||||||
)
|
|
||||||
self.assertTrue(
|
|
||||||
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in str(response.content)
|
|
||||||
)
|
|
||||||
response = self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users": self.skia.id, "start_date": "12/06/2016", "role": 4},
|
|
||||||
)
|
|
||||||
self.assertTrue(response.status_code == 200)
|
|
||||||
self.assertFalse(
|
|
||||||
"S' Kia</a></td>\\n <td>Secrétaire</td>"
|
|
||||||
in str(response.content)
|
|
||||||
)
|
)
|
||||||
|
self.skia.refresh_from_db()
|
||||||
|
self.assertEqual(nb_memberships, self.skia.memberships.count())
|
||||||
|
new_membership = self.skia.memberships.ongoing().get(club=self.club)
|
||||||
|
self.assertEqual(current_membership, new_membership)
|
||||||
|
self.assertEqual(self.club.get_membership_for(self.skia), new_membership)
|
||||||
|
|
||||||
def test_create_add_user_non_existent_to_club_from_root_fail(self):
|
def test_add_not_existing_users(self):
|
||||||
|
"""
|
||||||
|
Test that not existing users cannot be added in clubs.
|
||||||
|
If one user in the request is invalid, no membership creation at all
|
||||||
|
can take place.
|
||||||
|
"""
|
||||||
self.client.login(username="root", password="plop")
|
self.client.login(username="root", password="plop")
|
||||||
|
nb_memberships = self.club.members.count()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{"users": [9999], "start_date": "12/06/2016", "role": 3},
|
{"users": [9999], "role": 1},
|
||||||
)
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertContains(response, '<ul class="errorlist"><li>')
|
||||||
content = str(response.content)
|
self.club.refresh_from_db()
|
||||||
self.assertTrue('<ul class="errorlist"><li>' in content)
|
self.assertEqual(self.club.members.count(), nb_memberships)
|
||||||
self.assertFalse("<td>Responsable info</td>" in content)
|
|
||||||
self.client.login(username="root", password="plop")
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{
|
{
|
||||||
"users": "|%d|%d|" % (self.skia.id, 9999),
|
"users": f"|{self.subscriber.id}|{9999}|",
|
||||||
"start_date": "12/06/2016",
|
"start_date": "12/06/2016",
|
||||||
"role": 3,
|
"role": 3,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertContains(response, '<ul class="errorlist"><li>')
|
||||||
content = str(response.content)
|
self.club.refresh_from_db()
|
||||||
self.assertTrue('<ul class="errorlist"><li>' in content)
|
self.assertEqual(self.club.members.count(), nb_memberships)
|
||||||
self.assertFalse("<td>Responsable info</td>" in content)
|
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_skia_ok(self):
|
def test_president_add_members(self):
|
||||||
self.client.login(username="root", password="plop")
|
"""
|
||||||
self.client.post(
|
Test that the president of the club can add members
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
"""
|
||||||
{"users": self.skia.id, "start_date": "12/06/2016", "role": 10},
|
president = self.club.members.get(role=10).user
|
||||||
|
nb_club_membership = self.club.members.count()
|
||||||
|
nb_subscriber_memberships = self.subscriber.memberships.count()
|
||||||
|
self.client.login(username=president.username, password="plop")
|
||||||
|
response = self.client.post(
|
||||||
|
self.members_url,
|
||||||
|
{"users": self.subscriber.id, "role": 9},
|
||||||
)
|
)
|
||||||
self.client.login(username="skia", password="plop")
|
self.assertRedirects(response, self.members_url)
|
||||||
self.client.post(
|
self.club.refresh_from_db()
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.subscriber.refresh_from_db()
|
||||||
{"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 9},
|
self.assertEqual(self.club.members.count(), nb_club_membership + 1)
|
||||||
|
self.assertEqual(
|
||||||
|
self.subscriber.memberships.count(), nb_subscriber_memberships + 1
|
||||||
)
|
)
|
||||||
response = self.client.get(
|
self.assert_membership_just_started(self.subscriber, role=9)
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
|
||||||
|
def test_add_member_greater_role(self):
|
||||||
|
"""
|
||||||
|
Test that a member of the club member cannot create
|
||||||
|
a membership with a greater role than its own.
|
||||||
|
"""
|
||||||
|
self.client.login(username=self.skia.username, password="plop")
|
||||||
|
nb_memberships = self.club.members.count()
|
||||||
|
response = self.client.post(
|
||||||
|
self.members_url,
|
||||||
|
{"users": self.subscriber.id, "role": 10},
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertIn(
|
self.assertInHTML(
|
||||||
"""Richard Batsbak</a></td>\n <td>Vice-Président⸱e</td>""",
|
"<li>Vous n'avez pas la permission de faire cela</li>",
|
||||||
response.content.decode(),
|
response.content.decode(),
|
||||||
)
|
)
|
||||||
|
self.club.refresh_from_db()
|
||||||
|
self.assertEqual(nb_memberships, self.club.members.count())
|
||||||
|
self.assertIsNone(self.subscriber.memberships.filter(club=self.club).first())
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_richard_fail(self):
|
def test_add_member_without_role(self):
|
||||||
self.client.login(username="root", password="plop")
|
"""
|
||||||
self.client.post(
|
Test that trying to add members without specifying their role fails
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
"""
|
||||||
{"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 3},
|
|
||||||
)
|
|
||||||
self.client.login(username="rbatsbak", password="plop")
|
|
||||||
response = self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users": self.skia.id, "start_date": "12/06/2016", "role": 10},
|
|
||||||
)
|
|
||||||
self.assertTrue(response.status_code == 200)
|
|
||||||
self.assertTrue(
|
|
||||||
"<li>Vous n'avez pas la permission de faire cela</li>"
|
|
||||||
in str(response.content)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_role_required_if_users_specified(self):
|
|
||||||
self.client.login(username="root", password="plop")
|
self.client.login(username="root", password="plop")
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{"users": self.rbatsbak.id, "start_date": "12/06/2016"},
|
{"users": self.subscriber.id, "start_date": "12/06/2016"},
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
'<ul class="errorlist"><li>Vous devez choisir un r' in str(response.content)
|
'<ul class="errorlist"><li>Vous devez choisir un r' in str(response.content)
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_mark_old_user_to_club_from_skia_ok(self):
|
def test_end_membership_self(self):
|
||||||
self.client.login(username="root", password="plop")
|
"""
|
||||||
self.client.post(
|
Test that a member can end its own membership
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
"""
|
||||||
{
|
|
||||||
"users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
|
|
||||||
"start_date": "12/06/2016",
|
|
||||||
"role": 3,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.client.login(username="skia", password="plop")
|
self.client.login(username="skia", password="plop")
|
||||||
response = self.client.post(
|
self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{"users_old": self.rbatsbak.id},
|
|
||||||
)
|
|
||||||
self.assertTrue(response.status_code == 302)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
|
||||||
)
|
|
||||||
self.assertTrue(response.status_code == 200)
|
|
||||||
content = str(response.content)
|
|
||||||
self.assertFalse(
|
|
||||||
"Richard Batsbak</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in content
|
|
||||||
)
|
|
||||||
self.assertTrue(
|
|
||||||
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in content
|
|
||||||
)
|
|
||||||
|
|
||||||
# Skia is board member so he should be able to mark as old even without being in the club
|
|
||||||
response = self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users_old": self.skia.id},
|
{"users_old": self.skia.id},
|
||||||
)
|
)
|
||||||
|
self.skia.refresh_from_db()
|
||||||
|
self.assert_membership_just_ended(self.skia)
|
||||||
|
|
||||||
|
def test_end_membership_lower_role(self):
|
||||||
|
"""
|
||||||
|
Test that board members of the club can end memberships
|
||||||
|
of users with lower roles
|
||||||
|
"""
|
||||||
|
# remainder : skia has role 3, comptable has role 10, richard has role 1
|
||||||
|
self.client.login(username=self.skia.username, password="plop")
|
||||||
|
response = self.client.post(
|
||||||
|
self.members_url,
|
||||||
|
{"users_old": self.richard.id},
|
||||||
|
)
|
||||||
|
self.assertRedirects(response, self.members_url)
|
||||||
|
self.club.refresh_from_db()
|
||||||
|
self.assert_membership_just_ended(self.richard)
|
||||||
|
|
||||||
|
def test_end_membership_higher_role(self):
|
||||||
|
"""
|
||||||
|
Test that board members of the club cannot end memberships
|
||||||
|
of users with higher roles
|
||||||
|
"""
|
||||||
|
membership = self.comptable.memberships.filter(club=self.club).first()
|
||||||
|
self.client.login(username=self.skia.username, password="plop")
|
||||||
|
self.client.post(
|
||||||
|
self.members_url,
|
||||||
|
{"users_old": self.comptable.id},
|
||||||
|
)
|
||||||
|
self.club.refresh_from_db()
|
||||||
|
new_membership = self.club.get_membership_for(self.comptable)
|
||||||
|
self.assertIsNotNone(new_membership)
|
||||||
|
self.assertEqual(new_membership, membership)
|
||||||
|
|
||||||
|
membership = self.comptable.memberships.filter(club=self.club).first()
|
||||||
|
self.assertIsNone(membership.end_date)
|
||||||
|
|
||||||
|
def test_end_membership_as_main_club_board(self):
|
||||||
|
"""
|
||||||
|
Test that board members of the main club can end the membership
|
||||||
|
of anyone
|
||||||
|
"""
|
||||||
|
# make subscriber a board member
|
||||||
|
self.subscriber.memberships.all().delete()
|
||||||
|
Membership.objects.create(club=self.ae, user=self.subscriber, role=3)
|
||||||
|
|
||||||
|
nb_memberships = self.club.members.count()
|
||||||
|
self.client.login(username=self.subscriber.username, password="plop")
|
||||||
|
response = self.client.post(
|
||||||
|
self.members_url,
|
||||||
|
{"users_old": self.comptable.id},
|
||||||
|
)
|
||||||
|
self.assertRedirects(response, self.members_url)
|
||||||
|
self.assert_membership_just_ended(self.comptable)
|
||||||
|
self.assertEqual(self.club.members.ongoing().count(), nb_memberships - 1)
|
||||||
|
|
||||||
|
def test_end_membership_as_root(self):
|
||||||
|
"""
|
||||||
|
Test that root users can end the membership of anyone
|
||||||
|
"""
|
||||||
|
nb_memberships = self.club.members.count()
|
||||||
self.client.login(username="root", password="plop")
|
self.client.login(username="root", password="plop")
|
||||||
self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 3},
|
|
||||||
)
|
|
||||||
self.client.login(username="skia", password="plop")
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{"users_old": self.rbatsbak.id},
|
{"users_old": [self.comptable.id]},
|
||||||
)
|
|
||||||
self.assertFalse(
|
|
||||||
"Richard Batsbak</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in str(response.content)
|
|
||||||
)
|
)
|
||||||
|
self.assertRedirects(response, self.members_url)
|
||||||
|
self.assert_membership_just_ended(self.comptable)
|
||||||
|
self.assertEqual(self.club.members.ongoing().count(), nb_memberships - 1)
|
||||||
|
self.assertEqual(self.club.members.count(), nb_memberships)
|
||||||
|
|
||||||
def test_mark_old_multiple_users_from_skia_ok(self):
|
def test_end_membership_as_foreigner(self):
|
||||||
self.client.login(username="root", password="plop")
|
"""
|
||||||
|
Test that users who are not in this club cannot end its memberships
|
||||||
|
"""
|
||||||
|
nb_memberships = self.club.members.count()
|
||||||
|
membership = self.richard.memberships.filter(club=self.club).first()
|
||||||
|
self.client.login(username="subscriber", password="root")
|
||||||
self.client.post(
|
self.client.post(
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.members_url,
|
||||||
{
|
{"users_old": [self.richard.id]},
|
||||||
"users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
|
|
||||||
"start_date": "12/06/2016",
|
|
||||||
"role": 3,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
self.client.login(username="skia", password="plop")
|
# nothing should have changed
|
||||||
response = self.client.post(
|
new_mem = self.club.get_membership_for(self.richard)
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.assertIsNotNone(new_mem)
|
||||||
{"users_old": [self.rbatsbak.id, self.skia.id]},
|
self.assertEqual(self.club.members.count(), nb_memberships)
|
||||||
)
|
self.assertEqual(membership, new_mem)
|
||||||
self.assertTrue(response.status_code == 302)
|
|
||||||
|
|
||||||
response = self.client.get(
|
def test_delete_remove_from_meta_group(self):
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
"""
|
||||||
)
|
Test that when a club is deleted, all its members are removed from the
|
||||||
self.assertTrue(response.status_code == 200)
|
associated metagroup
|
||||||
content = str(response.content)
|
"""
|
||||||
self.assertFalse(
|
memberships = self.club.members.select_related("user")
|
||||||
"Richard Batsbak</a></td>\\n <td>Responsable info</td>"
|
users = [membership.user for membership in memberships]
|
||||||
in content
|
meta_group = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
|
||||||
)
|
|
||||||
self.assertFalse(
|
|
||||||
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in content
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_mark_old_user_to_club_from_richard_ok(self):
|
self.club.delete()
|
||||||
self.client.login(username="root", password="plop")
|
for user in users:
|
||||||
self.client.post(
|
self.assertFalse(user.is_in_group(name=meta_group))
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{
|
|
||||||
"users": "|%d|%d|" % (self.skia.id, self.rbatsbak.id),
|
|
||||||
"start_date": "12/06/2016",
|
|
||||||
"role": 3,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with equal rights
|
def test_add_to_meta_group(self):
|
||||||
self.client.login(username="rbatsbak", password="plop")
|
"""
|
||||||
response = self.client.post(
|
Test that when a membership begins, the user is added to the meta group
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
"""
|
||||||
{"users_old": self.skia.id},
|
group_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
|
||||||
)
|
board_members = self.club.unix_name + settings.SITH_BOARD_SUFFIX
|
||||||
self.assertTrue(response.status_code == 302)
|
self.assertFalse(self.subscriber.is_in_group(name=group_members))
|
||||||
|
self.assertFalse(self.subscriber.is_in_group(name=board_members))
|
||||||
|
Membership.objects.create(club=self.club, user=self.subscriber, role=3)
|
||||||
|
self.assertTrue(self.subscriber.is_in_group(name=group_members))
|
||||||
|
self.assertTrue(self.subscriber.is_in_group(name=board_members))
|
||||||
|
|
||||||
response = self.client.get(
|
def test_remove_from_meta_group(self):
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
"""
|
||||||
)
|
Test that when a membership ends, the user is removed from meta group
|
||||||
self.assertTrue(response.status_code == 200)
|
"""
|
||||||
content = str(response.content)
|
group_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
|
||||||
self.assertTrue(
|
board_members = self.club.unix_name + settings.SITH_BOARD_SUFFIX
|
||||||
"Richard Batsbak</a></td>\\n <td>Responsable info</td>"
|
self.assertTrue(self.comptable.is_in_group(name=group_members))
|
||||||
in content
|
self.assertTrue(self.comptable.is_in_group(name=board_members))
|
||||||
)
|
self.comptable.memberships.update(end_date=localtime(now()))
|
||||||
self.assertFalse(
|
self.assertFalse(self.comptable.is_in_group(name=group_members))
|
||||||
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
self.assertFalse(self.comptable.is_in_group(name=board_members))
|
||||||
in content
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with lower rights
|
def test_club_owner(self):
|
||||||
self.client.post(
|
"""
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
Test that a club is owned only by board members of the main club
|
||||||
{"users": self.skia.id, "start_date": "12/06/2016", "role": 0},
|
"""
|
||||||
)
|
anonymous = AnonymousUser()
|
||||||
|
self.assertFalse(self.club.is_owned_by(anonymous))
|
||||||
|
self.assertFalse(self.club.is_owned_by(self.subscriber))
|
||||||
|
|
||||||
self.client.post(
|
# make sli a board member
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
self.sli.memberships.all().delete()
|
||||||
{"users_old": self.skia.id},
|
Membership(club=self.ae, user=self.sli, role=3).save()
|
||||||
)
|
self.assertTrue(self.club.is_owned_by(self.sli))
|
||||||
response = self.client.get(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
|
||||||
)
|
|
||||||
self.assertTrue(response.status_code == 200)
|
|
||||||
content = str(response.content)
|
|
||||||
self.assertTrue(
|
|
||||||
"Richard Batsbak</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in content
|
|
||||||
)
|
|
||||||
self.assertFalse(
|
|
||||||
"S' Kia</a></td>\\n <td>Curieux</td>" in content
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_mark_old_user_to_club_from_richard_fail(self):
|
|
||||||
self.client.login(username="root", password="plop")
|
|
||||||
self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users": self.skia.id, "start_date": "12/06/2016", "role": 3},
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with richard outside of the club
|
|
||||||
self.client.login(username="rbatsbak", password="plop")
|
|
||||||
response = self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users_old": self.skia.id},
|
|
||||||
)
|
|
||||||
self.assertTrue(response.status_code == 200)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
|
||||||
)
|
|
||||||
self.assertTrue(response.status_code == 200)
|
|
||||||
self.assertTrue(
|
|
||||||
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
|
||||||
in str(response.content)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with lower rights
|
|
||||||
self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users": self.rbatsbak.id, "start_date": "12/06/2016", "role": 0},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.client.post(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
|
||||||
{"users_old": self.skia.id},
|
|
||||||
)
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
content = response.content.decode()
|
|
||||||
self.assertIn(
|
|
||||||
"Richard Batsbak</a></td>\n <td>Curieux⸱euse</td>",
|
|
||||||
content,
|
|
||||||
)
|
|
||||||
self.assertIn(
|
|
||||||
"S' Kia</a></td>\n <td>Responsable info</td>",
|
|
||||||
content,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class MailingFormTest(TestCase):
|
class MailingFormTest(TestCase):
|
||||||
"""Perform validation tests for MailingForm"""
|
"""Perform validation tests for MailingForm"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.skia = User.objects.filter(username="skia").first()
|
||||||
|
cls.rbatsbak = User.objects.filter(username="rbatsbak").first()
|
||||||
|
cls.krophil = User.objects.filter(username="krophil").first()
|
||||||
|
cls.comunity = User.objects.filter(username="comunity").first()
|
||||||
|
cls.bdf = Club.objects.filter(unix_name=SITH_BAR_MANAGER["unix_name"]).first()
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
|
||||||
self.skia = User.objects.filter(username="skia").first()
|
|
||||||
self.rbatsbak = User.objects.filter(username="rbatsbak").first()
|
|
||||||
self.krophil = User.objects.filter(username="krophil").first()
|
|
||||||
self.comunity = User.objects.filter(username="comunity").first()
|
|
||||||
self.bdf = Club.objects.filter(unix_name="bdf").first()
|
|
||||||
Membership(
|
Membership(
|
||||||
user=self.rbatsbak,
|
user=self.rbatsbak,
|
||||||
club=self.bdf,
|
club=self.bdf,
|
||||||
@ -705,7 +885,6 @@ class ClubSellingViewTest(TestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
|
||||||
self.ae = Club.objects.filter(unix_name="ae").first()
|
self.ae = Club.objects.filter(unix_name="ae").first()
|
||||||
|
|
||||||
def test_page_not_internal_error(self):
|
def test_page_not_internal_error(self):
|
||||||
|
86
club/urls.py
@ -23,94 +23,84 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.urls import re_path
|
from django.urls import path
|
||||||
|
|
||||||
from club.views import *
|
from club.views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
re_path(r"^$", ClubListView.as_view(), name="club_list"),
|
path("", ClubListView.as_view(), name="club_list"),
|
||||||
re_path(r"^new$", ClubCreateView.as_view(), name="club_new"),
|
path("new/", ClubCreateView.as_view(), name="club_new"),
|
||||||
re_path(r"^stats$", ClubStatView.as_view(), name="club_stats"),
|
path("stats/", ClubStatView.as_view(), name="club_stats"),
|
||||||
re_path(r"^(?P<club_id>[0-9]+)/$", ClubView.as_view(), name="club_view"),
|
path("<int:club_id>/", ClubView.as_view(), name="club_view"),
|
||||||
re_path(
|
path(
|
||||||
r"^(?P<club_id>[0-9]+)/rev/(?P<rev_id>[0-9]+)/$",
|
"<int:club_id>/rev/<int:rev_id>/",
|
||||||
ClubRevView.as_view(),
|
ClubRevView.as_view(),
|
||||||
name="club_view_rev",
|
name="club_view_rev",
|
||||||
),
|
),
|
||||||
re_path(
|
path("<int:club_id>/hist/", ClubPageHistView.as_view(), name="club_hist"),
|
||||||
r"^(?P<club_id>[0-9]+)/hist$", ClubPageHistView.as_view(), name="club_hist"
|
path("<int:club_id>/edit/", ClubEditView.as_view(), name="club_edit"),
|
||||||
),
|
path(
|
||||||
re_path(r"^(?P<club_id>[0-9]+)/edit$", ClubEditView.as_view(), name="club_edit"),
|
"<int:club_id>/edit/page/",
|
||||||
re_path(
|
|
||||||
r"^(?P<club_id>[0-9]+)/edit/page$",
|
|
||||||
ClubPageEditView.as_view(),
|
ClubPageEditView.as_view(),
|
||||||
name="club_edit_page",
|
name="club_edit_page",
|
||||||
),
|
),
|
||||||
re_path(
|
path("<int:club_id>/members/", ClubMembersView.as_view(), name="club_members"),
|
||||||
r"^(?P<club_id>[0-9]+)/members$", ClubMembersView.as_view(), name="club_members"
|
path(
|
||||||
),
|
"<int:club_id>/elderlies/",
|
||||||
re_path(
|
|
||||||
r"^(?P<club_id>[0-9]+)/elderlies$",
|
|
||||||
ClubOldMembersView.as_view(),
|
ClubOldMembersView.as_view(),
|
||||||
name="club_old_members",
|
name="club_old_members",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^(?P<club_id>[0-9]+)/sellings$",
|
"<int:club_id>/sellings/",
|
||||||
ClubSellingView.as_view(),
|
ClubSellingView.as_view(),
|
||||||
name="club_sellings",
|
name="club_sellings",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^(?P<club_id>[0-9]+)/sellings/csv$",
|
"<int:club_id>/sellings/csv/",
|
||||||
ClubSellingCSVView.as_view(),
|
ClubSellingCSVView.as_view(),
|
||||||
name="sellings_csv",
|
name="sellings_csv",
|
||||||
),
|
),
|
||||||
re_path(
|
path("<int:club_id>/prop/", ClubEditPropView.as_view(), name="club_prop"),
|
||||||
r"^(?P<club_id>[0-9]+)/prop$", ClubEditPropView.as_view(), name="club_prop"
|
path("<int:club_id>/tools/", ClubToolsView.as_view(), name="tools"),
|
||||||
),
|
path("<int:club_id>/mailing/", ClubMailingView.as_view(), name="mailing"),
|
||||||
re_path(r"^(?P<club_id>[0-9]+)/tools$", ClubToolsView.as_view(), name="tools"),
|
path(
|
||||||
re_path(
|
"<int:mailing_id>/mailing/generate/",
|
||||||
r"^(?P<club_id>[0-9]+)/mailing$", ClubMailingView.as_view(), name="mailing"
|
|
||||||
),
|
|
||||||
re_path(
|
|
||||||
r"^(?P<mailing_id>[0-9]+)/mailing/generate$",
|
|
||||||
MailingAutoGenerationView.as_view(),
|
MailingAutoGenerationView.as_view(),
|
||||||
name="mailing_generate",
|
name="mailing_generate",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^(?P<mailing_id>[0-9]+)/mailing/delete$",
|
"<int:mailing_id>/mailing/delete/",
|
||||||
MailingDeleteView.as_view(),
|
MailingDeleteView.as_view(),
|
||||||
name="mailing_delete",
|
name="mailing_delete",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^(?P<mailing_subscription_id>[0-9]+)/mailing/delete/subscription$",
|
"<int:mailing_subscription_id>/mailing/delete/subscription/",
|
||||||
MailingSubscriptionDeleteView.as_view(),
|
MailingSubscriptionDeleteView.as_view(),
|
||||||
name="mailing_subscription_delete",
|
name="mailing_subscription_delete",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^membership/(?P<membership_id>[0-9]+)/set_old$",
|
"membership/<int:membership_id>/set_old/",
|
||||||
MembershipSetOldView.as_view(),
|
MembershipSetOldView.as_view(),
|
||||||
name="membership_set_old",
|
name="membership_set_old",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^membership/(?P<membership_id>[0-9]+)/delete$",
|
"membership/<int:membership_id>/delete/",
|
||||||
MembershipDeleteView.as_view(),
|
MembershipDeleteView.as_view(),
|
||||||
name="membership_delete",
|
name="membership_delete",
|
||||||
),
|
),
|
||||||
re_path(
|
path("<int:club_id>/poster/", PosterListView.as_view(), name="poster_list"),
|
||||||
r"^(?P<club_id>[0-9]+)/poster$", PosterListView.as_view(), name="poster_list"
|
path(
|
||||||
),
|
"<int:club_id>/poster/create/",
|
||||||
re_path(
|
|
||||||
r"^(?P<club_id>[0-9]+)/poster/create$",
|
|
||||||
PosterCreateView.as_view(),
|
PosterCreateView.as_view(),
|
||||||
name="poster_create",
|
name="poster_create",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/edit$",
|
"<int:club_id>/poster/<int:poster_id>/edit/",
|
||||||
PosterEditView.as_view(),
|
PosterEditView.as_view(),
|
||||||
name="poster_edit",
|
name="poster_edit",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/delete$",
|
"<int:club_id>/poster/<int:poster_id>/delete/",
|
||||||
PosterDeleteView.as_view(),
|
PosterDeleteView.as_view(),
|
||||||
name="poster_delete",
|
name="poster_delete",
|
||||||
),
|
),
|
||||||
|
@ -306,9 +306,7 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.members = (
|
self.members = self.get_object().members.ongoing().order_by("-role")
|
||||||
self.get_object().members.filter(end_date=None).order_by("-role").all()
|
|
||||||
)
|
|
||||||
return super(ClubMembersView, self).dispatch(request, *args, **kwargs)
|
return super(ClubMembersView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
@ -443,7 +441,6 @@ class ClubSellingCSVView(ClubSellingView):
|
|||||||
return row
|
return row
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
kwargs = self.get_context_data(**kwargs)
|
kwargs = self.get_context_data(**kwargs)
|
||||||
|
|
||||||
@ -706,7 +703,6 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
|
|||||||
|
|
||||||
|
|
||||||
class MailingDeleteView(CanEditMixin, DeleteView):
|
class MailingDeleteView(CanEditMixin, DeleteView):
|
||||||
|
|
||||||
model = Mailing
|
model = Mailing
|
||||||
template_name = "core/delete_confirm.jinja"
|
template_name = "core/delete_confirm.jinja"
|
||||||
pk_url_kwarg = "mailing_id"
|
pk_url_kwarg = "mailing_id"
|
||||||
@ -724,7 +720,6 @@ class MailingDeleteView(CanEditMixin, DeleteView):
|
|||||||
|
|
||||||
|
|
||||||
class MailingSubscriptionDeleteView(CanEditMixin, DeleteView):
|
class MailingSubscriptionDeleteView(CanEditMixin, DeleteView):
|
||||||
|
|
||||||
model = MailingSubscription
|
model = MailingSubscription
|
||||||
template_name = "core/delete_confirm.jinja"
|
template_name = "core/delete_confirm.jinja"
|
||||||
pk_url_kwarg = "mailing_subscription_id"
|
pk_url_kwarg = "mailing_subscription_id"
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
50
com/admin.py
@ -1,43 +1,49 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
from ajax_select import make_ajax_form
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from haystack.admin import SearchModelAdmin
|
from haystack.admin import SearchModelAdmin
|
||||||
|
|
||||||
from com.models import *
|
from com.models import *
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(News)
|
||||||
class NewsAdmin(SearchModelAdmin):
|
class NewsAdmin(SearchModelAdmin):
|
||||||
search_fields = ["title", "summary", "content"]
|
list_display = ("title", "type", "club", "author")
|
||||||
|
search_fields = ("title", "summary", "content")
|
||||||
|
form = make_ajax_form(
|
||||||
|
News,
|
||||||
|
{
|
||||||
|
"author": "users",
|
||||||
|
"moderator": "users",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Poster)
|
||||||
|
class PosterAdmin(SearchModelAdmin):
|
||||||
|
list_display = ("name", "club", "date_begin", "date_end", "moderator")
|
||||||
|
form = make_ajax_form(Poster, {"moderator": "users"})
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Weekmail)
|
||||||
class WeekmailAdmin(SearchModelAdmin):
|
class WeekmailAdmin(SearchModelAdmin):
|
||||||
search_fields = ["title"]
|
list_display = ("title", "sent")
|
||||||
|
search_fields = ("title",)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Sith)
|
admin.site.register(Sith)
|
||||||
admin.site.register(News, NewsAdmin)
|
|
||||||
admin.site.register(Weekmail, WeekmailAdmin)
|
|
||||||
admin.site.register(Screen)
|
admin.site.register(Screen)
|
||||||
admin.site.register(Poster)
|
|
||||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("club", "0005_auto_20161120_1149"),
|
("club", "0005_auto_20161120_1149"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("club", "0006_auto_20161229_0040"),
|
("club", "0006_auto_20161229_0040"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
@ -8,7 +8,6 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("club", "0010_auto_20170912_2028"),
|
("club", "0010_auto_20170912_2028"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("com", "0004_auto_20171221_1614")]
|
dependencies = [("com", "0004_auto_20171221_1614")]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -6,7 +6,6 @@ from django.db import migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [("com", "0005_auto_20180318_2227")]
|
dependencies = [("com", "0005_auto_20180318_2227")]
|
||||||
|
|
||||||
operations = [migrations.RemoveField(model_name="sith", name="index_page")]
|
operations = [migrations.RemoveField(model_name="sith", name="index_page")]
|
||||||
|
@ -36,6 +36,7 @@ from django.core.exceptions import ValidationError
|
|||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from core import utils
|
||||||
from core.models import User, Preferences, RealGroup, Notification, SithFile
|
from core.models import User, Preferences, RealGroup, Notification, SithFile
|
||||||
from club.models import Club
|
from club.models import Club
|
||||||
|
|
||||||
@ -46,9 +47,12 @@ class Sith(models.Model):
|
|||||||
alert_msg = models.TextField(_("alert message"), default="", blank=True)
|
alert_msg = models.TextField(_("alert message"), default="", blank=True)
|
||||||
info_msg = models.TextField(_("info message"), default="", blank=True)
|
info_msg = models.TextField(_("info message"), default="", blank=True)
|
||||||
weekmail_destinations = models.TextField(_("weekmail destinations"), default="")
|
weekmail_destinations = models.TextField(_("weekmail destinations"), default="")
|
||||||
|
version = utils.get_git_revision_short_hash()
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
return user.is_com_admin
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "⛩ Sith ⛩"
|
return "⛩ Sith ⛩"
|
||||||
@ -61,11 +65,6 @@ NEWS_TYPES = [
|
|||||||
("CALL", _("Call")),
|
("CALL", _("Call")),
|
||||||
]
|
]
|
||||||
|
|
||||||
WEEKMAIL_TYPE = [
|
|
||||||
("WEEKMAIL", _("Weekmail")),
|
|
||||||
("INVITATION", _("Invitation")),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class News(models.Model):
|
class News(models.Model):
|
||||||
"""The news class"""
|
"""The news class"""
|
||||||
@ -95,13 +94,15 @@ class News(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user == self.author
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
return user.is_com_admin or user == self.author
|
||||||
|
|
||||||
def can_be_edited_by(self, user):
|
def can_be_edited_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return user.is_com_admin
|
||||||
|
|
||||||
def can_be_viewed_by(self, user):
|
def can_be_viewed_by(self, user):
|
||||||
return self.is_moderated or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return self.is_moderated or user.is_com_admin
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("com:news_detail", kwargs={"news_id": self.id})
|
return reverse("com:news_detail", kwargs={"news_id": self.id})
|
||||||
@ -183,9 +184,6 @@ class Weekmail(models.Model):
|
|||||||
protip = models.TextField(_("protip"), blank=True)
|
protip = models.TextField(_("protip"), blank=True)
|
||||||
conclusion = models.TextField(_("conclusion"), blank=True)
|
conclusion = models.TextField(_("conclusion"), blank=True)
|
||||||
sent = models.BooleanField(_("sent"), default=False)
|
sent = models.BooleanField(_("sent"), default=False)
|
||||||
type = models.CharField(
|
|
||||||
_("type"), max_length=16, choices=WEEKMAIL_TYPE, default="WEEKMAIL"
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ["-id"]
|
ordering = ["-id"]
|
||||||
@ -223,17 +221,6 @@ class Weekmail(models.Model):
|
|||||||
None, "com/weekmail_renderer_text.jinja", context={"weekmail": self}
|
None, "com/weekmail_renderer_text.jinja", context={"weekmail": self}
|
||||||
).content.decode("utf-8")
|
).content.decode("utf-8")
|
||||||
|
|
||||||
def switch_type(self):
|
|
||||||
"""
|
|
||||||
Switch the type of weekmail we are sending :
|
|
||||||
- a simple weekmail
|
|
||||||
- or an invitation
|
|
||||||
"""
|
|
||||||
if self.type == "INVITATION":
|
|
||||||
self.type = "WEEKMAIL"
|
|
||||||
else:
|
|
||||||
self.type = "INVITATION"
|
|
||||||
|
|
||||||
def render_html(self):
|
def render_html(self):
|
||||||
"""
|
"""
|
||||||
Renders an HTML version of the mail with images and fancy CSS.
|
Renders an HTML version of the mail with images and fancy CSS.
|
||||||
@ -246,15 +233,10 @@ class Weekmail(models.Model):
|
|||||||
"""
|
"""
|
||||||
Return an absolute link to the banner.
|
Return an absolute link to the banner.
|
||||||
"""
|
"""
|
||||||
if self.type == "INVITATION":
|
|
||||||
return (
|
|
||||||
"http://" + settings.SITH_URL + static("com/img/invitation_bannerP22.png")
|
|
||||||
)
|
|
||||||
return (
|
return (
|
||||||
"http://" + settings.SITH_URL + static("com/img/weekmail_bannerV2P22.png")
|
"http://" + settings.SITH_URL + static("com/img/weekmail_bannerV2P22.png")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_footer(self):
|
def get_footer(self):
|
||||||
"""
|
"""
|
||||||
Return an absolute link to the footer.
|
Return an absolute link to the footer.
|
||||||
@ -265,7 +247,9 @@ class Weekmail(models.Model):
|
|||||||
return "Weekmail %s (sent: %s) - %s" % (self.id, self.sent, self.title)
|
return "Weekmail %s (sent: %s) - %s" % (self.id, self.sent, self.title)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
return user.is_com_admin
|
||||||
|
|
||||||
|
|
||||||
class WeekmailArticle(models.Model):
|
class WeekmailArticle(models.Model):
|
||||||
@ -293,7 +277,9 @@ class WeekmailArticle(models.Model):
|
|||||||
rank = models.IntegerField(_("rank"), default=-1)
|
rank = models.IntegerField(_("rank"), default=-1)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
return user.is_com_admin
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s - %s (%s)" % (self.title, self.author, self.club)
|
return "%s - %s (%s)" % (self.title, self.author, self.club)
|
||||||
@ -309,7 +295,9 @@ class Screen(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
if user.is_anonymous:
|
||||||
|
return False
|
||||||
|
return user.is_com_admin
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s" % (self.name)
|
return "%s" % (self.name)
|
||||||
@ -362,12 +350,12 @@ class Poster(models.Model):
|
|||||||
raise ValidationError(_("Begin date should be before end date"))
|
raise ValidationError(_("Begin date should be before end date"))
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(
|
if user.is_anonymous:
|
||||||
settings.SITH_GROUP_COM_ADMIN_ID
|
return False
|
||||||
) or Club.objects.filter(id__in=user.clubs_with_rights)
|
return user.is_com_admin or len(user.clubs_with_rights) > 0
|
||||||
|
|
||||||
def can_be_moderated_by(self, user):
|
def can_be_moderated_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return user.is_com_admin
|
||||||
|
|
||||||
def get_display_name(self):
|
def get_display_name(self):
|
||||||
return self.club.get_display_name()
|
return self.club.get_display_name()
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<p>{% trans %}Author: {% endtrans %}{{ user_profile_link(news.author) }}</p>
|
<p>{% trans %}Author: {% endtrans %}{{ user_profile_link(news.author) }}</p>
|
||||||
{% if news.moderator %}
|
{% if news.moderator %}
|
||||||
<p>{% trans %}Moderator: {% endtrans %}{{ user_profile_link(news.moderator) }}</p>
|
<p>{% trans %}Moderator: {% endtrans %}{{ user_profile_link(news.moderator) }}</p>
|
||||||
{% elif user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
|
{% elif user.is_com_admin %}
|
||||||
<p> <a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a></p>
|
<p> <a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.can_edit(news) %}
|
{% if user.can_edit(news) %}
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
<p>{{ form.club.errors }}<label for="{{ form.club.name }}">{{ form.club.label }}</label> {{ form.club }}</p>
|
<p>{{ form.club.errors }}<label for="{{ form.club.name }}">{{ form.club.label }}</label> {{ form.club }}</p>
|
||||||
<p>{{ form.summary.errors }}<label for="{{ form.summary.name }}">{{ form.summary.label }}</label> {{ form.summary }}</p>
|
<p>{{ form.summary.errors }}<label for="{{ form.summary.name }}">{{ form.summary.label }}</label> {{ form.summary }}</p>
|
||||||
<p>{{ form.content.errors }}<label for="{{ form.content.name }}">{{ form.content.label }}</label> {{ form.content }}</p>
|
<p>{{ form.content.errors }}<label for="{{ form.content.name }}">{{ form.content.label }}</label> {{ form.content }}</p>
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
|
{% if user.is_com_admin %}
|
||||||
<p>{{ form.automoderation.errors }}<label for="{{ form.automoderation.name }}">{{ form.automoderation.label }}</label>
|
<p>{{ form.automoderation.errors }}<label for="{{ form.automoderation.name }}">{{ form.automoderation.label }}</label>
|
||||||
{{ form.automoderation }}</p>
|
{{ form.automoderation }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -6,15 +6,15 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
|
{% if user.is_com_admin %}
|
||||||
<div id="news_admin">
|
<div id="news_admin">
|
||||||
<a href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a>
|
<a class="button" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a>
|
||||||
</div>
|
</div>
|
||||||
|
<br>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="news">
|
<div id="news">
|
||||||
<div id="left_column" class="news_column">
|
<div id="left_column" class="news_column">
|
||||||
|
|
||||||
{% for news in object_list.filter(type="NOTICE") %}
|
{% for news in object_list.filter(type="NOTICE") %}
|
||||||
<section class="news_notice">
|
<section class="news_notice">
|
||||||
<h4><a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
|
<h4><a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
|
||||||
@ -97,6 +97,15 @@
|
|||||||
</section>
|
</section>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<h3>{% trans %}All coming events{% endtrans %}</h3>
|
||||||
|
<iframe
|
||||||
|
src="https://embed.styledcalendar.com/#2mF2is8CEXhr4ADcX6qN"
|
||||||
|
title="Styled Calendar"
|
||||||
|
class="styled-calendar-container"
|
||||||
|
style="width: 100%; border: none; height: 1060px"
|
||||||
|
data-cy="calendar-embed-iframe">
|
||||||
|
</iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="right_column" class="news_column">
|
<div id="right_column" class="news_column">
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<div id="progress_bar"></div>
|
<div id="progress_bar"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="{{ static('core/js/jquery-3.1.0.min.js') }}"></script>
|
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script>
|
||||||
<script src="{{ static('com/js/slideshow.js') }}"></script>
|
<script src="{{ static('com/js/slideshow.js') }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<p><a href="{{ url('com:weekmail_preview') }}">{% trans %}Preview{% endtrans %}</a></p>
|
<p><a href="{{ url('com:weekmail_preview') }}">{% trans %}Preview{% endtrans %}</a></p>
|
||||||
<p><a href="{{ url('com:weekmail_preview') }}?send=true">{% trans %}Send{% endtrans %}</a></p>
|
<p><a href="{{ url('com:weekmail_preview') }}?send=true">{% trans %}Send{% endtrans %}</a></p>
|
||||||
<p><a href="{{ url('com:weekmail_article') }}">{% trans %}New article{% endtrans %}</a></p>
|
<p><a href="{{ url('com:weekmail_article') }}">{% trans %}New article{% endtrans %}</a></p>
|
||||||
<p><a href="{{ url('com:weekmail') }}" onclick="{{weekmail.switch_type()}}">{% trans %}Switch invitation/weekmail{% endtrans %}</a></p>
|
|
||||||
<h4>{% trans %}Articles in no weekmail yet{% endtrans %}</h4>
|
<h4>{% trans %}Articles in no weekmail yet{% endtrans %}</h4>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
155
com/tests.py
@ -1,42 +1,33 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.utils import html
|
from django.utils import html
|
||||||
|
from django.utils.timezone import localtime, now
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
from club.models import Club, Membership
|
||||||
from core.models import User, RealGroup
|
from com.models import Sith, News, Weekmail, WeekmailArticle, Poster
|
||||||
|
from core.models import User, RealGroup, AnonymousUser
|
||||||
|
|
||||||
|
|
||||||
class ComAlertTest(TestCase):
|
class ComAlertTest(TestCase):
|
||||||
def setUp(self):
|
|
||||||
call_command("populate")
|
|
||||||
|
|
||||||
def test_page_is_working(self):
|
def test_page_is_working(self):
|
||||||
self.client.login(username="comunity", password="plop")
|
self.client.login(username="comunity", password="plop")
|
||||||
response = self.client.get(reverse("com:alert_edit"))
|
response = self.client.get(reverse("com:alert_edit"))
|
||||||
@ -45,9 +36,6 @@ class ComAlertTest(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class ComInfoTest(TestCase):
|
class ComInfoTest(TestCase):
|
||||||
def setUp(self):
|
|
||||||
call_command("populate")
|
|
||||||
|
|
||||||
def test_page_is_working(self):
|
def test_page_is_working(self):
|
||||||
self.client.login(username="comunity", password="plop")
|
self.client.login(username="comunity", password="plop")
|
||||||
response = self.client.get(reverse("com:info_edit"))
|
response = self.client.get(reverse("com:info_edit"))
|
||||||
@ -56,14 +44,16 @@ class ComInfoTest(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class ComTest(TestCase):
|
class ComTest(TestCase):
|
||||||
def setUp(self):
|
@classmethod
|
||||||
call_command("populate")
|
def setUpTestData(cls):
|
||||||
self.skia = User.objects.filter(username="skia").first()
|
cls.skia = User.objects.filter(username="skia").first()
|
||||||
self.com_group = RealGroup.objects.filter(
|
cls.com_group = RealGroup.objects.filter(
|
||||||
id=settings.SITH_GROUP_COM_ADMIN_ID
|
id=settings.SITH_GROUP_COM_ADMIN_ID
|
||||||
).first()
|
).first()
|
||||||
self.skia.groups.set([self.com_group])
|
cls.skia.groups.set([cls.com_group])
|
||||||
self.skia.save()
|
cls.skia.save()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
self.client.login(username=self.skia.username, password="plop")
|
self.client.login(username=self.skia.username, password="plop")
|
||||||
|
|
||||||
def test_alert_msg(self):
|
def test_alert_msg(self):
|
||||||
@ -82,7 +72,7 @@ class ComTest(TestCase):
|
|||||||
self.assertContains(
|
self.assertContains(
|
||||||
r,
|
r,
|
||||||
"""<div id="alert_box">
|
"""<div id="alert_box">
|
||||||
<div class="markdown"><h3>ALERTE!</h3>
|
<div class="markdown"><h3>ALERTE!</h3>
|
||||||
<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""",
|
<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -100,7 +90,7 @@ class ComTest(TestCase):
|
|||||||
self.assertContains(
|
self.assertContains(
|
||||||
r,
|
r,
|
||||||
"""<div id="info_box">
|
"""<div id="info_box">
|
||||||
<div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""",
|
<div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_birthday_non_subscribed_user(self):
|
def test_birthday_non_subscribed_user(self):
|
||||||
@ -122,3 +112,102 @@ class ComTest(TestCase):
|
|||||||
_("You need an up to date subscription to access this content")
|
_("You need an up to date subscription to access this content")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SithTest(TestCase):
|
||||||
|
def test_sith_owner(self):
|
||||||
|
"""
|
||||||
|
Test that the sith instance is owned by com admins
|
||||||
|
and nobody else
|
||||||
|
"""
|
||||||
|
sith: Sith = Sith.objects.first()
|
||||||
|
|
||||||
|
com_admin = User.objects.get(username="comunity")
|
||||||
|
self.assertTrue(sith.is_owned_by(com_admin))
|
||||||
|
|
||||||
|
anonymous = AnonymousUser()
|
||||||
|
self.assertFalse(sith.is_owned_by(anonymous))
|
||||||
|
|
||||||
|
sli = User.objects.get(username="sli")
|
||||||
|
self.assertFalse(sith.is_owned_by(sli))
|
||||||
|
|
||||||
|
|
||||||
|
class NewsTest(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.com_admin = User.objects.get(username="comunity")
|
||||||
|
new = News.objects.create(
|
||||||
|
title="dummy new",
|
||||||
|
summary="This is a dummy new",
|
||||||
|
content="Look at that beautiful dummy new",
|
||||||
|
author=User.objects.get(username="subscriber"),
|
||||||
|
club=Club.objects.first(),
|
||||||
|
)
|
||||||
|
cls.new = new
|
||||||
|
cls.author = new.author
|
||||||
|
cls.sli = User.objects.get(username="sli")
|
||||||
|
cls.anonymous = AnonymousUser()
|
||||||
|
|
||||||
|
def test_news_owner(self):
|
||||||
|
"""
|
||||||
|
Test that news are owned by com admins
|
||||||
|
or by their author but nobody else
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.assertTrue(self.new.is_owned_by(self.com_admin))
|
||||||
|
self.assertTrue(self.new.is_owned_by(self.author))
|
||||||
|
self.assertFalse(self.new.is_owned_by(self.anonymous))
|
||||||
|
self.assertFalse(self.new.is_owned_by(self.sli))
|
||||||
|
|
||||||
|
|
||||||
|
class WeekmailArticleTest(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.com_admin = User.objects.get(username="comunity")
|
||||||
|
author = User.objects.get(username="subscriber")
|
||||||
|
cls.article = WeekmailArticle.objects.create(
|
||||||
|
weekmail=Weekmail.objects.create(),
|
||||||
|
author=author,
|
||||||
|
title="title",
|
||||||
|
content="Some content",
|
||||||
|
club=Club.objects.first(),
|
||||||
|
)
|
||||||
|
cls.author = author
|
||||||
|
cls.sli = User.objects.get(username="sli")
|
||||||
|
cls.anonymous = AnonymousUser()
|
||||||
|
|
||||||
|
def test_weekmail_owner(self):
|
||||||
|
"""
|
||||||
|
Test that weekmails are owned only by com admins
|
||||||
|
"""
|
||||||
|
self.assertTrue(self.article.is_owned_by(self.com_admin))
|
||||||
|
self.assertFalse(self.article.is_owned_by(self.author))
|
||||||
|
self.assertFalse(self.article.is_owned_by(self.anonymous))
|
||||||
|
self.assertFalse(self.article.is_owned_by(self.sli))
|
||||||
|
|
||||||
|
|
||||||
|
class PosterTest(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.com_admin = User.objects.get(username="comunity")
|
||||||
|
cls.poster = Poster.objects.create(
|
||||||
|
name="dummy",
|
||||||
|
file=SimpleUploadedFile("dummy.jpg", b"azertyuiop"),
|
||||||
|
club=Club.objects.first(),
|
||||||
|
date_begin=localtime(now()),
|
||||||
|
)
|
||||||
|
cls.sli = User.objects.get(username="sli")
|
||||||
|
cls.sli.memberships.all().delete()
|
||||||
|
Membership(user=cls.sli, club=Club.objects.first(), role=5).save()
|
||||||
|
cls.susbcriber = User.objects.get(username="subscriber")
|
||||||
|
cls.anonymous = AnonymousUser()
|
||||||
|
|
||||||
|
def test_poster_owner(self):
|
||||||
|
"""
|
||||||
|
Test that poster are owned by com admins and board members in clubs
|
||||||
|
"""
|
||||||
|
self.assertTrue(self.poster.is_owned_by(self.com_admin))
|
||||||
|
self.assertFalse(self.poster.is_owned_by(self.anonymous))
|
||||||
|
|
||||||
|
self.assertFalse(self.poster.is_owned_by(self.susbcriber))
|
||||||
|
self.assertTrue(self.poster.is_owned_by(self.sli))
|
||||||
|
122
com/urls.py
@ -1,125 +1,111 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.urls import re_path
|
from django.urls import path
|
||||||
|
|
||||||
from com.views import *
|
|
||||||
from club.views import MailingDeleteView
|
from club.views import MailingDeleteView
|
||||||
|
from com.views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
re_path(r"^sith/edit/alert$", AlertMsgEditView.as_view(), name="alert_edit"),
|
path("sith/edit/alert/", AlertMsgEditView.as_view(), name="alert_edit"),
|
||||||
re_path(r"^sith/edit/info$", InfoMsgEditView.as_view(), name="info_edit"),
|
path("sith/edit/info/", InfoMsgEditView.as_view(), name="info_edit"),
|
||||||
re_path(
|
path(
|
||||||
r"^sith/edit/weekmail_destinations$",
|
"sith/edit/weekmail_destinations/",
|
||||||
WeekmailDestinationEditView.as_view(),
|
WeekmailDestinationEditView.as_view(),
|
||||||
name="weekmail_destinations",
|
name="weekmail_destinations",
|
||||||
),
|
),
|
||||||
re_path(r"^weekmail$", WeekmailEditView.as_view(), name="weekmail"),
|
path("weekmail/", WeekmailEditView.as_view(), name="weekmail"),
|
||||||
re_path(
|
path("weekmail/preview/", WeekmailPreviewView.as_view(), name="weekmail_preview"),
|
||||||
r"^weekmail/preview$", WeekmailPreviewView.as_view(), name="weekmail_preview"
|
path(
|
||||||
),
|
"weekmail/new_article/",
|
||||||
re_path(
|
|
||||||
r"^weekmail/new_article$",
|
|
||||||
WeekmailArticleCreateView.as_view(),
|
WeekmailArticleCreateView.as_view(),
|
||||||
name="weekmail_article",
|
name="weekmail_article",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^weekmail/article/(?P<article_id>[0-9]+)/delete$",
|
"weekmail/article/<int:article_id>/delete/",
|
||||||
WeekmailArticleDeleteView.as_view(),
|
WeekmailArticleDeleteView.as_view(),
|
||||||
name="weekmail_article_delete",
|
name="weekmail_article_delete",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^weekmail/article/(?P<article_id>[0-9]+)/edit$",
|
"weekmail/article/<int:article_id>/edit/",
|
||||||
WeekmailArticleEditView.as_view(),
|
WeekmailArticleEditView.as_view(),
|
||||||
name="weekmail_article_edit",
|
name="weekmail_article_edit",
|
||||||
),
|
),
|
||||||
re_path(r"^news$", NewsListView.as_view(), name="news_list"),
|
path("news/", NewsListView.as_view(), name="news_list"),
|
||||||
re_path(r"^news/admin$", NewsAdminListView.as_view(), name="news_admin_list"),
|
path("news/admin/", NewsAdminListView.as_view(), name="news_admin_list"),
|
||||||
re_path(r"^news/create$", NewsCreateView.as_view(), name="news_new"),
|
path("news/create/", NewsCreateView.as_view(), name="news_new"),
|
||||||
re_path(
|
path(
|
||||||
r"^news/(?P<news_id>[0-9]+)/delete$",
|
"news/<int:news_id>/delete/",
|
||||||
NewsDeleteView.as_view(),
|
NewsDeleteView.as_view(),
|
||||||
name="news_delete",
|
name="news_delete",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^news/(?P<news_id>[0-9]+)/moderate$",
|
"news/<int:news_id>/moderate/",
|
||||||
NewsModerateView.as_view(),
|
NewsModerateView.as_view(),
|
||||||
name="news_moderate",
|
name="news_moderate",
|
||||||
),
|
),
|
||||||
re_path(
|
path("news/<int:news_id>/edit/", NewsEditView.as_view(), name="news_edit"),
|
||||||
r"^news/(?P<news_id>[0-9]+)/edit$", NewsEditView.as_view(), name="news_edit"
|
path("news/<int:news_id>/", NewsDetailView.as_view(), name="news_detail"),
|
||||||
),
|
path("mailings/", MailingListAdminView.as_view(), name="mailing_admin"),
|
||||||
re_path(
|
path(
|
||||||
r"^news/(?P<news_id>[0-9]+)$", NewsDetailView.as_view(), name="news_detail"
|
"mailings/<int:mailing_id>/moderate/",
|
||||||
),
|
|
||||||
re_path(r"^mailings$", MailingListAdminView.as_view(), name="mailing_admin"),
|
|
||||||
re_path(
|
|
||||||
r"^mailings/(?P<mailing_id>[0-9]+)/moderate$",
|
|
||||||
MailingModerateView.as_view(),
|
MailingModerateView.as_view(),
|
||||||
name="mailing_moderate",
|
name="mailing_moderate",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^mailings/(?P<mailing_id>[0-9]+)/delete$",
|
"mailings/<int:mailing_id>/delete/",
|
||||||
MailingDeleteView.as_view(redirect_page="com:mailing_admin"),
|
MailingDeleteView.as_view(redirect_page="com:mailing_admin"),
|
||||||
name="mailing_delete",
|
name="mailing_delete",
|
||||||
),
|
),
|
||||||
re_path(r"^poster$", PosterListView.as_view(), name="poster_list"),
|
path("poster/", PosterListView.as_view(), name="poster_list"),
|
||||||
re_path(r"^poster/create$", PosterCreateView.as_view(), name="poster_create"),
|
path("poster/create/", PosterCreateView.as_view(), name="poster_create"),
|
||||||
re_path(
|
path(
|
||||||
r"^poster/(?P<poster_id>[0-9]+)/edit$",
|
"poster/<int:poster_id>/edit/",
|
||||||
PosterEditView.as_view(),
|
PosterEditView.as_view(),
|
||||||
name="poster_edit",
|
name="poster_edit",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^poster/(?P<poster_id>[0-9]+)/delete$",
|
"poster/<int:poster_id>/delete/",
|
||||||
PosterDeleteView.as_view(),
|
PosterDeleteView.as_view(),
|
||||||
name="poster_delete",
|
name="poster_delete",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^poster/moderate$",
|
"poster/moderate/",
|
||||||
PosterModerateListView.as_view(),
|
PosterModerateListView.as_view(),
|
||||||
name="poster_moderate_list",
|
name="poster_moderate_list",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^poster/(?P<object_id>[0-9]+)/moderate$",
|
"poster/<int:object_id>/moderate/",
|
||||||
PosterModerateView.as_view(),
|
PosterModerateView.as_view(),
|
||||||
name="poster_moderate",
|
name="poster_moderate",
|
||||||
),
|
),
|
||||||
re_path(r"^screen$", ScreenListView.as_view(), name="screen_list"),
|
path("screen/", ScreenListView.as_view(), name="screen_list"),
|
||||||
re_path(r"^screen/create$", ScreenCreateView.as_view(), name="screen_create"),
|
path("screen/create/", ScreenCreateView.as_view(), name="screen_create"),
|
||||||
re_path(
|
path(
|
||||||
r"^screen/(?P<screen_id>[0-9]+)/slideshow$",
|
"screen/<int:screen_id>/slideshow/",
|
||||||
ScreenSlideshowView.as_view(),
|
ScreenSlideshowView.as_view(),
|
||||||
name="screen_slideshow",
|
name="screen_slideshow",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^screen/(?P<screen_id>[0-9]+)/edit$",
|
"screen/<int:screen_id>/edit/",
|
||||||
ScreenEditView.as_view(),
|
ScreenEditView.as_view(),
|
||||||
name="screen_edit",
|
name="screen_edit",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^screen/(?P<screen_id>[0-9]+)/delete$",
|
"screen/<int:screen_id>/delete/",
|
||||||
ScreenDeleteView.as_view(),
|
ScreenDeleteView.as_view(),
|
||||||
name="screen_delete",
|
name="screen_delete",
|
||||||
),
|
),
|
||||||
|
15
com/views.py
@ -146,7 +146,7 @@ class ComTabsMixin(TabedViewMixin):
|
|||||||
|
|
||||||
class IsComAdminMixin(View):
|
class IsComAdminMixin(View):
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)):
|
if not request.user.is_com_admin:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
return super(IsComAdminMixin, self).dispatch(request, *args, **kwargs)
|
return super(IsComAdminMixin, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
@ -283,9 +283,7 @@ class NewsEditView(CanEditMixin, UpdateView):
|
|||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
self.object = form.save()
|
self.object = form.save()
|
||||||
if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
|
if form.cleaned_data["automoderation"] and self.request.user.is_com_admin:
|
||||||
settings.SITH_GROUP_COM_ADMIN_ID
|
|
||||||
):
|
|
||||||
self.object.moderator = self.request.user
|
self.object.moderator = self.request.user
|
||||||
self.object.is_moderated = True
|
self.object.is_moderated = True
|
||||||
self.object.save()
|
self.object.save()
|
||||||
@ -333,9 +331,7 @@ class NewsCreateView(CanCreateMixin, CreateView):
|
|||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
self.object = form.save()
|
self.object = form.save()
|
||||||
if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
|
if form.cleaned_data["automoderation"] and self.request.user.is_com_admin:
|
||||||
settings.SITH_GROUP_COM_ADMIN_ID
|
|
||||||
):
|
|
||||||
self.object.moderator = self.request.user
|
self.object.moderator = self.request.user
|
||||||
self.object.is_moderated = True
|
self.object.is_moderated = True
|
||||||
self.object.save()
|
self.object.save()
|
||||||
@ -617,10 +613,7 @@ class MailingListAdminView(ComTabsMixin, ListView):
|
|||||||
current_tab = "mailings"
|
current_tab = "mailings"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not (
|
if not (request.user.is_com_admin or request.user.is_root):
|
||||||
request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
|
||||||
or request.user.is_root
|
|
||||||
):
|
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
return super(MailingListAdminView, self).dispatch(request, *args, **kwargs)
|
return super(MailingListAdminView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -1,40 +1,34 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from ajax_select import make_ajax_form
|
from ajax_select import make_ajax_form
|
||||||
from core.models import User, Page, RealGroup, SithFile
|
from core.models import User, Page, RealGroup, MetaGroup, SithFile
|
||||||
from django.contrib.auth.models import Group as AuthGroup
|
from django.contrib.auth.models import Group as AuthGroup
|
||||||
from haystack.admin import SearchModelAdmin
|
from haystack.admin import SearchModelAdmin
|
||||||
|
|
||||||
|
|
||||||
admin.site.unregister(AuthGroup)
|
admin.site.unregister(AuthGroup)
|
||||||
|
admin.site.register(MetaGroup)
|
||||||
admin.site.register(RealGroup)
|
admin.site.register(RealGroup)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(User)
|
||||||
class UserAdmin(SearchModelAdmin):
|
class UserAdmin(SearchModelAdmin):
|
||||||
list_display = ["first_name", "last_name", "username", "email", "nick_name"]
|
list_display = ("first_name", "last_name", "username", "email", "nick_name")
|
||||||
form = make_ajax_form(
|
form = make_ajax_form(
|
||||||
User,
|
User,
|
||||||
{
|
{
|
||||||
@ -48,11 +42,9 @@ class UserAdmin(SearchModelAdmin):
|
|||||||
search_fields = ["first_name", "last_name", "username"]
|
search_fields = ["first_name", "last_name", "username"]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Page)
|
@admin.register(Page)
|
||||||
class PageAdmin(admin.ModelAdmin):
|
class PageAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("name", "_full_name", "owner_group")
|
||||||
form = make_ajax_form(
|
form = make_ajax_form(
|
||||||
Page,
|
Page,
|
||||||
{
|
{
|
||||||
@ -66,4 +58,12 @@ class PageAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(SithFile)
|
@admin.register(SithFile)
|
||||||
class SithFileAdmin(admin.ModelAdmin):
|
class SithFileAdmin(admin.ModelAdmin):
|
||||||
form = make_ajax_form(SithFile, {"parent": "files"}) # ManyToManyField
|
list_display = ("name", "owner", "size", "date", "is_in_sas")
|
||||||
|
form = make_ajax_form(
|
||||||
|
SithFile,
|
||||||
|
{
|
||||||
|
"parent": "files",
|
||||||
|
"owner": "users",
|
||||||
|
"moderator": "users",
|
||||||
|
},
|
||||||
|
) # ManyToManyField
|
||||||
|
14
core/apps.py
@ -25,6 +25,7 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.core.cache import cache
|
||||||
from django.core.signals import request_started
|
from django.core.signals import request_started
|
||||||
|
|
||||||
|
|
||||||
@ -33,26 +34,17 @@ class SithConfig(AppConfig):
|
|||||||
verbose_name = "Core app of the Sith"
|
verbose_name = "Core app of the Sith"
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
from core.models import User
|
|
||||||
from club.models import Club
|
|
||||||
from forum.models import Forum
|
from forum.models import Forum
|
||||||
|
import core.signals
|
||||||
|
|
||||||
def clear_cached_groups(**kwargs):
|
cache.clear()
|
||||||
User._group_ids = {}
|
|
||||||
User._group_name = {}
|
|
||||||
|
|
||||||
def clear_cached_memberships(**kwargs):
|
def clear_cached_memberships(**kwargs):
|
||||||
User._club_memberships = {}
|
|
||||||
Club._memberships = {}
|
|
||||||
Forum._club_memberships = {}
|
Forum._club_memberships = {}
|
||||||
|
|
||||||
print("Connecting signals!", file=sys.stderr)
|
print("Connecting signals!", file=sys.stderr)
|
||||||
request_started.connect(
|
|
||||||
clear_cached_groups, weak=False, dispatch_uid="clear_cached_groups"
|
|
||||||
)
|
|
||||||
request_started.connect(
|
request_started.connect(
|
||||||
clear_cached_memberships,
|
clear_cached_memberships,
|
||||||
weak=False,
|
weak=False,
|
||||||
dispatch_uid="clear_cached_memberships",
|
dispatch_uid="clear_cached_memberships",
|
||||||
)
|
)
|
||||||
# TODO: there may be a need to add more cache clearing
|
|
||||||
|
35
core/converters.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from core.models import Page
|
||||||
|
|
||||||
|
|
||||||
|
class FourDigitYearConverter:
|
||||||
|
regex = "[0-9]{4}"
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
def to_url(self, value):
|
||||||
|
return str(value).zfill(4)
|
||||||
|
|
||||||
|
|
||||||
|
class TwoDigitMonthConverter:
|
||||||
|
regex = "[0-9]{2}"
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
def to_url(self, value):
|
||||||
|
return str(value).zfill(2)
|
||||||
|
|
||||||
|
|
||||||
|
class BooleanStringConverter:
|
||||||
|
"""
|
||||||
|
Converter whose regex match either True or False
|
||||||
|
"""
|
||||||
|
|
||||||
|
regex = r"(True)|(False)"
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
return str(value) == "True"
|
||||||
|
|
||||||
|
def to_url(self, value):
|
||||||
|
return str(value)
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
BIN
core/fixtures/images/sas/Family/skia_sli.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
core/fixtures/images/sas/Family/skia_sli_krophil.jpg
Normal file
After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 30 KiB |
@ -1,24 +1,16 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -28,8 +20,9 @@ from ajax_select import register, LookupChannel
|
|||||||
from core.views.site import search_user
|
from core.views.site import search_user
|
||||||
from core.models import User, Group, SithFile
|
from core.models import User, Group, SithFile
|
||||||
from club.models import Club
|
from club.models import Club
|
||||||
from counter.models import Product, Counter
|
from counter.models import Product, Counter, Customer
|
||||||
from accounting.models import ClubAccount, Company
|
from accounting.models import ClubAccount, Company
|
||||||
|
from eboutic.models import BasketItem
|
||||||
|
|
||||||
|
|
||||||
def check_token(request):
|
def check_token(request):
|
||||||
@ -60,6 +53,21 @@ class UsersLookup(RightManagedLookupChannel):
|
|||||||
return item.get_display_name()
|
return item.get_display_name()
|
||||||
|
|
||||||
|
|
||||||
|
@register("customers")
|
||||||
|
class CustomerLookup(RightManagedLookupChannel):
|
||||||
|
model = Customer
|
||||||
|
|
||||||
|
def get_query(self, q, request):
|
||||||
|
users = search_user(q)
|
||||||
|
return [user.customer for user in users]
|
||||||
|
|
||||||
|
def format_match(self, obj):
|
||||||
|
return obj.user.get_mini_item()
|
||||||
|
|
||||||
|
def format_item_display(self, obj):
|
||||||
|
return f"{obj.user.get_display_name()} ({obj.account_id})"
|
||||||
|
|
||||||
|
|
||||||
@register("groups")
|
@register("groups")
|
||||||
class GroupsLookup(RightManagedLookupChannel):
|
class GroupsLookup(RightManagedLookupChannel):
|
||||||
model = Group
|
model = Group
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2023 © AE UTBM
|
||||||
# - Skia <skia@libskia.so>
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# This file is part of the website of the UTBM Student Association (AE UTBM),
|
||||||
# http://ae.utbm.fr.
|
# https://ae.utbm.fr.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
# You can find the source code of the website at https://github.com/ae-utbm/sith3
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -6,8 +6,15 @@ from django.core.management.base import BaseCommand
|
|||||||
|
|
||||||
# see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
# see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
||||||
# added "v?"
|
# added "v?"
|
||||||
|
# Please note that this does not match the version of the three.js library.
|
||||||
|
# Hence, you shall have to check this one by yourself
|
||||||
semver_regex = re.compile(
|
semver_regex = re.compile(
|
||||||
"""^v?(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"""
|
r"^v?"
|
||||||
|
r"(?P<major>\d+)"
|
||||||
|
r"\.(?P<minor>\d+)"
|
||||||
|
r"\.(?P<patch>\d+)"
|
||||||
|
r"(?:-(?P<prerelease>(?:\d+|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:\d+|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?"
|
||||||
|
r"(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +39,5 @@ class Command(compilemessages.Command):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
os.chdir("sith")
|
os.chdir("sith")
|
||||||
super(Command, self).handle(*args, **options)
|
super(Command, self).handle(*args, **options)
|
||||||
|
@ -60,7 +60,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
def compilescss(self, file):
|
def compilescss(self, file):
|
||||||
print("compiling %s" % file)
|
print("compiling %s" % file)
|
||||||
with (open(file.replace(".scss", ".css"), "w")) as newfile:
|
with open(file.replace(".scss", ".css"), "w") as newfile:
|
||||||
newfile.write(self.compile(file))
|
newfile.write(self.compile(file))
|
||||||
|
|
||||||
def removescss(self, file):
|
def removescss(self, file):
|
||||||
@ -68,7 +68,6 @@ class Command(BaseCommand):
|
|||||||
os.remove(file)
|
os.remove(file)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
if os.path.isdir(settings.STATIC_ROOT):
|
if os.path.isdir(settings.STATIC_ROOT):
|
||||||
print("---- Compiling scss files ---")
|
print("---- Compiling scss files ---")
|
||||||
self.exec_on_folder(settings.STATIC_ROOT, self.compilescss)
|
self.exec_on_folder(settings.STATIC_ROOT, self.compilescss)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding:utf-8 -*
|
# -*- coding:utf-8 -*
|
||||||
#
|
#
|
||||||
# Copyright 2016,2017
|
# Copyright 2016,2017,2023
|
||||||
# - Skia <skia@libskia.so>
|
# - Skia <skia@hya.sk>
|
||||||
#
|
#
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
||||||
# http://ae.utbm.fr.
|
# http://ae.utbm.fr.
|
||||||
@ -25,7 +25,9 @@
|
|||||||
import os
|
import os
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from io import StringIO, BytesIO
|
from io import StringIO, BytesIO
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Permission
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -53,6 +55,7 @@ from com.models import Sith, Weekmail, News, NewsDate
|
|||||||
from election.models import Election, Role, Candidature, ElectionList
|
from election.models import Election, Role, Candidature, ElectionList
|
||||||
from forum.models import Forum, ForumTopic
|
from forum.models import Forum, ForumTopic
|
||||||
from pedagogy.models import UV
|
from pedagogy.models import UV
|
||||||
|
from sas.models import Album, Picture, PeoplePictureRelation
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
@ -70,10 +73,8 @@ class Command(BaseCommand):
|
|||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
os.environ["DJANGO_COLORS"] = "nocolor"
|
os.environ["DJANGO_COLORS"] = "nocolor"
|
||||||
Site(id=4000, domain=settings.SITH_URL, name=settings.SITH_NAME).save()
|
Site(id=4000, domain=settings.SITH_URL, name=settings.SITH_NAME).save()
|
||||||
root_path = os.path.dirname(
|
root_path = Path(__file__).parent.parent.parent.parent
|
||||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
root_group, _ = Group.objects.get_or_create(name="Root")
|
||||||
)
|
|
||||||
Group(name="Root").save()
|
|
||||||
Group(name="Public").save()
|
Group(name="Public").save()
|
||||||
Group(name="Subscribers").save()
|
Group(name="Subscribers").save()
|
||||||
Group(name="Old subscribers").save()
|
Group(name="Old subscribers").save()
|
||||||
@ -83,10 +84,15 @@ class Command(BaseCommand):
|
|||||||
Group(name="Banned from buying alcohol").save()
|
Group(name="Banned from buying alcohol").save()
|
||||||
Group(name="Banned from counters").save()
|
Group(name="Banned from counters").save()
|
||||||
Group(name="Banned to subscribe").save()
|
Group(name="Banned to subscribe").save()
|
||||||
Group(name="SAS admin").save()
|
sas_admin, _ = Group.objects.get_or_create(name="SAS admin")
|
||||||
Group(name="Forum admin").save()
|
Group(name="Forum admin").save()
|
||||||
Group(name="Pedagogy admin").save()
|
Group(name="Pedagogy admin").save()
|
||||||
self.reset_index("core", "auth")
|
self.reset_index("core", "auth")
|
||||||
|
|
||||||
|
change_billing = Permission.objects.get(codename="change_billinginfo")
|
||||||
|
add_billing = Permission.objects.get(codename="add_billinginfo")
|
||||||
|
root_group.permissions.add(change_billing, add_billing)
|
||||||
|
|
||||||
root = User(
|
root = User(
|
||||||
id=0,
|
id=0,
|
||||||
username="root",
|
username="root",
|
||||||
@ -113,7 +119,8 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
club_root = SithFile(parent=None, name="clubs", is_folder=True, owner=root)
|
club_root = SithFile(parent=None, name="clubs", is_folder=True, owner=root)
|
||||||
club_root.save()
|
club_root.save()
|
||||||
SithFile(parent=None, name="SAS", is_folder=True, owner=root).save()
|
sas = SithFile(parent=None, name="SAS", is_folder=True, owner=root)
|
||||||
|
sas.save()
|
||||||
main_club = Club(
|
main_club = Club(
|
||||||
id=1,
|
id=1,
|
||||||
name=settings.SITH_MAIN_CLUB["name"],
|
name=settings.SITH_MAIN_CLUB["name"],
|
||||||
@ -148,12 +155,10 @@ class Command(BaseCommand):
|
|||||||
Counter(name="Eboutic", club=main_club, type="EBOUTIC").save()
|
Counter(name="Eboutic", club=main_club, type="EBOUTIC").save()
|
||||||
Counter(name="AE", club=main_club, type="OFFICE").save()
|
Counter(name="AE", club=main_club, type="OFFICE").save()
|
||||||
|
|
||||||
home_root.view_groups.set(
|
ae_members = Group.objects.get(name=settings.SITH_MAIN_MEMBERS_GROUP)
|
||||||
[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first()]
|
|
||||||
)
|
home_root.view_groups.set([ae_members])
|
||||||
club_root.view_groups.set(
|
club_root.view_groups.set([ae_members])
|
||||||
[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first()]
|
|
||||||
)
|
|
||||||
home_root.save()
|
home_root.save()
|
||||||
club_root.save()
|
club_root.save()
|
||||||
|
|
||||||
@ -203,6 +208,8 @@ Welcome to the wiki page!
|
|||||||
|
|
||||||
# Here we add a lot of test datas, that are not necessary for the Sith, but that provide a basic development environment
|
# Here we add a lot of test datas, that are not necessary for the Sith, but that provide a basic development environment
|
||||||
if not options["prod"]:
|
if not options["prod"]:
|
||||||
|
self.now = timezone.now().replace(hour=12)
|
||||||
|
|
||||||
# Adding user Skia
|
# Adding user Skia
|
||||||
skia = User(
|
skia = User(
|
||||||
username="skia",
|
username="skia",
|
||||||
@ -213,11 +220,17 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
skia.set_password("plop")
|
skia.set_password("plop")
|
||||||
skia.save()
|
skia.save()
|
||||||
skia.view_groups = [
|
skia.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
skia.save()
|
skia.save()
|
||||||
skia_profile_path = os.path.join(root_path, "core/fixtures/images/3.jpg")
|
skia_profile_path = (
|
||||||
|
root_path
|
||||||
|
/ "core"
|
||||||
|
/ "fixtures"
|
||||||
|
/ "images"
|
||||||
|
/ "sas"
|
||||||
|
/ "Family"
|
||||||
|
/ "skia.jpg"
|
||||||
|
)
|
||||||
with open(skia_profile_path, "rb") as f:
|
with open(skia_profile_path, "rb") as f:
|
||||||
name = str(skia.id) + "_profile.jpg"
|
name = str(skia.id) + "_profile.jpg"
|
||||||
skia_profile = SithFile(
|
skia_profile = SithFile(
|
||||||
@ -227,7 +240,7 @@ Welcome to the wiki page!
|
|||||||
owner=skia,
|
owner=skia,
|
||||||
is_folder=False,
|
is_folder=False,
|
||||||
mime_type="image/jpeg",
|
mime_type="image/jpeg",
|
||||||
size=os.path.getsize(skia_profile_path),
|
size=skia_profile_path.stat().st_size,
|
||||||
)
|
)
|
||||||
skia_profile.file.name = name
|
skia_profile.file.name = name
|
||||||
skia_profile.save()
|
skia_profile.save()
|
||||||
@ -246,9 +259,7 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
public.set_password("plop")
|
public.set_password("plop")
|
||||||
public.save()
|
public.save()
|
||||||
public.view_groups = [
|
public.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
public.save()
|
public.save()
|
||||||
# Adding user Subscriber
|
# Adding user Subscriber
|
||||||
subscriber = User(
|
subscriber = User(
|
||||||
@ -262,9 +273,7 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
subscriber.set_password("plop")
|
subscriber.set_password("plop")
|
||||||
subscriber.save()
|
subscriber.save()
|
||||||
subscriber.view_groups = [
|
subscriber.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
subscriber.save()
|
subscriber.save()
|
||||||
# Adding user old Subscriber
|
# Adding user old Subscriber
|
||||||
old_subscriber = User(
|
old_subscriber = User(
|
||||||
@ -278,9 +287,7 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
old_subscriber.set_password("plop")
|
old_subscriber.set_password("plop")
|
||||||
old_subscriber.save()
|
old_subscriber.save()
|
||||||
old_subscriber.view_groups = [
|
old_subscriber.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
old_subscriber.save()
|
old_subscriber.save()
|
||||||
# Adding user Counter admin
|
# Adding user Counter admin
|
||||||
counter = User(
|
counter = User(
|
||||||
@ -294,9 +301,7 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
counter.set_password("plop")
|
counter.set_password("plop")
|
||||||
counter.save()
|
counter.save()
|
||||||
counter.view_groups = [
|
counter.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
counter.groups.set(
|
counter.groups.set(
|
||||||
[
|
[
|
||||||
Group.objects.filter(id=settings.SITH_GROUP_COUNTER_ADMIN_ID)
|
Group.objects.filter(id=settings.SITH_GROUP_COUNTER_ADMIN_ID)
|
||||||
@ -317,9 +322,7 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
comptable.set_password("plop")
|
comptable.set_password("plop")
|
||||||
comptable.save()
|
comptable.save()
|
||||||
comptable.view_groups = [
|
comptable.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
comptable.groups.set(
|
comptable.groups.set(
|
||||||
[
|
[
|
||||||
Group.objects.filter(id=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
Group.objects.filter(id=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||||
@ -340,28 +343,49 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
u.set_password("plop")
|
u.set_password("plop")
|
||||||
u.save()
|
u.save()
|
||||||
u.view_groups = [
|
u.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
u.save()
|
u.save()
|
||||||
# Adding user Richard Batsbak
|
# Adding user Richard Batsbak
|
||||||
r = User(
|
richard = User(
|
||||||
username="rbatsbak",
|
username="rbatsbak",
|
||||||
last_name="Batsbak",
|
last_name="Batsbak",
|
||||||
first_name="Richard",
|
first_name="Richard",
|
||||||
email="richard@git.an",
|
email="richard@git.an",
|
||||||
date_of_birth="1982-06-12",
|
date_of_birth="1982-06-12",
|
||||||
)
|
)
|
||||||
r.set_password("plop")
|
richard.set_password("plop")
|
||||||
r.save()
|
richard.save()
|
||||||
r.view_groups = [
|
richard.godfathers.add(comptable)
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
richard_profile_path = (
|
||||||
]
|
root_path
|
||||||
r.save()
|
/ "core"
|
||||||
|
/ "fixtures"
|
||||||
|
/ "images"
|
||||||
|
/ "sas"
|
||||||
|
/ "Family"
|
||||||
|
/ "richard.jpg"
|
||||||
|
)
|
||||||
|
with open(richard_profile_path, "rb") as f:
|
||||||
|
name = f"{richard.id}_profile.jpg"
|
||||||
|
richard_profile = SithFile(
|
||||||
|
parent=profiles_root,
|
||||||
|
name=name,
|
||||||
|
file=resize_image(Image.open(BytesIO(f.read())), 400, "JPEG"),
|
||||||
|
owner=richard,
|
||||||
|
is_folder=False,
|
||||||
|
mime_type="image/jpeg",
|
||||||
|
size=richard_profile_path.stat().st_size,
|
||||||
|
)
|
||||||
|
richard_profile.file.name = name
|
||||||
|
richard_profile.save()
|
||||||
|
richard.profile_pict = richard_profile
|
||||||
|
richard.save()
|
||||||
|
richard.view_groups = [ae_members.id]
|
||||||
|
richard.save()
|
||||||
# Adding syntax help page
|
# Adding syntax help page
|
||||||
p = Page(name="Aide_sur_la_syntaxe")
|
p = Page(name="Aide_sur_la_syntaxe")
|
||||||
p.save(force_lock=True)
|
p.save(force_lock=True)
|
||||||
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as rm:
|
with open(root_path / "doc" / "SYNTAX.md", "r") as rm:
|
||||||
PageRev(
|
PageRev(
|
||||||
page=p, title="Aide sur la syntaxe", author=skia, content=rm.read()
|
page=p, title="Aide sur la syntaxe", author=skia, content=rm.read()
|
||||||
).save()
|
).save()
|
||||||
@ -388,7 +412,7 @@ Welcome to the wiki page!
|
|||||||
default_subscription = "un-semestre"
|
default_subscription = "un-semestre"
|
||||||
# Root
|
# Root
|
||||||
s = Subscription(
|
s = Subscription(
|
||||||
member=User.objects.filter(pk=root.pk).first(),
|
member=root,
|
||||||
subscription_type=default_subscription,
|
subscription_type=default_subscription,
|
||||||
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
|
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
|
||||||
)
|
)
|
||||||
@ -436,7 +460,7 @@ Welcome to the wiki page!
|
|||||||
s.save()
|
s.save()
|
||||||
# Richard
|
# Richard
|
||||||
s = Subscription(
|
s = Subscription(
|
||||||
member=User.objects.filter(pk=r.pk).first(),
|
member=User.objects.filter(pk=richard.pk).first(),
|
||||||
subscription_type=default_subscription,
|
subscription_type=default_subscription,
|
||||||
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
|
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
|
||||||
)
|
)
|
||||||
@ -488,7 +512,7 @@ Welcome to the wiki page!
|
|||||||
Club(
|
Club(
|
||||||
name="Woenzel'UT", unix_name="woenzel", address="Woenzel", parent=guyut
|
name="Woenzel'UT", unix_name="woenzel", address="Woenzel", parent=guyut
|
||||||
).save()
|
).save()
|
||||||
Membership(user=skia, club=main_club, role=3, description="").save()
|
Membership(user=skia, club=main_club, role=3).save()
|
||||||
troll = Club(
|
troll = Club(
|
||||||
name="Troll Penché",
|
name="Troll Penché",
|
||||||
unix_name="troll",
|
unix_name="troll",
|
||||||
@ -505,8 +529,10 @@ Welcome to the wiki page!
|
|||||||
refound.save()
|
refound.save()
|
||||||
|
|
||||||
# Counters
|
# Counters
|
||||||
|
subscribers = Group.objects.get(name="Subscribers")
|
||||||
|
old_subscribers = Group.objects.get(name="Old subscribers")
|
||||||
Customer(user=skia, account_id="6568j", amount=0).save()
|
Customer(user=skia, account_id="6568j", amount=0).save()
|
||||||
Customer(user=r, account_id="4000k", amount=0).save()
|
Customer(user=richard, account_id="4000k", amount=0).save()
|
||||||
p = ProductType(name="Bières bouteilles")
|
p = ProductType(name="Bières bouteilles")
|
||||||
p.save()
|
p.save()
|
||||||
c = ProductType(name="Cotisations")
|
c = ProductType(name="Cotisations")
|
||||||
@ -525,6 +551,9 @@ Welcome to the wiki page!
|
|||||||
club=main_club,
|
club=main_club,
|
||||||
)
|
)
|
||||||
cotis.save()
|
cotis.save()
|
||||||
|
cotis.buying_groups.add(subscribers)
|
||||||
|
cotis.buying_groups.add(old_subscribers)
|
||||||
|
cotis.save()
|
||||||
cotis2 = Product(
|
cotis2 = Product(
|
||||||
name="Cotis 2 semestres",
|
name="Cotis 2 semestres",
|
||||||
code="2SCOTIZ",
|
code="2SCOTIZ",
|
||||||
@ -535,6 +564,9 @@ Welcome to the wiki page!
|
|||||||
club=main_club,
|
club=main_club,
|
||||||
)
|
)
|
||||||
cotis2.save()
|
cotis2.save()
|
||||||
|
cotis2.buying_groups.add(subscribers)
|
||||||
|
cotis2.buying_groups.add(old_subscribers)
|
||||||
|
cotis2.save()
|
||||||
refill = Product(
|
refill = Product(
|
||||||
name="Rechargement 15 €",
|
name="Rechargement 15 €",
|
||||||
code="15REFILL",
|
code="15REFILL",
|
||||||
@ -545,6 +577,8 @@ Welcome to the wiki page!
|
|||||||
club=main_club,
|
club=main_club,
|
||||||
)
|
)
|
||||||
refill.save()
|
refill.save()
|
||||||
|
refill.buying_groups.add(subscribers)
|
||||||
|
refill.save()
|
||||||
barb = Product(
|
barb = Product(
|
||||||
name="Barbar",
|
name="Barbar",
|
||||||
code="BARB",
|
code="BARB",
|
||||||
@ -553,8 +587,11 @@ Welcome to the wiki page!
|
|||||||
selling_price="1.7",
|
selling_price="1.7",
|
||||||
special_selling_price="1.6",
|
special_selling_price="1.6",
|
||||||
club=main_club,
|
club=main_club,
|
||||||
|
limit_age=18,
|
||||||
)
|
)
|
||||||
barb.save()
|
barb.save()
|
||||||
|
barb.buying_groups.add(subscribers)
|
||||||
|
barb.save()
|
||||||
cble = Product(
|
cble = Product(
|
||||||
name="Chimay Bleue",
|
name="Chimay Bleue",
|
||||||
code="CBLE",
|
code="CBLE",
|
||||||
@ -563,8 +600,11 @@ Welcome to the wiki page!
|
|||||||
selling_price="1.7",
|
selling_price="1.7",
|
||||||
special_selling_price="1.6",
|
special_selling_price="1.6",
|
||||||
club=main_club,
|
club=main_club,
|
||||||
|
limit_age=18,
|
||||||
)
|
)
|
||||||
cble.save()
|
cble.save()
|
||||||
|
cble.buying_groups.add(subscribers)
|
||||||
|
cble.save()
|
||||||
cons = Product(
|
cons = Product(
|
||||||
name="Consigne Eco-cup",
|
name="Consigne Eco-cup",
|
||||||
code="CONS",
|
code="CONS",
|
||||||
@ -574,7 +614,6 @@ Welcome to the wiki page!
|
|||||||
special_selling_price="1",
|
special_selling_price="1",
|
||||||
club=main_club,
|
club=main_club,
|
||||||
)
|
)
|
||||||
cons.id = 1152
|
|
||||||
cons.save()
|
cons.save()
|
||||||
dcons = Product(
|
dcons = Product(
|
||||||
name="Déconsigne Eco-cup",
|
name="Déconsigne Eco-cup",
|
||||||
@ -585,9 +624,8 @@ Welcome to the wiki page!
|
|||||||
special_selling_price="-1",
|
special_selling_price="-1",
|
||||||
club=main_club,
|
club=main_club,
|
||||||
)
|
)
|
||||||
dcons.id = 1151
|
|
||||||
dcons.save()
|
dcons.save()
|
||||||
Product(
|
cors = Product(
|
||||||
name="Corsendonk",
|
name="Corsendonk",
|
||||||
code="CORS",
|
code="CORS",
|
||||||
product_type=p,
|
product_type=p,
|
||||||
@ -595,8 +633,12 @@ Welcome to the wiki page!
|
|||||||
selling_price="1.7",
|
selling_price="1.7",
|
||||||
special_selling_price="1.6",
|
special_selling_price="1.6",
|
||||||
club=main_club,
|
club=main_club,
|
||||||
).save()
|
limit_age=18,
|
||||||
Product(
|
)
|
||||||
|
cors.save()
|
||||||
|
cors.buying_groups.add(subscribers)
|
||||||
|
cors.save()
|
||||||
|
carolus = Product(
|
||||||
name="Carolus",
|
name="Carolus",
|
||||||
code="CARO",
|
code="CARO",
|
||||||
product_type=p,
|
product_type=p,
|
||||||
@ -604,7 +646,11 @@ Welcome to the wiki page!
|
|||||||
selling_price="1.7",
|
selling_price="1.7",
|
||||||
special_selling_price="1.6",
|
special_selling_price="1.6",
|
||||||
club=main_club,
|
club=main_club,
|
||||||
).save()
|
limit_age=18,
|
||||||
|
)
|
||||||
|
carolus.save()
|
||||||
|
carolus.buying_groups.add(subscribers)
|
||||||
|
carolus.save()
|
||||||
mde = Counter.objects.filter(name="MDE").first()
|
mde = Counter.objects.filter(name="MDE").first()
|
||||||
mde.products.add(barb)
|
mde.products.add(barb)
|
||||||
mde.products.add(cble)
|
mde.products.add(cble)
|
||||||
@ -793,11 +839,17 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
sli.set_password("plop")
|
sli.set_password("plop")
|
||||||
sli.save()
|
sli.save()
|
||||||
sli.view_groups = [
|
sli.view_groups = [ae_members.id]
|
||||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
|
||||||
]
|
|
||||||
sli.save()
|
sli.save()
|
||||||
sli_profile_path = os.path.join(root_path, "core/fixtures/images/5.jpg")
|
sli_profile_path = (
|
||||||
|
root_path
|
||||||
|
/ "core"
|
||||||
|
/ "fixtures"
|
||||||
|
/ "images"
|
||||||
|
/ "sas"
|
||||||
|
/ "Family"
|
||||||
|
/ "sli.jpg"
|
||||||
|
)
|
||||||
with open(sli_profile_path, "rb") as f:
|
with open(sli_profile_path, "rb") as f:
|
||||||
name = str(sli.id) + "_profile.jpg"
|
name = str(sli.id) + "_profile.jpg"
|
||||||
sli_profile = SithFile(
|
sli_profile = SithFile(
|
||||||
@ -807,7 +859,7 @@ Welcome to the wiki page!
|
|||||||
owner=sli,
|
owner=sli,
|
||||||
is_folder=False,
|
is_folder=False,
|
||||||
mime_type="image/jpeg",
|
mime_type="image/jpeg",
|
||||||
size=os.path.getsize(sli_profile_path),
|
size=sli_profile_path.stat().st_size,
|
||||||
)
|
)
|
||||||
sli_profile.file.name = name
|
sli_profile.file.name = name
|
||||||
sli_profile.save()
|
sli_profile.save()
|
||||||
@ -823,7 +875,15 @@ Welcome to the wiki page!
|
|||||||
)
|
)
|
||||||
krophil.set_password("plop")
|
krophil.set_password("plop")
|
||||||
krophil.save()
|
krophil.save()
|
||||||
krophil_profile_path = os.path.join(root_path, "core/fixtures/images/6.jpg")
|
krophil_profile_path = (
|
||||||
|
root_path
|
||||||
|
/ "core"
|
||||||
|
/ "fixtures"
|
||||||
|
/ "images"
|
||||||
|
/ "sas"
|
||||||
|
/ "Family"
|
||||||
|
/ "krophil.jpg"
|
||||||
|
)
|
||||||
with open(krophil_profile_path, "rb") as f:
|
with open(krophil_profile_path, "rb") as f:
|
||||||
name = str(krophil.id) + "_profile.jpg"
|
name = str(krophil.id) + "_profile.jpg"
|
||||||
krophil_profile = SithFile(
|
krophil_profile = SithFile(
|
||||||
@ -833,7 +893,7 @@ Welcome to the wiki page!
|
|||||||
owner=krophil,
|
owner=krophil,
|
||||||
is_folder=False,
|
is_folder=False,
|
||||||
mime_type="image/jpeg",
|
mime_type="image/jpeg",
|
||||||
size=os.path.getsize(krophil_profile_path),
|
size=krophil_profile_path.stat().st_size,
|
||||||
)
|
)
|
||||||
krophil_profile.file.name = name
|
krophil_profile.file.name = name
|
||||||
krophil_profile.save()
|
krophil_profile.save()
|
||||||
@ -856,7 +916,7 @@ Welcome to the wiki page!
|
|||||||
Membership(
|
Membership(
|
||||||
user=comunity,
|
user=comunity,
|
||||||
club=bar_club,
|
club=bar_club,
|
||||||
start_date=timezone.now(),
|
start_date=self.now,
|
||||||
role=settings.SITH_CLUB_ROLES_ID["Board member"],
|
role=settings.SITH_CLUB_ROLES_ID["Board member"],
|
||||||
).save()
|
).save()
|
||||||
# Adding user tutu
|
# Adding user tutu
|
||||||
@ -1015,7 +1075,7 @@ Welcome to the wiki page!
|
|||||||
ForumTopic(forum=hall)
|
ForumTopic(forum=hall)
|
||||||
|
|
||||||
# News
|
# News
|
||||||
friday = timezone.now()
|
friday = self.now
|
||||||
while friday.weekday() != 4:
|
while friday.weekday() != 4:
|
||||||
friday += timedelta(hours=6)
|
friday += timedelta(hours=6)
|
||||||
friday.replace(hour=20, minute=0, second=0)
|
friday.replace(hour=20, minute=0, second=0)
|
||||||
@ -1033,8 +1093,8 @@ Welcome to the wiki page!
|
|||||||
n.save()
|
n.save()
|
||||||
NewsDate(
|
NewsDate(
|
||||||
news=n,
|
news=n,
|
||||||
start_date=timezone.now() + timedelta(hours=70),
|
start_date=self.now + timedelta(hours=70),
|
||||||
end_date=timezone.now() + timedelta(hours=72),
|
end_date=self.now + timedelta(hours=72),
|
||||||
).save()
|
).save()
|
||||||
n = News(
|
n = News(
|
||||||
title="Repas barman",
|
title="Repas barman",
|
||||||
@ -1050,8 +1110,8 @@ Welcome to the wiki page!
|
|||||||
n.save()
|
n.save()
|
||||||
NewsDate(
|
NewsDate(
|
||||||
news=n,
|
news=n,
|
||||||
start_date=timezone.now() + timedelta(hours=72),
|
start_date=self.now + timedelta(hours=72),
|
||||||
end_date=timezone.now() + timedelta(hours=84),
|
end_date=self.now + timedelta(hours=84),
|
||||||
).save()
|
).save()
|
||||||
n = News(
|
n = News(
|
||||||
title="Repas fromager",
|
title="Repas fromager",
|
||||||
@ -1066,8 +1126,8 @@ Welcome to the wiki page!
|
|||||||
n.save()
|
n.save()
|
||||||
NewsDate(
|
NewsDate(
|
||||||
news=n,
|
news=n,
|
||||||
start_date=timezone.now() + timedelta(hours=96),
|
start_date=self.now + timedelta(hours=96),
|
||||||
end_date=timezone.now() + timedelta(hours=100),
|
end_date=self.now + timedelta(hours=100),
|
||||||
).save()
|
).save()
|
||||||
n = News(
|
n = News(
|
||||||
title="SdF",
|
title="SdF",
|
||||||
@ -1083,7 +1143,7 @@ Welcome to the wiki page!
|
|||||||
NewsDate(
|
NewsDate(
|
||||||
news=n,
|
news=n,
|
||||||
start_date=friday + timedelta(hours=24 * 7 + 1),
|
start_date=friday + timedelta(hours=24 * 7 + 1),
|
||||||
end_date=timezone.now() + timedelta(hours=24 * 7 + 9),
|
end_date=self.now + timedelta(hours=24 * 7 + 9),
|
||||||
).save()
|
).save()
|
||||||
# Weekly
|
# Weekly
|
||||||
n = News(
|
n = News(
|
||||||
@ -1136,3 +1196,106 @@ Welcome to the wiki page!
|
|||||||
hours_THE=121,
|
hours_THE=121,
|
||||||
hours_TE=4,
|
hours_TE=4,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
|
# SAS
|
||||||
|
skia.groups.add(sas_admin.id)
|
||||||
|
sas_fixtures_path = root_path / "core" / "fixtures" / "images" / "sas"
|
||||||
|
for f in sas_fixtures_path.glob("*"):
|
||||||
|
if f.is_dir():
|
||||||
|
album = Album(
|
||||||
|
parent=sas,
|
||||||
|
name=f.name,
|
||||||
|
owner=root,
|
||||||
|
is_folder=True,
|
||||||
|
is_in_sas=True,
|
||||||
|
is_moderated=True,
|
||||||
|
)
|
||||||
|
album.clean()
|
||||||
|
album.save()
|
||||||
|
for p in f.iterdir():
|
||||||
|
pict = Picture(
|
||||||
|
parent=album,
|
||||||
|
name=p.name,
|
||||||
|
file=resize_image(
|
||||||
|
Image.open(BytesIO(p.read_bytes())), 1000, "JPEG"
|
||||||
|
),
|
||||||
|
owner=root,
|
||||||
|
is_folder=False,
|
||||||
|
is_in_sas=True,
|
||||||
|
is_moderated=True,
|
||||||
|
mime_type="image/jpeg",
|
||||||
|
size=p.stat().st_size,
|
||||||
|
)
|
||||||
|
pict.file.name = p.name
|
||||||
|
pict.clean()
|
||||||
|
pict.generate_thumbnails()
|
||||||
|
pict.save()
|
||||||
|
|
||||||
|
p = Picture.objects.get(name="skia.jpg")
|
||||||
|
PeoplePictureRelation(user=skia, picture=p).save()
|
||||||
|
p = Picture.objects.get(name="sli.jpg")
|
||||||
|
PeoplePictureRelation(user=sli, picture=p).save()
|
||||||
|
p = Picture.objects.get(name="krophil.jpg")
|
||||||
|
PeoplePictureRelation(user=krophil, picture=p).save()
|
||||||
|
p = Picture.objects.get(name="skia_sli.jpg")
|
||||||
|
PeoplePictureRelation(user=skia, picture=p).save()
|
||||||
|
PeoplePictureRelation(user=sli, picture=p).save()
|
||||||
|
p = Picture.objects.get(name="skia_sli_krophil.jpg")
|
||||||
|
PeoplePictureRelation(user=skia, picture=p).save()
|
||||||
|
PeoplePictureRelation(user=sli, picture=p).save()
|
||||||
|
PeoplePictureRelation(user=krophil, picture=p).save()
|
||||||
|
p = Picture.objects.get(name="richard.jpg")
|
||||||
|
PeoplePictureRelation(user=richard, picture=p).save()
|
||||||
|
|
||||||
|
with open(skia_profile_path, "rb") as f:
|
||||||
|
name = str(skia.id) + "_profile.jpg"
|
||||||
|
skia_profile = SithFile(
|
||||||
|
parent=profiles_root,
|
||||||
|
name=name,
|
||||||
|
file=resize_image(Image.open(BytesIO(f.read())), 400, "JPEG"),
|
||||||
|
owner=skia,
|
||||||
|
is_folder=False,
|
||||||
|
mime_type="image/jpeg",
|
||||||
|
size=skia_profile_path.stat().st_size,
|
||||||
|
)
|
||||||
|
skia_profile.file.name = name
|
||||||
|
skia_profile.save()
|
||||||
|
skia.profile_pict = skia_profile
|
||||||
|
skia.save()
|
||||||
|
|
||||||
|
# Create some additional data for galaxy to work with
|
||||||
|
root.godfathers.add(skia)
|
||||||
|
skia.godfathers.add(root)
|
||||||
|
sli.godfathers.add(skia)
|
||||||
|
richard.godchildren.add(subscriber)
|
||||||
|
richard.godchildren.add(public)
|
||||||
|
Membership(
|
||||||
|
user=sli,
|
||||||
|
club=troll,
|
||||||
|
role=9,
|
||||||
|
description="Padawan Troll",
|
||||||
|
start_date=self.now - timedelta(days=17),
|
||||||
|
).save()
|
||||||
|
Membership(
|
||||||
|
user=krophil,
|
||||||
|
club=troll,
|
||||||
|
role=10,
|
||||||
|
description="Maitre Troll",
|
||||||
|
start_date=self.now - timedelta(days=200),
|
||||||
|
).save()
|
||||||
|
Membership(
|
||||||
|
user=skia,
|
||||||
|
club=troll,
|
||||||
|
role=2,
|
||||||
|
description="Grand Ancien Troll",
|
||||||
|
start_date=self.now - timedelta(days=400),
|
||||||
|
end_date=self.now - timedelta(days=86),
|
||||||
|
).save()
|
||||||
|
Membership(
|
||||||
|
user=richard,
|
||||||
|
club=troll,
|
||||||
|
role=2,
|
||||||
|
description="",
|
||||||
|
start_date=self.now - timedelta(days=200),
|
||||||
|
end_date=self.now - timedelta(days=100),
|
||||||
|
).save()
|
||||||
|