2 Commits

Author SHA1 Message Date
858199e476 Modification of the weekmail template 2022-09-25 22:56:39 +02:00
f6ecbd899d Add of some modifications in the weekmail model 2022-09-25 22:55:39 +02:00
439 changed files with 12436 additions and 18178 deletions

View File

@ -1,8 +0,0 @@
name: "Compile messages"
description: "Compile the gettext translation messages"
runs:
using: composite
steps:
- name: Setup project
run: poetry run ./manage.py compilemessages
shell: bash

View File

@ -1,57 +0,0 @@
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 libgraphviz-dev
version: 1.0 # increment to reset cache
- name: Install dependencies
run: |
sudo apt update
sudo apt install gettext 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 --with docs,tests
shell: bash
- name: Install xapian
run: poetry run ./manage.py install_xapian
shell: bash
- name: Compile gettext messages
run: poetry run ./manage.py compilemessages
shell: bash

View File

@ -1,10 +0,0 @@
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

View File

@ -1,18 +0,0 @@
# 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] "

View File

@ -1,42 +0,0 @@
name: Sith 3 CI
on:
push:
branches: [master, taiste]
pull_request:
branches: [master, taiste]
workflow_dispatch:
jobs:
ruff:
name: Ruff lint & format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: ruff format
uses: chartboost/ruff-action@v1 # format
with:
args: format --diff
- name: ruff check
uses: chartboost/ruff-action@v1 # lint
tests:
name: Run tests and generate coverage report
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- uses: ./.github/actions/setup_project
- uses: ./.github/actions/setup_xapian
- uses: ./.github/actions/compile_messages
- name: Run tests
run: poetry run coverage run -m pytest
- 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

View File

@ -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/sith/.local/bin:$PATH" export PATH="$HOME/.poetry/bin:$PATH"
pushd ${{secrets.SITH_PATH}} pushd ${{secrets.SITH_PATH}}
git pull git pull
poetry install poetry update
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

View File

@ -1,63 +0,0 @@
name: Sith3 taiste
on:
push:
branches: [taiste]
workflow_dispatch:
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 Normal file
View File

@ -0,0 +1,83 @@
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
View File

@ -7,11 +7,9 @@ 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/

View File

@ -16,4 +16,3 @@ 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>

View File

@ -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: .

View File

@ -1,31 +0,0 @@
# Contributors
Thanks to everyone who has contributed to this project! We appreciate your time and effort.
## Copyright
> All contributions to this project are subject to the copyright owned by the Association des Étudiants de l'Université de Technologie de Belfort-Montbéliard (AE UTBM), for both past and future years. By making a contribution to this project, you acknowledge and agree that AE UTBM has the exclusive right to use, distribute, and modify your contribution, as well as to license others to do the same, in any way they see fit.
## License
This project was previously released under the MIT license, but it has since been changed to the GPL v3 license. Any contributions made to this project before the switch to GPL v3 are still subject to the MIT license, while contributions made after the switch are subject to the GPL v3 license.
## List of Contributors
- [@Hyask](https://github.com/Hyask) — Florent "Skia" Jacquet <skia@hya.sk>
- [@klmp200](https://github.com/klmp200) — Antoine "Sli" Bartuccio <antoine@bartuccio.fr>
- [@nab-os](https://github.com/nab-os) (AKA Gnikwo) — Sasha "Nabos" Ballet <nabos@glargh.fr>
- [@Krophil](https://github.com/Krophil) — Pierre "Krophil'" Brunet <pierre.brunet@krophil.fr>
- [@guillaume-renaud](https://github.com/guillaume-renaud) — Guillaume "Lo-J" RENAUD <renaudg779@gmail.com>
- [@imperosol](https://github.com/imperosol) — Thomas "Maréchal" Girod <thgirod@hotmail.com>
- [@TheoDurr](https://github.com/TheoDurr) — Théo "Ailé" Durr <git@theodurr.fr>
- [@RTrioux](https://github.com/RTrioux) — Robin "Vial" Trioux
- [@TheRolfFR](https://github.com/TheRolfFR) — Yann "Réseau" Le Vaguerès
- [@Magador](https://github.com/Magador) — Lucie "Magador" Lenglet
- [@lsacienne](https://github.com/lsacienne) — Alexandre "L'Sacienne" Viala
- [@Juknum](https://github.com/Juknum) — Julien "Tinople" Constant
- [@Tartofraise](https://github.com/Tartofraise) — Ryan "Soldat" Hadj-Mebarek
- [@FrancescoWitz](https://github.com/FrancescoWitz) — Francesco "Och" WITZ
- [@maxence-leblanc](https://github.com/maxence-leblanc) — Maxence "Juste" LEBLANC
_If you've contributed to this project and your name isn't on the list, please let us know so we can add you. And if you've contributed anonymously, thank you! We appreciate your contributions just as much as those from named contributors._

View File

@ -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/971448179075731476?label=Discord&logo=discord&style=for-the-badge"> <img src="https://img.shields.io/discord/889796155523874847?label=Discord&logo=discord&style=for-the-badge">
</a> </a>
</p> </p>
@ -37,4 +37,5 @@
</li> </li>
</ul> </ul>
> This project is licensed under GNU GPL, see the LICENSE file at the top of the repository for more details. > This project is licenced under GNU GPL, see the LICENSE file at the top of the repository for more details.

View File

@ -1,19 +1,23 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #

View File

@ -1,27 +1,32 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.contrib import admin from django.contrib import admin
from accounting.models import * from accounting.models import *
admin.site.register(BankAccount) admin.site.register(BankAccount)
admin.site.register(ClubAccount) admin.site.register(ClubAccount)
admin.site.register(GeneralJournal) admin.site.register(GeneralJournal)

View File

@ -1,14 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
import django.core.validators
import accounting.models import accounting.models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [] dependencies = []
operations = [ operations = [

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
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"),

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import phonenumber_field.modelfields
from django.db import migrations, models from django.db import migrations, models
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 = [

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
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 = [

View File

@ -5,6 +5,7 @@ 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 = [

View File

@ -1,36 +1,40 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from decimal import Decimal
from django.conf import settings
from django.core import validators
from django.core.exceptions import ValidationError
from django.db import models
from django.template import defaultfilters
from django.urls import reverse from django.urls import reverse
from django.core.exceptions import ValidationError
from django.core import validators
from django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.template import defaultfilters
from phonenumber_field.modelfields import PhoneNumberField from phonenumber_field.modelfields import PhoneNumberField
from decimal import Decimal
from core.models import User, SithFile
from club.models import Club from club.models import Club
from core.models import SithFile, User
class CurrencyField(models.DecimalField): class CurrencyField(models.DecimalField):
@ -70,7 +74,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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return True return True
return False return False
@ -121,9 +125,7 @@ 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_anonymous: if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
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"]:
@ -160,9 +162,7 @@ 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_anonymous: if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return False
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return True return True
return False return False
@ -233,9 +233,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_anonymous: if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
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
@ -245,7 +243,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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): if user.is_in_group(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
@ -424,9 +422,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_anonymous: if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
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
@ -439,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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return True return True
if self.journal.closed: if self.journal.closed:
return False return False
@ -495,9 +491,7 @@ 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_anonymous: if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return False
if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return True return True
return False return False
@ -568,8 +562,6 @@ 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):

View File

@ -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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and not object.club_accounts.exists() %} {% if user.is_in_group(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>

View File

@ -9,7 +9,7 @@
<h4> <h4>
{% trans %}Accounting{% endtrans %} {% trans %}Accounting{% endtrans %}
</h4> </h4>
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %} {% if user.is_in_group(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>

View File

@ -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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %} {% if user.is_in_group(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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and j.operations.count() == 0 %} {% if user.is_in_group(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>

View File

@ -6,12 +6,11 @@
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
{% if user.is_root {% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or 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>

View File

@ -84,10 +84,7 @@
<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 o.journal.club_account.bank_account.name not in ["AE TI", "TI"]
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
%}
{% if not o.journal.closed %} {% if not o.journal.closed %}
<a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a> <a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a>
{% endif %} {% endif %}

View File

@ -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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %} {% if user.is_in_group(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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %} {% if user.is_in_group(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 %}

View File

@ -1,103 +1,115 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from datetime import date, timedelta
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from django.core.management import call_command
from datetime import date, timedelta
from core.models import User
from accounting.models import ( from accounting.models import (
AccountingType,
GeneralJournal, GeneralJournal,
Label,
Operation, Operation,
Label,
AccountingType,
SimplifiedAccountingType, SimplifiedAccountingType,
) )
from core.models import User
class RefoundAccountTest(TestCase): class RefoundAccountTest(TestCase):
@classmethod def setUp(self):
def setUpTestData(cls): call_command("populate")
cls.skia = User.objects.get(username="skia") self.skia = User.objects.filter(username="skia").first()
# reffil skia's account # reffil skia's account
cls.skia.customer.amount = 800 self.skia.customer.amount = 800
cls.skia.customer.save() self.skia.customer.save()
cls.refound_account_url = reverse("accounting:refound_account")
def test_permission_denied(self): def test_permission_denied(self):
self.client.force_login(User.objects.get(username="guy")) self.client.login(username="guy", password="plop")
response_post = self.client.post( response_post = self.client.post(
self.refound_account_url, {"user": self.skia.id} reverse("accounting:refound_account"), {"user": self.skia.id}
) )
response_get = self.client.get(self.refound_account_url) response_get = self.client.get(reverse("accounting:refound_account"))
assert response_get.status_code == 403 self.assertTrue(response_get.status_code == 403)
assert response_post.status_code == 403 self.assertTrue(response_post.status_code == 403)
def test_root_granteed(self): def test_root_granteed(self):
self.client.force_login(User.objects.get(username="root")) self.client.login(username="root", password="plop")
response = self.client.post(self.refound_account_url, {"user": self.skia.id}) response_post = self.client.post(
self.assertRedirects(response, self.refound_account_url) reverse("accounting:refound_account"), {"user": self.skia.id}
self.skia.refresh_from_db() )
response = self.client.get(self.refound_account_url) self.skia = User.objects.filter(username="skia").first()
assert response.status_code == 200 response_get = self.client.get(reverse("accounting:refound_account"))
assert '<form action="" method="post">' in str(response.content) self.assertFalse(response_get.status_code == 403)
assert self.skia.customer.amount == 0 self.assertTrue('<form action="" method="post">' in str(response_get.content))
self.assertFalse(response_post.status_code == 403)
self.assertTrue(self.skia.customer.amount == 0)
def test_comptable_granteed(self): def test_comptable_granteed(self):
self.client.force_login(User.objects.get(username="comptable")) self.client.login(username="comptable", password="plop")
response = self.client.post(self.refound_account_url, {"user": self.skia.id}) response_post = self.client.post(
self.assertRedirects(response, self.refound_account_url) reverse("accounting:refound_account"), {"user": self.skia.id}
self.skia.refresh_from_db() )
response = self.client.get(self.refound_account_url) self.skia = User.objects.filter(username="skia").first()
assert response.status_code == 200 response_get = self.client.get(reverse("accounting:refound_account"))
assert '<form action="" method="post">' in str(response.content) self.assertFalse(response_get.status_code == 403)
assert self.skia.customer.amount == 0 self.assertTrue('<form action="" method="post">' in str(response_get.content))
self.assertFalse(response_post.status_code == 403)
self.assertTrue(self.skia.customer.amount == 0)
class JournalTest(TestCase): class JournalTest(TestCase):
@classmethod def setUp(self):
def setUpTestData(cls): call_command("populate")
cls.journal = GeneralJournal.objects.get(id=1) self.journal = GeneralJournal.objects.filter(id=1).first()
def test_permission_granted(self): def test_permission_granted(self):
self.client.force_login(User.objects.get(username="comptable")) self.client.login(username="comptable", password="plop")
response_get = self.client.get( response_get = self.client.get(
reverse("accounting:journal_details", args=[self.journal.id]) reverse("accounting:journal_details", args=[self.journal.id])
) )
assert response_get.status_code == 200 self.assertTrue(response_get.status_code == 200)
assert "<td>M\\xc3\\xa9thode de paiement</td>" in str(response_get.content) self.assertTrue(
"<td>M\\xc3\\xa9thode de paiement</td>" in str(response_get.content)
)
def test_permission_not_granted(self): def test_permission_not_granted(self):
self.client.force_login(User.objects.get(username="skia")) self.client.login(username="skia", password="plop")
response_get = self.client.get( response_get = self.client.get(
reverse("accounting:journal_details", args=[self.journal.id]) reverse("accounting:journal_details", args=[self.journal.id])
) )
assert response_get.status_code == 403 self.assertTrue(response_get.status_code == 403)
assert "<td>M\xc3\xa9thode de paiement</td>" not in str(response_get.content) self.assertFalse(
"<td>M\xc3\xa9thode de paiement</td>" in str(response_get.content)
)
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"
) )
@ -107,8 +119,9 @@ class OperationTest(TestCase):
code="443", label="Ce code n'existe pas", movement_type="CREDIT" code="443", label="Ce code n'existe pas", movement_type="CREDIT"
) )
at.save() at.save()
l = Label.objects.create(club_account=self.journal.club_account, name="bob") l = Label(club_account=self.journal.club_account, name="bob")
self.client.force_login(User.objects.get(username="comptable")) l.save()
self.client.login(username="comptable", password="plop")
self.op1 = Operation( self.op1 = Operation(
journal=self.journal, journal=self.journal,
date=date.today(), date=date.today(),
@ -137,7 +150,8 @@ class OperationTest(TestCase):
self.op2.save() self.op2.save()
def test_new_operation(self): def test_new_operation(self):
at = AccountingType.objects.get(code="604") self.client.login(username="comptable", password="plop")
at = AccountingType.objects.filter(code="604").first()
response = self.client.post( response = self.client.post(
reverse("accounting:op_new", args=[self.journal.id]), reverse("accounting:op_new", args=[self.journal.id]),
{ {
@ -169,7 +183,8 @@ class OperationTest(TestCase):
self.assertTrue("<td>Le fantome de la nuit</td>" in str(response_get.content)) self.assertTrue("<td>Le fantome de la nuit</td>" in str(response_get.content))
def test_bad_new_operation(self): def test_bad_new_operation(self):
AccountingType.objects.get(code="604") self.client.login(username="comptable", password="plop")
AccountingType.objects.filter(code="604").first()
response = self.client.post( response = self.client.post(
reverse("accounting:op_new", args=[self.journal.id]), reverse("accounting:op_new", args=[self.journal.id]),
{ {
@ -195,7 +210,7 @@ class OperationTest(TestCase):
) )
def test_new_operation_not_authorized(self): def test_new_operation_not_authorized(self):
self.client.force_login(self.skia) self.client.login(username="skia", password="plop")
at = AccountingType.objects.filter(code="604").first() at = AccountingType.objects.filter(code="604").first()
response = self.client.post( response = self.client.post(
reverse("accounting:op_new", args=[self.journal.id]), reverse("accounting:op_new", args=[self.journal.id]),
@ -222,6 +237,7 @@ class OperationTest(TestCase):
) )
def test__operation_simple_accounting(self): def test__operation_simple_accounting(self):
self.client.login(username="comptable", password="plop")
sat = SimplifiedAccountingType.objects.all().first() sat = SimplifiedAccountingType.objects.all().first()
response = self.client.post( response = self.client.post(
reverse("accounting:op_new", args=[self.journal.id]), reverse("accounting:op_new", args=[self.journal.id]),
@ -258,12 +274,14 @@ class OperationTest(TestCase):
) )
def test_nature_statement(self): def test_nature_statement(self):
self.client.login(username="comptable", password="plop")
response = self.client.get( response = self.client.get(
reverse("accounting:journal_nature_statement", args=[self.journal.id]) reverse("accounting:journal_nature_statement", args=[self.journal.id])
) )
self.assertContains(response, "bob (Troll Penché) : 3.00", status_code=200) self.assertContains(response, "bob (Troll Penché) : 3.00", status_code=200)
def test_person_statement(self): def test_person_statement(self):
self.client.login(username="comptable", password="plop")
response = self.client.get( response = self.client.get(
reverse("accounting:journal_person_statement", args=[self.journal.id]) reverse("accounting:journal_person_statement", args=[self.journal.id])
) )
@ -285,6 +303,7 @@ class OperationTest(TestCase):
) )
def test_accounting_statement(self): def test_accounting_statement(self):
self.client.login(username="comptable", password="plop")
response = self.client.get( response = self.client.get(
reverse("accounting:journal_accounting_statement", args=[self.journal.id]) reverse("accounting:journal_accounting_statement", args=[self.journal.id])
) )

View File

@ -1,144 +1,154 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.urls import path from django.urls import re_path
from accounting.views import * from accounting.views import *
urlpatterns = [ urlpatterns = [
# Accounting types # Accounting types
path( re_path(
"simple_type/", r"^simple_type$",
SimplifiedAccountingTypeListView.as_view(), SimplifiedAccountingTypeListView.as_view(),
name="simple_type_list", name="simple_type_list",
), ),
path( re_path(
"simple_type/create/", r"^simple_type/create$",
SimplifiedAccountingTypeCreateView.as_view(), SimplifiedAccountingTypeCreateView.as_view(),
name="simple_type_new", name="simple_type_new",
), ),
path( re_path(
"simple_type/<int:type_id>/edit/", r"^simple_type/(?P<type_id>[0-9]+)/edit$",
SimplifiedAccountingTypeEditView.as_view(), SimplifiedAccountingTypeEditView.as_view(),
name="simple_type_edit", name="simple_type_edit",
), ),
# Accounting types # Accounting types
path("type/", AccountingTypeListView.as_view(), name="type_list"), re_path(r"^type$", AccountingTypeListView.as_view(), name="type_list"),
path("type/create/", AccountingTypeCreateView.as_view(), name="type_new"), re_path(r"^type/create$", AccountingTypeCreateView.as_view(), name="type_new"),
path( re_path(
"type/<int:type_id>/edit/", r"^type/(?P<type_id>[0-9]+)/edit$",
AccountingTypeEditView.as_view(), AccountingTypeEditView.as_view(),
name="type_edit", name="type_edit",
), ),
# Bank accounts # Bank accounts
path("", BankAccountListView.as_view(), name="bank_list"), re_path(r"^$", BankAccountListView.as_view(), name="bank_list"),
path("bank/create", BankAccountCreateView.as_view(), name="bank_new"), re_path(r"^bank/create$", BankAccountCreateView.as_view(), name="bank_new"),
path( re_path(
"bank/<int:b_account_id>/", r"^bank/(?P<b_account_id>[0-9]+)$",
BankAccountDetailView.as_view(), BankAccountDetailView.as_view(),
name="bank_details", name="bank_details",
), ),
path( re_path(
"bank/<int:b_account_id>/edit/", r"^bank/(?P<b_account_id>[0-9]+)/edit$",
BankAccountEditView.as_view(), BankAccountEditView.as_view(),
name="bank_edit", name="bank_edit",
), ),
path( re_path(
"bank/<int:b_account_id>/delete/", r"^bank/(?P<b_account_id>[0-9]+)/delete$",
BankAccountDeleteView.as_view(), BankAccountDeleteView.as_view(),
name="bank_delete", name="bank_delete",
), ),
# Club accounts # Club accounts
path("club/create/", ClubAccountCreateView.as_view(), name="club_new"), re_path(r"^club/create$", ClubAccountCreateView.as_view(), name="club_new"),
path( re_path(
"club/<int:c_account_id>/", r"^club/(?P<c_account_id>[0-9]+)$",
ClubAccountDetailView.as_view(), ClubAccountDetailView.as_view(),
name="club_details", name="club_details",
), ),
path( re_path(
"club/<int:c_account_id>/edit/", r"^club/(?P<c_account_id>[0-9]+)/edit$",
ClubAccountEditView.as_view(), ClubAccountEditView.as_view(),
name="club_edit", name="club_edit",
), ),
path( re_path(
"club/<int:c_account_id>/delete/", r"^club/(?P<c_account_id>[0-9]+)/delete$",
ClubAccountDeleteView.as_view(), ClubAccountDeleteView.as_view(),
name="club_delete", name="club_delete",
), ),
# Journals # Journals
path("journal/create/", JournalCreateView.as_view(), name="journal_new"), re_path(r"^journal/create$", JournalCreateView.as_view(), name="journal_new"),
path( re_path(
"journal/<int:j_id>/", r"^journal/(?P<j_id>[0-9]+)$",
JournalDetailView.as_view(), JournalDetailView.as_view(),
name="journal_details", name="journal_details",
), ),
path( re_path(
"journal/<int:j_id>/edit/", r"^journal/(?P<j_id>[0-9]+)/edit$",
JournalEditView.as_view(), JournalEditView.as_view(),
name="journal_edit", name="journal_edit",
), ),
path( re_path(
"journal/<int:j_id>/delete/", r"^journal/(?P<j_id>[0-9]+)/delete$",
JournalDeleteView.as_view(), JournalDeleteView.as_view(),
name="journal_delete", name="journal_delete",
), ),
path( re_path(
"journal/<int:j_id>/statement/nature/", r"^journal/(?P<j_id>[0-9]+)/statement/nature$",
JournalNatureStatementView.as_view(), JournalNatureStatementView.as_view(),
name="journal_nature_statement", name="journal_nature_statement",
), ),
path( re_path(
"journal/<int:j_id>/statement/person/", r"^journal/(?P<j_id>[0-9]+)/statement/person$",
JournalPersonStatementView.as_view(), JournalPersonStatementView.as_view(),
name="journal_person_statement", name="journal_person_statement",
), ),
path( re_path(
"journal/<int:j_id>/statement/accounting/", r"^journal/(?P<j_id>[0-9]+)/statement/accounting$",
JournalAccountingStatementView.as_view(), JournalAccountingStatementView.as_view(),
name="journal_accounting_statement", name="journal_accounting_statement",
), ),
# Operations # Operations
path( re_path(
"operation/create/<int:j_id>/", r"^operation/create/(?P<j_id>[0-9]+)$",
OperationCreateView.as_view(), OperationCreateView.as_view(),
name="op_new", name="op_new",
), ),
path("operation/<int:op_id>/", OperationEditView.as_view(), name="op_edit"), re_path(
path("operation/<int:op_id>/pdf/", OperationPDFView.as_view(), name="op_pdf"), r"^operation/(?P<op_id>[0-9]+)$", OperationEditView.as_view(), name="op_edit"
),
re_path(
r"^operation/(?P<op_id>[0-9]+)/pdf$", OperationPDFView.as_view(), name="op_pdf"
),
# Companies # Companies
path("company/list/", CompanyListView.as_view(), name="co_list"), re_path(r"^company/list$", CompanyListView.as_view(), name="co_list"),
path("company/create/", CompanyCreateView.as_view(), name="co_new"), re_path(r"^company/create$", CompanyCreateView.as_view(), name="co_new"),
path("company/<int:co_id>/", CompanyEditView.as_view(), name="co_edit"), re_path(r"^company/(?P<co_id>[0-9]+)$", CompanyEditView.as_view(), name="co_edit"),
# Labels # Labels
path("label/new/", LabelCreateView.as_view(), name="label_new"), re_path(r"^label/new$", LabelCreateView.as_view(), name="label_new"),
path( re_path(
"label/<int:clubaccount_id>/", r"^label/(?P<clubaccount_id>[0-9]+)$",
LabelListView.as_view(), LabelListView.as_view(),
name="label_list", name="label_list",
), ),
path("label/<int:label_id>/edit/", LabelEditView.as_view(), name="label_edit"), re_path(
path( r"^label/(?P<label_id>[0-9]+)/edit$", LabelEditView.as_view(), name="label_edit"
"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
path("refound/account/", RefoundAccountView.as_view(), name="refound_account"), re_path(r"^refound/account$", RefoundAccountView.as_view(), name="refound_account"),
] ]

View File

@ -1,58 +1,62 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView
from django.urls import reverse_lazy, reverse
from django.utils.translation import gettext_lazy as _
from django.forms.models import modelform_factory
from django.core.exceptions import PermissionDenied, ValidationError
from django.forms import HiddenInput
from django.db import transaction
from django.db.models import Sum
from django.conf import settings
from django import forms
from django.http import HttpResponse
import collections import collections
from ajax_select.fields import AutoCompleteSelectField from ajax_select.fields import AutoCompleteSelectField
from django import forms
from django.conf import settings
from django.core.exceptions import PermissionDenied, ValidationError
from django.db import transaction
from django.db.models import Sum
from django.forms import HiddenInput
from django.forms.models import modelform_factory
from django.http import HttpResponse
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from accounting.models import (
AccountingType,
BankAccount,
ClubAccount,
Company,
GeneralJournal,
Label,
Operation,
SimplifiedAccountingType,
)
from core.views import ( from core.views import (
CanCreateMixin, CanViewMixin,
CanEditMixin, CanEditMixin,
CanEditPropMixin, CanEditPropMixin,
CanViewMixin, CanCreateMixin,
TabedViewMixin, TabedViewMixin,
) )
from core.views.forms import SelectDate, SelectFile from core.views.forms import SelectFile, SelectDate
from counter.models import Counter, Product, Selling from accounting.models import (
BankAccount,
ClubAccount,
GeneralJournal,
Operation,
AccountingType,
Company,
SimplifiedAccountingType,
Label,
)
from counter.models import Counter, Selling, Product
# Main accounting view # Main accounting view
@ -525,14 +529,14 @@ class OperationPDFView(CanViewMixin, DetailView):
pk_url_kwarg = "op_id" pk_url_kwarg = "op_id"
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors from reportlab.lib import colors
from reportlab.lib.pagesizes import letter from reportlab.lib.pagesizes import letter
from reportlab.lib.units import cm
from reportlab.lib.utils import ImageReader from reportlab.lib.utils import ImageReader
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas from reportlab.pdfbase import pdfmetrics
from reportlab.platypus import Table, TableStyle
pdfmetrics.registerFont(TTFont("DejaVu", "DejaVuSerif.ttf")) pdfmetrics.registerFont(TTFont("DejaVu", "DejaVuSerif.ttf"))
@ -603,7 +607,7 @@ class OperationPDFView(CanViewMixin, DetailView):
payment_mode = "" payment_mode = ""
for m in settings.SITH_ACCOUNTING_PAYMENT_METHOD: for m in settings.SITH_ACCOUNTING_PAYMENT_METHOD:
if m[0] == mode: if m[0] == mode:
payment_mode += "[\u00d7]" payment_mode += "[\u00D7]"
else: else:
payment_mode += "[ ]" payment_mode += "[ ]"
payment_mode += " %s\n" % (m[1]) payment_mode += " %s\n" % (m[1])
@ -895,7 +899,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(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID): if user.is_root or user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
return True return True
else: else:
raise PermissionDenied raise PermissionDenied

View File

@ -1,19 +1,23 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #

View File

@ -1,21 +1,27 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.contrib import admin
# Register your models here. # Register your models here.

View File

@ -1,21 +1,27 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.db import models
# Create your models here. # Create your models here.

View File

@ -1,21 +1,27 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.test import TestCase
# Create your tests here. # Create your tests here.

View File

@ -1,27 +1,31 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.urls import include, path, re_path from django.urls import re_path, path, include
from rest_framework import routers
from api.views import * from api.views import *
from rest_framework import routers
# Router config # Router config
router = routers.DefaultRouter() router = routers.DefaultRouter()

View File

@ -1,30 +1,34 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.core.exceptions import PermissionDenied
from django.db.models.query import QuerySet
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import viewsets
from django.core.exceptions import PermissionDenied
from rest_framework.decorators import action
from django.db.models.query import QuerySet
from core.views import can_edit, can_view from core.views import can_view, can_edit
def check_if(obj, user, test): def check_if(obj, user, test):
@ -68,10 +72,10 @@ class RightModelViewSet(ManageModelMixin, viewsets.ModelViewSet):
from .api import * from .api import *
from .club import *
from .counter import * from .counter import *
from .user import *
from .club import *
from .group import * from .group import *
from .launderette import * from .launderette import *
from .sas import *
from .user import *
from .uv import * from .uv import *
from .sas import *

View File

@ -1,26 +1,30 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from rest_framework.response import Response
from rest_framework.decorators import api_view, renderer_classes from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import StaticHTMLRenderer from rest_framework.renderers import StaticHTMLRenderer
from rest_framework.response import Response
from core.templatetags.renderer import markdown from core.templatetags.renderer import markdown

View File

@ -1,32 +1,38 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.conf import settings from rest_framework.response import Response
from django.core.exceptions import PermissionDenied
from rest_framework import serializers from rest_framework import serializers
from rest_framework.decorators import api_view, renderer_classes from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import StaticHTMLRenderer from rest_framework.renderers import StaticHTMLRenderer
from rest_framework.response import Response
from django.conf import settings
from django.core.exceptions import PermissionDenied
from club.models import Club, Mailing
from api.views import RightModelViewSet from api.views import RightModelViewSet
from club.models import Club, Mailing
class ClubSerializer(serializers.ModelSerializer): class ClubSerializer(serializers.ModelSerializer):

View File

@ -1,32 +1,38 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from rest_framework import serializers from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.decorators import action
from counter.models import Counter
from api.views import RightModelViewSet from api.views import RightModelViewSet
from counter.models import Counter
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

View File

@ -1,28 +1,33 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from rest_framework import serializers from rest_framework import serializers
from api.views import RightModelViewSet
from core.models import RealGroup from core.models import RealGroup
from api.views import RightModelViewSet
class GroupSerializer(serializers.ModelSerializer): class GroupSerializer(serializers.ModelSerializer):
class Meta: class Meta:

View File

@ -1,32 +1,38 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from rest_framework import serializers from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.decorators import action
from launderette.models import Launderette, Machine, Token
from api.views import RightModelViewSet from api.views import RightModelViewSet
from launderette.models import Launderette, Machine, Token
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
) )

View File

@ -1,5 +1,4 @@
from typing import List from typing import List
from rest_framework.decorators import api_view, renderer_classes from rest_framework.decorators import api_view, renderer_classes
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
from rest_framework.generics import get_object_or_404 from rest_framework.generics import get_object_or_404
@ -7,8 +6,8 @@ from rest_framework.renderers import JSONRenderer
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from core.models import User
from core.views import can_edit from core.views import can_edit
from core.models import User
from sas.models import Picture from sas.models import Picture

View File

@ -1,31 +1,36 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
import datetime import datetime
from rest_framework import serializers from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.decorators import action
from core.models import User
from api.views import RightModelViewSet from api.views import RightModelViewSet
from core.models import User
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):

View File

@ -1,12 +1,11 @@
import json from rest_framework.response import Response
import urllib.request
from django.conf import settings
from django.core.exceptions import PermissionDenied
from rest_framework import serializers
from rest_framework.decorators import api_view, renderer_classes from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import JSONRenderer from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response from django.core.exceptions import PermissionDenied
from django.conf import settings
from rest_framework import serializers
import urllib.request
import json
from pedagogy.views import CanCreateUVFunctionMixin from pedagogy.views import CanCreateUVFunctionMixin

View File

@ -1,19 +1,23 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #

View File

@ -1,40 +1,31 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE, # You should have received a copy of the GNU General Public License along with
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old # this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# OR WITHIN THE LOCAL FILE "LICENSE.old" # 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.register(Club) admin.site.register(Club)
class ClubAdmin(admin.ModelAdmin): admin.site.register(Membership)
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"})

View File

@ -1,32 +1,40 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file. # - Sli <antoine@bartuccio.fr>
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from ajax_select.fields import AutoCompleteSelectMultipleField
from django import forms
from django.conf import settings from django.conf import settings
from django import forms
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from club.models import Club, Mailing, MailingSubscription, Membership from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
from club.models import Mailing, MailingSubscription, Club, Membership
from core.models import User from core.models import User
from core.views.forms import SelectDate, TzAwareDateTimeField from core.views.forms import SelectDate, SelectDateTime
from counter.models import Counter from counter.models import Counter
from core.views.forms import TzAwareDateTimeField
class ClubEditForm(forms.ModelForm): class ClubEditForm(forms.ModelForm):
@ -159,6 +167,7 @@ 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(),
@ -221,7 +230,9 @@ 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(self.request_user) if ms.can_be_edited_by(
self.request_user, self.request_user_membership
)
] ]
).all(), ).all(),
label=_("Mark as old"), label=_("Mark as old"),

View File

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models
import django.core.validators import django.core.validators
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [] dependencies = []
operations = [ operations = [

View File

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
from django.conf import settings
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"),

View File

@ -5,6 +5,7 @@ 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 = [

View File

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
from django.conf import settings
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 = [

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
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 = [

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.utils.timezone
from django.db import migrations, models from django.db import migrations, models
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 = [

View File

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations 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 = [

View File

@ -5,6 +5,7 @@ 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 = [

View File

@ -1,15 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import re import re
import django.core.validators import django.core.validators
import django.db.models.deletion import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
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"),

View File

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
from club.models import Club from club.models import Club
from core.operations import PsqlRunOnly from core.operations import PsqlRunOnly
import django.db.models.deletion
def generate_club_pages(apps, schema_editor): def generate_club_pages(apps, schema_editor):
@ -19,6 +19,7 @@ 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 = [

View File

@ -5,6 +5,7 @@ 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 = [

View File

@ -1,13 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
import club.models import club.models
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 = [

View File

@ -1,37 +1,40 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file. # - Sli <antoine@bartuccio.fr>
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from typing import Optional
from django.conf import settings from django.db import models
from django.core import validators from django.core import validators
from django.core.cache import cache from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator, validate_email from django.core.exceptions import ValidationError, ObjectDoesNotExist
from django.db import models, transaction from django.db import transaction
from django.db.models import Q
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.core.validators import RegexValidator, validate_email
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from core.models import Group, MetaGroup, Notification, Page, RealGroup, SithFile, User from core.models import User, MetaGroup, Group, SithFile, RealGroup, Notification, Page
# Create your models here. # Create your models here.
@ -69,7 +72,6 @@ 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
@ -120,22 +122,12 @@ class Club(models.Model):
def clean(self): def clean(self):
self.check_loop() self.check_loop()
def _change_unixname(self, old_name, new_name): def _change_unixname(self, 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"))
@ -179,11 +171,14 @@ 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():
creation = False
old = Club.objects.filter(id=self.id).first() old = Club.objects.filter(id=self.id).first()
creation = old is None if not old:
if not creation and old.unix_name != self.unix_name: creation = True
else:
if old.unix_name != self.unix_name:
self._change_unixname(self.unix_name) self._change_unixname(self.unix_name)
super(Club, self).save(*args, **kwargs) super(Club, self).save(*args, **kwargs)
if creation: if creation:
@ -199,14 +194,6 @@ class Club(models.Model):
self.home.view_groups.set([member, subscribers]) self.home.view_groups.set([member, subscribers])
self.home.save() self.home.save()
self.make_page() self.make_page()
cache.set(f"sith_club_{self.unix_name}", self)
def delete(self, *args, **kwargs):
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
@ -221,9 +208,7 @@ 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
""" """
if user.is_anonymous: return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
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)
@ -243,89 +228,28 @@ class Club(models.Model):
return False return False
return sub.was_subscribed return sub.was_subscribed
def get_membership_for(self, user: User) -> Optional["Membership"]: _memberships = {}
def get_membership_for(self, user):
""" """
Return the current membership the given user. Returns the current membership the given user
The result is cached.
""" """
if user.is_anonymous: try:
return None return Club._memberships[self.id][user.id]
membership = cache.get(f"membership_{self.id}_{user.id}") except:
if membership == "not_member": m = self.members.filter(user=user.id).filter(end_date=None).first()
return None try:
if membership is None: Club._memberships[self.id][user.id] = m
membership = self.members.filter(user=user, end_date=None).first() except:
if membership is None: Club._memberships[self.id] = {}
cache.set(f"membership_{self.id}_{user.id}", "not_member") Club._memberships[self.id][user.id] = m
else: return m
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
@ -365,8 +289,6 @@ 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
@ -381,34 +303,24 @@ 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
""" """
if user.is_anonymous: return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
return False
return user.is_board_member
def can_be_edited_by(self, user: User) -> bool: def can_be_edited_by(self, user, membership=None):
""" """
Check 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_root or user.is_board_member: if user.memberships:
return True if membership: # This is for optimisation purpose
membership = self.club.get_membership_for(user) ms = membership
if membership is not None and membership.role >= self.role: else:
return True ms = user.memberships.filter(club=self.club, end_date=None).first()
return False return (ms and ms.role >= self.role) or user.is_in_group(
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):
@ -461,12 +373,14 @@ 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_com_admin return user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
def is_owned_by(self, user): def is_owned_by(self, user):
if user.is_anonymous: return (
return False user.is_in_group(self)
return user.is_root or user.is_com_admin or user.is_root
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)
@ -474,8 +388,9 @@ 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, *args, **kwargs): def delete(self):
self.subscriptions.all().delete() for sub in self.subscriptions.all():
sub.delete()
super(Mailing, self).delete() super(Mailing, self).delete()
def fetch_format(self): def fetch_format(self):
@ -548,12 +463,10 @@ 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_com_admin or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
) )
def can_be_edited_by(self, user): def can_be_edited_by(self, user):

View File

@ -13,7 +13,6 @@
{% endif %} {% endif %}
<table> <table>
<thead> <thead>
<tr>
<td>{% trans %}User{% endtrans %}</td> <td>{% trans %}User{% endtrans %}</td>
<td>{% trans %}Role{% endtrans %}</td> <td>{% trans %}Role{% endtrans %}</td>
<td>{% trans %}Description{% endtrans %}</td> <td>{% trans %}Description{% endtrans %}</td>
@ -21,7 +20,6 @@
{% if users_old %} {% if users_old %}
<td>{% trans %}Mark as old{% endtrans %}</td> <td>{% trans %}Mark as old{% endtrans %}</td>
{% endif %} {% endif %}
</tr>
</thead> </thead>
<tbody> <tbody>
{% for m in members %} {% for m in members %}

View File

@ -2,7 +2,7 @@
{% from 'core/macros.jinja' import user_profile_link, paginate %} {% from 'core/macros.jinja' import user_profile_link, paginate %}
{% block content %} {% block content %}
<h3>{% trans %}Sales{% endtrans %}</h3> <h3>{% trans %}Sellings{% endtrans %}</h3>
<form id="form" action="?page=1" method="post"> <form id="form" action="?page=1" method="post">
{% csrf_token %} {% csrf_token %}
{{ form }} {{ form }}

View File

@ -30,7 +30,7 @@
{% endif %} {% endif %}
</ul> </ul>
{% if object.club_account.exists() %} {% if object.club_account.exists() %}
<h4>{% trans %}Accounting: {% endtrans %}</h4> <h4>{% trans %}Accouting: {% endtrans %}</h4>
<ul> <ul>
{% for ca in object.club_account.all() %} {% for ca in object.club_account.all() %}
<li><a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca.get_display_name() }}</a></li> <li><a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca.get_display_name() }}</a></li>

File diff suppressed because it is too large Load Diff

View File

@ -1,101 +1,116 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file. # - Sli <antoine@bartuccio.fr>
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.urls import path from django.urls import re_path
from club.views import * from club.views import *
urlpatterns = [ urlpatterns = [
path("", ClubListView.as_view(), name="club_list"), re_path(r"^$", ClubListView.as_view(), name="club_list"),
path("new/", ClubCreateView.as_view(), name="club_new"), re_path(r"^new$", ClubCreateView.as_view(), name="club_new"),
path("stats/", ClubStatView.as_view(), name="club_stats"), re_path(r"^stats$", ClubStatView.as_view(), name="club_stats"),
path("<int:club_id>/", ClubView.as_view(), name="club_view"), re_path(r"^(?P<club_id>[0-9]+)/$", ClubView.as_view(), name="club_view"),
path( re_path(
"<int:club_id>/rev/<int:rev_id>/", r"^(?P<club_id>[0-9]+)/rev/(?P<rev_id>[0-9]+)/$",
ClubRevView.as_view(), ClubRevView.as_view(),
name="club_view_rev", name="club_view_rev",
), ),
path("<int:club_id>/hist/", ClubPageHistView.as_view(), name="club_hist"), re_path(
path("<int:club_id>/edit/", ClubEditView.as_view(), name="club_edit"), r"^(?P<club_id>[0-9]+)/hist$", ClubPageHistView.as_view(), name="club_hist"
path( ),
"<int:club_id>/edit/page/", re_path(r"^(?P<club_id>[0-9]+)/edit$", ClubEditView.as_view(), name="club_edit"),
re_path(
r"^(?P<club_id>[0-9]+)/edit/page$",
ClubPageEditView.as_view(), ClubPageEditView.as_view(),
name="club_edit_page", name="club_edit_page",
), ),
path("<int:club_id>/members/", ClubMembersView.as_view(), name="club_members"), re_path(
path( r"^(?P<club_id>[0-9]+)/members$", ClubMembersView.as_view(), name="club_members"
"<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",
), ),
path( re_path(
"<int:club_id>/sellings/", r"^(?P<club_id>[0-9]+)/sellings$",
ClubSellingView.as_view(), ClubSellingView.as_view(),
name="club_sellings", name="club_sellings",
), ),
path( re_path(
"<int:club_id>/sellings/csv/", r"^(?P<club_id>[0-9]+)/sellings/csv$",
ClubSellingCSVView.as_view(), ClubSellingCSVView.as_view(),
name="sellings_csv", name="sellings_csv",
), ),
path("<int:club_id>/prop/", ClubEditPropView.as_view(), name="club_prop"), re_path(
path("<int:club_id>/tools/", ClubToolsView.as_view(), name="tools"), r"^(?P<club_id>[0-9]+)/prop$", ClubEditPropView.as_view(), name="club_prop"
path("<int:club_id>/mailing/", ClubMailingView.as_view(), name="mailing"), ),
path( re_path(r"^(?P<club_id>[0-9]+)/tools$", ClubToolsView.as_view(), name="tools"),
"<int:mailing_id>/mailing/generate/", re_path(
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",
), ),
path( re_path(
"<int:mailing_id>/mailing/delete/", r"^(?P<mailing_id>[0-9]+)/mailing/delete$",
MailingDeleteView.as_view(), MailingDeleteView.as_view(),
name="mailing_delete", name="mailing_delete",
), ),
path( re_path(
"<int:mailing_subscription_id>/mailing/delete/subscription/", r"^(?P<mailing_subscription_id>[0-9]+)/mailing/delete/subscription$",
MailingSubscriptionDeleteView.as_view(), MailingSubscriptionDeleteView.as_view(),
name="mailing_subscription_delete", name="mailing_subscription_delete",
), ),
path( re_path(
"membership/<int:membership_id>/set_old/", r"^membership/(?P<membership_id>[0-9]+)/set_old$",
MembershipSetOldView.as_view(), MembershipSetOldView.as_view(),
name="membership_set_old", name="membership_set_old",
), ),
path( re_path(
"membership/<int:membership_id>/delete/", r"^membership/(?P<membership_id>[0-9]+)/delete$",
MembershipDeleteView.as_view(), MembershipDeleteView.as_view(),
name="membership_delete", name="membership_delete",
), ),
path("<int:club_id>/poster/", PosterListView.as_view(), name="poster_list"), re_path(
path( r"^(?P<club_id>[0-9]+)/poster$", PosterListView.as_view(), name="poster_list"
"<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",
), ),
path( re_path(
"<int:club_id>/poster/<int:poster_id>/edit/", r"^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/edit$",
PosterEditView.as_view(), PosterEditView.as_view(),
name="poster_edit", name="poster_edit",
), ),
path( re_path(
"<int:club_id>/poster/<int:poster_id>/delete/", r"^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/delete$",
PosterDeleteView.as_view(), PosterDeleteView.as_view(),
name="poster_delete", name="poster_delete",
), ),

View File

@ -1,63 +1,76 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file. # - Sli <antoine@bartuccio.fr>
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
import csv import csv
from django.conf import settings from django.conf import settings
from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied, ValidationError from django import forms
from django.core.paginator import InvalidPage, Paginator from django.views.generic import ListView, DetailView, TemplateView, View
from django.db.models import Sum from django.views.generic.edit import DeleteView
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import UpdateView, CreateView
from django.http import ( from django.http import (
Http404,
HttpResponseRedirect, HttpResponseRedirect,
HttpResponse,
Http404,
StreamingHttpResponse, StreamingHttpResponse,
) )
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext as _t
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, TemplateView, View from django.utils.translation import gettext as _t
from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.core.exceptions import PermissionDenied, ValidationError, NON_FIELD_ERRORS
from django.core.paginator import Paginator, InvalidPage
from django.shortcuts import get_object_or_404, redirect
from django.db.models import Sum
from club.forms import ClubEditForm, ClubMemberForm, MailingForm, SellingsForm
from club.models import Club, Mailing, MailingSubscription, Membership
from com.views import (
PosterCreateBaseView,
PosterDeleteBaseView,
PosterEditBaseView,
PosterListBaseView,
)
from core.models import PageRev
from core.views import ( from core.views import (
CanCreateMixin, CanCreateMixin,
CanViewMixin,
CanEditMixin, CanEditMixin,
CanEditPropMixin, CanEditPropMixin,
CanViewMixin,
DetailFormView,
PageEditViewBase,
TabedViewMixin,
UserIsRootMixin, UserIsRootMixin,
TabedViewMixin,
PageEditViewBase,
DetailFormView,
) )
from core.models import PageRev
from counter.models import Selling from counter.models import Selling
from com.views import (
PosterListBaseView,
PosterCreateBaseView,
PosterEditBaseView,
PosterDeleteBaseView,
)
from club.models import Club, Membership, Mailing, MailingSubscription
from club.forms import MailingForm, ClubEditForm, ClubMemberForm, SellingsForm
class ClubTabsMixin(TabedViewMixin): class ClubTabsMixin(TabedViewMixin):
def get_tabs_title(self): def get_tabs_title(self):
@ -293,7 +306,9 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
return resp return resp
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.members = self.get_object().members.ongoing().order_by("-role") self.members = (
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):
@ -428,6 +443,7 @@ 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)
@ -598,7 +614,7 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
} }
return kwargs return kwargs
def add_new_mailing(self, cleaned_data) -> ValidationError | None: def add_new_mailing(self, cleaned_data) -> ValidationError:
""" """
Create a new mailing list from the form Create a new mailing list from the form
""" """
@ -615,7 +631,7 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
mailing.save() mailing.save()
return None return None
def add_new_subscription(self, cleaned_data) -> ValidationError | None: def add_new_subscription(self, cleaned_data) -> ValidationError:
""" """
Add mailing subscriptions for each user given and/or for the specified email in form Add mailing subscriptions for each user given and/or for the specified email in form
""" """
@ -690,6 +706,7 @@ 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"
@ -707,6 +724,7 @@ 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"

View File

@ -1,19 +1,23 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #

View File

@ -1,53 +1,43 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE, # You should have received a copy of the GNU General Public License along with
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old # this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# OR WITHIN THE LOCAL FILE "LICENSE.old" # 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):
list_display = ("title", "type", "club", "author") search_fields = ["title", "summary", "content"]
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):
list_display = ("title", "sent") search_fields = ["title"]
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)

View File

@ -5,6 +5,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [] dependencies = []
operations = [ operations = [

View File

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
from django.conf import settings
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),

View File

@ -1,12 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
from django.conf import settings
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),

View File

@ -1,13 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import django.db.models.deletion from django.db import migrations, models
import django.utils.timezone import django.utils.timezone
from django.conf import settings from django.conf import settings
from django.db import migrations, models 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),

View File

@ -5,6 +5,7 @@ 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 = [

View File

@ -6,6 +6,7 @@ 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")]

View File

@ -1,37 +1,43 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file. # - Sli <antoine@bartuccio.fr>
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.conf import settings from django.shortcuts import render
from django.core.exceptions import ValidationError
from django.core.mail import EmailMultiAlternatives
from django.db import models, transaction from django.db import models, transaction
from django.db.models import Q from django.db.models import Q
from django.shortcuts import render
from django.templatetags.static import static
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django.urls import reverse
from django.conf import settings
from django.templatetags.static import static
from django.core.mail import EmailMultiAlternatives
from django.core.exceptions import ValidationError
from django.utils import timezone
from core.models import User, Preferences, RealGroup, Notification, SithFile
from club.models import Club from club.models import Club
from core import utils
from core.models import Notification, Preferences, RealGroup, User
class Sith(models.Model): class Sith(models.Model):
@ -40,12 +46,9 @@ 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):
if user.is_anonymous: return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
return False
return user.is_com_admin
def __str__(self): def __str__(self):
return "⛩ Sith ⛩" return "⛩ Sith ⛩"
@ -58,6 +61,11 @@ 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"""
@ -87,15 +95,13 @@ class News(models.Model):
) )
def is_owned_by(self, user): def is_owned_by(self, user):
if user.is_anonymous: return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user == self.author
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_com_admin return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
def can_be_viewed_by(self, user): def can_be_viewed_by(self, user):
return self.is_moderated or user.is_com_admin return self.is_moderated or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
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})
@ -177,6 +183,9 @@ 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"]
@ -214,6 +223,17 @@ 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.
@ -226,10 +246,15 @@ 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.
@ -240,9 +265,7 @@ 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):
if user.is_anonymous: return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
return False
return user.is_com_admin
class WeekmailArticle(models.Model): class WeekmailArticle(models.Model):
@ -270,9 +293,7 @@ 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):
if user.is_anonymous: return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
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)
@ -288,9 +309,7 @@ class Screen(models.Model):
) )
def is_owned_by(self, user): def is_owned_by(self, user):
if user.is_anonymous: return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
return False
return user.is_com_admin
def __str__(self): def __str__(self):
return "%s" % (self.name) return "%s" % (self.name)
@ -343,12 +362,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):
if user.is_anonymous: return user.is_in_group(
return False settings.SITH_GROUP_COM_ADMIN_ID
return user.is_com_admin or len(user.clubs_with_rights) > 0 ) or Club.objects.filter(id__in=user.clubs_with_rights)
def can_be_moderated_by(self, user): def can_be_moderated_by(self, user):
return user.is_com_admin return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
def get_display_name(self): def get_display_name(self):
return self.club.get_display_name() return self.club.get_display_name()

View File

@ -35,11 +35,11 @@
<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_com_admin %} {% elif user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
<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) %}
<p> <a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit (will be moderated again){% endtrans %}</a></p> <p> <a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit (will be remoderated){% endtrans %}</a></p>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -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_com_admin %} {% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
<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 %}

View File

@ -6,15 +6,15 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if user.is_com_admin %} {% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
<div id="news_admin"> <div id="news_admin">
<a class="button" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a> <a 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,15 +97,6 @@
</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">

View File

@ -24,7 +24,7 @@
<div id="progress_bar"></div> <div id="progress_bar"></div>
</div> </div>
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script> <script src="{{ static('core/js/jquery-3.1.0.min.js') }}"></script>
<script src="{{ static('com/js/slideshow.js') }}"></script> <script src="{{ static('com/js/slideshow.js') }}"></script>
</body> </body>
</html> </html>

View File

@ -10,6 +10,7 @@
<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>

View File

@ -1,69 +1,73 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE, # You should have received a copy of the GNU General Public License along with
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old # this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# OR WITHIN THE LOCAL FILE "LICENSE.old" # Place - Suite 330, Boston, MA 02111-1307, USA.
# #
import pytest #
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase from django.test import TestCase
from django.conf import settings
from django.urls import reverse from django.urls import reverse
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 com.models import News, Poster, Sith, Weekmail, WeekmailArticle from core.models import User, RealGroup
from core.models import AnonymousUser, RealGroup, User
@pytest.fixture() class ComAlertTest(TestCase):
def user_community(): def setUp(self):
return User.objects.get(username="comunity") call_command("populate")
def test_page_is_working(self):
self.client.login(username="comunity", password="plop")
response = self.client.get(reverse("com:alert_edit"))
self.assertNotEqual(response.status_code, 500)
self.assertEqual(response.status_code, 200)
@pytest.mark.django_db class ComInfoTest(TestCase):
@pytest.mark.parametrize( def setUp(self):
"url", call_command("populate")
[
reverse("com:alert_edit"), def test_page_is_working(self):
reverse("com:info_edit"), self.client.login(username="comunity", password="plop")
], response = self.client.get(reverse("com:info_edit"))
) self.assertNotEqual(response.status_code, 500)
def test_com_page_is_working(client, url, user_community): self.assertEqual(response.status_code, 200)
client.force_login(user_community)
response = client.get(url)
assert response.status_code == 200
class ComTest(TestCase): class ComTest(TestCase):
@classmethod def setUp(self):
def setUpTestData(cls): call_command("populate")
cls.skia = User.objects.get(username="skia") self.skia = User.objects.filter(username="skia").first()
cls.com_group = RealGroup.objects.filter( self.com_group = RealGroup.objects.filter(
id=settings.SITH_GROUP_COM_ADMIN_ID id=settings.SITH_GROUP_COM_ADMIN_ID
).first() ).first()
cls.skia.groups.set([cls.com_group]) self.skia.groups.set([self.com_group])
self.skia.save()
def setUp(self): self.client.login(username=self.skia.username, password="plop")
self.client.force_login(self.skia)
def test_alert_msg(self): def test_alert_msg(self):
self.client.post( response = self.client.post(
reverse("com:alert_edit"), reverse("com:alert_edit"),
{ {
"alert_msg": """ "alert_msg": """
@ -74,6 +78,7 @@ class ComTest(TestCase):
}, },
) )
r = self.client.get(reverse("core:index")) r = self.client.get(reverse("core:index"))
self.assertTrue(r.status_code == 200)
self.assertContains( self.assertContains(
r, r,
"""<div id="alert_box"> """<div id="alert_box">
@ -82,7 +87,7 @@ class ComTest(TestCase):
) )
def test_info_msg(self): def test_info_msg(self):
self.client.post( response = self.client.post(
reverse("com:info_edit"), reverse("com:info_edit"),
{ {
"info_msg": """ "info_msg": """
@ -91,6 +96,7 @@ class ComTest(TestCase):
}, },
) )
r = self.client.get(reverse("core:index")) r = self.client.get(reverse("core:index"))
self.assertTrue(r.status_code == 200)
self.assertContains( self.assertContains(
r, r,
"""<div id="info_box"> """<div id="info_box">
@ -98,7 +104,7 @@ class ComTest(TestCase):
) )
def test_birthday_non_subscribed_user(self): def test_birthday_non_subscribed_user(self):
self.client.force_login(User.objects.get(username="guy")) self.client.login(username="guy", password="plop")
response = self.client.get(reverse("core:index")) response = self.client.get(reverse("core:index"))
self.assertContains( self.assertContains(
response, response,
@ -116,129 +122,3 @@ 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")
assert sith.is_owned_by(com_admin)
anonymous = AnonymousUser()
assert not sith.is_owned_by(anonymous)
sli = User.objects.get(username="sli")
assert not 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
"""
assert self.new.is_owned_by(self.com_admin)
assert self.new.is_owned_by(self.author)
assert not self.new.is_owned_by(self.anonymous)
assert not self.new.is_owned_by(self.sli)
def test_news_viewer(self):
"""
Test that moderated news can be viewed by anyone
and not moderated news only by com admins
"""
# by default a news isn't moderated
assert self.new.can_be_viewed_by(self.com_admin)
assert not self.new.can_be_viewed_by(self.sli)
assert not self.new.can_be_viewed_by(self.anonymous)
assert not self.new.can_be_viewed_by(self.author)
self.new.is_moderated = True
self.new.save()
assert self.new.can_be_viewed_by(self.com_admin)
assert self.new.can_be_viewed_by(self.sli)
assert self.new.can_be_viewed_by(self.anonymous)
assert self.new.can_be_viewed_by(self.author)
def test_news_editor(self):
"""
Test that only com admins can edit news
"""
assert self.new.can_be_edited_by(self.com_admin)
assert not self.new.can_be_edited_by(self.sli)
assert not self.new.can_be_edited_by(self.anonymous)
assert not self.new.can_be_edited_by(self.author)
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
"""
assert self.article.is_owned_by(self.com_admin)
assert not self.article.is_owned_by(self.author)
assert not self.article.is_owned_by(self.anonymous)
assert not 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
"""
assert self.poster.is_owned_by(self.com_admin)
assert not self.poster.is_owned_by(self.anonymous)
assert not self.poster.is_owned_by(self.susbcriber)
assert self.poster.is_owned_by(self.sli)

View File

@ -1,115 +1,125 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from django.urls import path from django.urls import re_path
from club.views import MailingDeleteView
from com.views import * from com.views import *
from club.views import MailingDeleteView
urlpatterns = [ urlpatterns = [
path("sith/edit/alert/", AlertMsgEditView.as_view(), name="alert_edit"), re_path(r"^sith/edit/alert$", AlertMsgEditView.as_view(), name="alert_edit"),
path("sith/edit/info/", InfoMsgEditView.as_view(), name="info_edit"), re_path(r"^sith/edit/info$", InfoMsgEditView.as_view(), name="info_edit"),
path( re_path(
"sith/edit/weekmail_destinations/", r"^sith/edit/weekmail_destinations$",
WeekmailDestinationEditView.as_view(), WeekmailDestinationEditView.as_view(),
name="weekmail_destinations", name="weekmail_destinations",
), ),
path("weekmail/", WeekmailEditView.as_view(), name="weekmail"), re_path(r"^weekmail$", WeekmailEditView.as_view(), name="weekmail"),
path("weekmail/preview/", WeekmailPreviewView.as_view(), name="weekmail_preview"), re_path(
path( r"^weekmail/preview$", WeekmailPreviewView.as_view(), name="weekmail_preview"
"weekmail/new_article/", ),
re_path(
r"^weekmail/new_article$",
WeekmailArticleCreateView.as_view(), WeekmailArticleCreateView.as_view(),
name="weekmail_article", name="weekmail_article",
), ),
path( re_path(
"weekmail/article/<int:article_id>/delete/", r"^weekmail/article/(?P<article_id>[0-9]+)/delete$",
WeekmailArticleDeleteView.as_view(), WeekmailArticleDeleteView.as_view(),
name="weekmail_article_delete", name="weekmail_article_delete",
), ),
path( re_path(
"weekmail/article/<int:article_id>/edit/", r"^weekmail/article/(?P<article_id>[0-9]+)/edit$",
WeekmailArticleEditView.as_view(), WeekmailArticleEditView.as_view(),
name="weekmail_article_edit", name="weekmail_article_edit",
), ),
path("news/", NewsListView.as_view(), name="news_list"), re_path(r"^news$", NewsListView.as_view(), name="news_list"),
path("news/admin/", NewsAdminListView.as_view(), name="news_admin_list"), re_path(r"^news/admin$", NewsAdminListView.as_view(), name="news_admin_list"),
path("news/create/", NewsCreateView.as_view(), name="news_new"), re_path(r"^news/create$", NewsCreateView.as_view(), name="news_new"),
path( re_path(
"news/<int:news_id>/delete/", r"^news/(?P<news_id>[0-9]+)/delete$",
NewsDeleteView.as_view(), NewsDeleteView.as_view(),
name="news_delete", name="news_delete",
), ),
path( re_path(
"news/<int:news_id>/moderate/", r"^news/(?P<news_id>[0-9]+)/moderate$",
NewsModerateView.as_view(), NewsModerateView.as_view(),
name="news_moderate", name="news_moderate",
), ),
path("news/<int:news_id>/edit/", NewsEditView.as_view(), name="news_edit"), re_path(
path("news/<int:news_id>/", NewsDetailView.as_view(), name="news_detail"), r"^news/(?P<news_id>[0-9]+)/edit$", NewsEditView.as_view(), name="news_edit"
path("mailings/", MailingListAdminView.as_view(), name="mailing_admin"), ),
path( re_path(
"mailings/<int:mailing_id>/moderate/", r"^news/(?P<news_id>[0-9]+)$", NewsDetailView.as_view(), name="news_detail"
),
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",
), ),
path( re_path(
"mailings/<int:mailing_id>/delete/", r"^mailings/(?P<mailing_id>[0-9]+)/delete$",
MailingDeleteView.as_view(redirect_page="com:mailing_admin"), MailingDeleteView.as_view(redirect_page="com:mailing_admin"),
name="mailing_delete", name="mailing_delete",
), ),
path("poster/", PosterListView.as_view(), name="poster_list"), re_path(r"^poster$", PosterListView.as_view(), name="poster_list"),
path("poster/create/", PosterCreateView.as_view(), name="poster_create"), re_path(r"^poster/create$", PosterCreateView.as_view(), name="poster_create"),
path( re_path(
"poster/<int:poster_id>/edit/", r"^poster/(?P<poster_id>[0-9]+)/edit$",
PosterEditView.as_view(), PosterEditView.as_view(),
name="poster_edit", name="poster_edit",
), ),
path( re_path(
"poster/<int:poster_id>/delete/", r"^poster/(?P<poster_id>[0-9]+)/delete$",
PosterDeleteView.as_view(), PosterDeleteView.as_view(),
name="poster_delete", name="poster_delete",
), ),
path( re_path(
"poster/moderate/", r"^poster/moderate$",
PosterModerateListView.as_view(), PosterModerateListView.as_view(),
name="poster_moderate_list", name="poster_moderate_list",
), ),
path( re_path(
"poster/<int:object_id>/moderate/", r"^poster/(?P<object_id>[0-9]+)/moderate$",
PosterModerateView.as_view(), PosterModerateView.as_view(),
name="poster_moderate", name="poster_moderate",
), ),
path("screen/", ScreenListView.as_view(), name="screen_list"), re_path(r"^screen$", ScreenListView.as_view(), name="screen_list"),
path("screen/create/", ScreenCreateView.as_view(), name="screen_create"), re_path(r"^screen/create$", ScreenCreateView.as_view(), name="screen_create"),
path( re_path(
"screen/<int:screen_id>/slideshow/", r"^screen/(?P<screen_id>[0-9]+)/slideshow$",
ScreenSlideshowView.as_view(), ScreenSlideshowView.as_view(),
name="screen_slideshow", name="screen_slideshow",
), ),
path( re_path(
"screen/<int:screen_id>/edit/", r"^screen/(?P<screen_id>[0-9]+)/edit$",
ScreenEditView.as_view(), ScreenEditView.as_view(),
name="screen_edit", name="screen_edit",
), ),
path( re_path(
"screen/<int:screen_id>/delete/", r"^screen/(?P<screen_id>[0-9]+)/delete$",
ScreenDeleteView.as_view(), ScreenDeleteView.as_view(),
name="screen_delete", name="screen_delete",
), ),

View File

@ -1,52 +1,60 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file. # - Sli <antoine@bartuccio.fr>
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE, # You should have received a copy of the GNU General Public License along with
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old # this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# OR WITHIN THE LOCAL FILE "LICENSE.old" # Place - Suite 330, Boston, MA 02111-1307, USA.
# #
#
from django.shortcuts import redirect, get_object_or_404
from django.http import HttpResponseRedirect
from django.views.generic import ListView, DetailView, View
from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.views.generic.detail import SingleObjectMixin
from django.utils.translation import gettext_lazy as _
from django.urls import reverse, reverse_lazy
from django.core.exceptions import ValidationError
from django.utils import timezone
from django.conf import settings
from django.db.models import Max
from django.forms.models import modelform_factory
from django.core.exceptions import PermissionDenied
from django import forms
from datetime import timedelta from datetime import timedelta
from smtplib import SMTPRecipientsRefused from smtplib import SMTPRecipientsRefused
from django import forms from com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle, Screen, Poster
from django.conf import settings
from django.core.exceptions import PermissionDenied, ValidationError
from django.db.models import Max
from django.forms.models import modelform_factory
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, View
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from club.models import Club, Mailing
from com.models import News, NewsDate, Poster, Screen, Sith, Weekmail, WeekmailArticle
from core.models import Notification, RealGroup, User
from core.views import ( from core.views import (
CanCreateMixin, CanViewMixin,
CanEditMixin, CanEditMixin,
CanEditPropMixin, CanEditPropMixin,
CanViewMixin,
QuickNotifMixin,
TabedViewMixin, TabedViewMixin,
CanCreateMixin,
QuickNotifMixin,
) )
from core.views.forms import MarkdownInput, TzAwareDateTimeField from core.views.forms import SelectDateTime, MarkdownInput
from core.models import Notification, RealGroup, User
from club.models import Club, Mailing
from core.views.forms import TzAwareDateTimeField
# Sith object # Sith object
@ -138,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_com_admin: if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)):
raise PermissionDenied raise PermissionDenied
return super(IsComAdminMixin, self).dispatch(request, *args, **kwargs) return super(IsComAdminMixin, self).dispatch(request, *args, **kwargs)
@ -275,7 +283,9 @@ 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_com_admin: if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
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()
@ -323,7 +333,9 @@ 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_com_admin: if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
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()
@ -605,7 +617,10 @@ class MailingListAdminView(ComTabsMixin, ListView):
current_tab = "mailings" current_tab = "mailings"
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not (request.user.is_com_admin or request.user.is_root): if not (
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)

View File

@ -1,14 +0,0 @@
import pytest
from django.core.management import call_command
from django.utils.translation import activate
@pytest.fixture(scope="session")
def django_db_setup(django_db_setup, django_db_blocker):
with django_db_blocker.unblock():
call_command("setup")
@pytest.fixture(scope="session", autouse=True)
def set_default_language():
activate("fr")

View File

@ -1,19 +1,23 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #

View File

@ -1,38 +1,40 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from ajax_select import make_ajax_form
from django.contrib import admin from django.contrib import admin
from ajax_select import make_ajax_form
from core.models import User, Page, RealGroup, 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
from core.models import MetaGroup, Page, RealGroup, SithFile, User
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,
{ {
@ -46,9 +48,11 @@ 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,
{ {
@ -62,12 +66,4 @@ class PageAdmin(admin.ModelAdmin):
@admin.register(SithFile) @admin.register(SithFile)
class SithFileAdmin(admin.ModelAdmin): class SithFileAdmin(admin.ModelAdmin):
list_display = ("name", "owner", "size", "date", "is_in_sas") form = make_ajax_form(SithFile, {"parent": "files"}) # ManyToManyField
form = make_ajax_form(
SithFile,
{
"parent": "files",
"owner": "users",
"moderator": "users",
},
) # ManyToManyField

View File

@ -1,27 +1,30 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
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
@ -30,17 +33,26 @@ class SithConfig(AppConfig):
verbose_name = "Core app of the Sith" verbose_name = "Core app of the Sith"
def ready(self): def ready(self):
import core.signals # noqa F401 from core.models import User
from club.models import Club
from forum.models import Forum from forum.models import Forum
cache.clear() def clear_cached_groups(**kwargs):
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

View File

@ -1,55 +0,0 @@
# -*- coding:utf-8 -*-
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# You can find the whole source code at https://github.com/ae-utbm/sith3
#
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
#
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)

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,31 +1,35 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #
from ajax_select import LookupChannel, register
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from ajax_select import register, LookupChannel
from accounting.models import ClubAccount, Company
from club.models import Club
from core.models import Group, SithFile, User
from core.views.site import search_user from core.views.site import search_user
from counter.models import Counter, Customer, Product from core.models import User, Group, SithFile
from club.models import Club
from counter.models import Product, Counter
from accounting.models import ClubAccount, Company
def check_token(request): def check_token(request):
@ -56,21 +60,6 @@ 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

View File

@ -1,19 +1,23 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*
# #
# Copyright 2023 © AE UTBM # Copyright 2016,2017
# ae@utbm.fr / ae.info@utbm.fr # - Skia <skia@libskia.so>
# All contributors are listed in the CONTRIBUTORS file.
# #
# This file is part of the website of the UTBM Student Association (AE UTBM), # Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# https://ae.utbm.fr. # http://ae.utbm.fr.
# #
# You can find the whole source code at https://github.com/ae-utbm/sith3 # This program is free software; you can redistribute it and/or modify it under
# 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.
# #
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3) # This program is distributed in the hope that it will be useful, but WITHOUT
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# OR WITHIN THE LOCAL FILE "LICENSE" # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# 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.
# #
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# #

Some files were not shown because too many files have changed in this diff Show More