4 Commits

Author SHA1 Message Date
f234f94171 Removed unused xapian action 2023-11-05 23:49:45 +01:00
fa758867cc Migrated from xapian to elastic 2023-11-05 23:42:52 +01:00
f41ff281fb Remove eurocks tickets from eboutic (event is finished) 2023-10-10 15:50:35 +02:00
321cb72ca8 October 2023 update (#672)
* integration of 3D secure v2 for eboutic bank payment

* edit yml to avoid git conflict when deploying on test

* escape html characters on xml (#505)

* Change country id to ISO 3166 1 numeric for 3DSV2 (#510)

* remove useless tests

* Fix le panier de l'Eboutic pour Safari (#518)

Co-authored-by: Théo DURR <git@theodurr.fr>
Co-authored-by: thomas girod <56346771+imperosol@users.noreply.github.com>

* update some dependencies (#523)

* [Eboutic] Fix double quote issue & improved user experience on small screen (#522)

* Fix #511 Regex issue with escaped double quotes

* Fix basket being when reloading the page (when cookie != "")

+ Added JSDoc
+ Cleaned some code

* Fix #509 Improved user experience on small screens

* Fix css class not being added back when reloading page

* CSS Fixes (see description)

+ Fixed overlaping item title with the cart emoji on small screen
+ Fixed minimal size of the basket on small screen (full width)

* Added darkened background circle to items with no image

* Fix issue were the basket could be None


* Edited CSS to have bette img ratio & the 🛒 icon

Adapt, Improve, Overcome

* Moved basket down on small screen size

* enhance admin pages

* update documentation

* Update doc/about/tech.rst

Co-authored-by: Julien Constant <49886317+Juknum@users.noreply.github.com>

* remove csrf_token

* Fix 3DSv2 implementation (#542)

* Fixed wrong HMAC signature generation

* Fix xml du panier

Co-authored-by: Julien Constant <julienconstant190@gmail.com>

* [FIX] 3DSv2 - Echappement du XML et modif tables (#543)

* Fixed wrong HMAC signature generation
* Updated migration files

Co-authored-by: Julien Constant <julienconstant190@gmail.com>

* Update doc/about/tech.rst

* Update doc/start/install.rst

* Updated lock file according to pyproject

* unify account_id creation

* upgrade re_path to path (#533)

* redirect directly on counter if user is barman

* Passage de vue à Alpine pour les comptoirs (#561)

Vue, c'est cool, mais avec Django c'est un peu chiant à utiliser. Alpine a l'avantage d'être plus léger et d'avoir une syntaxe qui ne ressemble pas à celle de Jinja (ce qui évite d'avoir à mettre des {% raw %} partout).

* resolved importError (#565)

* Add galaxy (#562)

* style.scss: lint

* style.scss: add 'th' padding

* core: populate: add much more data for development

* Add galaxy

* repair user merging tool (#498)

* Disabled galaxy feature (only visually)

* Disabled Galaxy button & Removed 404 exception display

* Update 404.jinja

* Fixed broken test

* Added eurocks links to eboutic

* fix typo

* fix wording

Co-authored-by: Théo DURR <git@theodurr.fr>

* Edited unit tests

This test caused a breach in security due to the alert block displaying sensitive data.

* Repair NaN bug for autocomplete on counter click

* remove-useless-queries-counter-stats (#519)

* Amélioration des pages utilisateurs pour les petits écrans (#578, #520)

- Refonte de l'organisation des pages utilisateurs (principalement du front)
  - Page des parrains/fillots
  - Page d'édition du profil
  - Page du profil
  - Page des outils
  - Page des préférences
  - Page des stats utilisateurs

- Refonte du CSS / organisation de la navbar principale (en haut de l'écran)
- Refonte du CSS de la navbar bleu clair (le menu)
- Refonte du CSS du SAS :
  - Page de photo
  - Page d'albums

* Added GA/Clubs Google Calendar to main page (#585)

* Added GA/Clubs google calendar to main page

* Made tables full width

* Create dependabot.yml (#587)

* Bump django from 3.2.16 to 3.2.18 (#574)

* [CSS] Follow up of #578 (#589)

* [FIX] Broken link in readme and license fix (& update) (#591)

* Fixes pour la mise à jour de mars (#598)

* Fix problème de cache dans le SAS & améliore le CSS du SAS

Co-authored-by: Bartuccio Antoine <klmp200@users.noreply.github.com>

* Fixes & améliorations du nouveau CSS (#616)

* [UPDATE] Bump sentry-sdk from 1.12.1 to 1.19.1 (#620)

* [FIX] Fixes supplémentaires pour la màj de mars (#622)

- Les photos de l'onglet de la page utilisateur utilise désormais leur version thumbnail au lieu de leur version HD
- Une des classes du CSS du SAS a été renommée car elle empiétait sur une class de la navbar
- Le profil utilisateur a été revu pour ajouter plus d'espacement entre le tableau des cotisations et le numéro de cotisants
- Les images de forum & blouse sont de nouveau cliquable pour les afficher en grands
- Sur mobile, lorsqu'on cliquait sur le premier élément de la navbar, ce dernier avait un overlay avec des angles arrondis
- Sur mobile, les utilisateurs avec des images de profils non carrées dépassait dans l'onglet Famille

* [UPDATE] Bump dict2xml from 1.7.2 to 1.7.3 (#592)

Bumps [dict2xml](https://github.com/delfick/python-dict2xml) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/delfick/python-dict2xml/releases)
- [Commits](https://github.com/delfick/python-dict2xml/compare/release-1.7.2...release-1.7.3)

---
updated-dependencies:
- dependency-name: dict2xml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

* [UPDATE] Bump django-debug-toolbar from 3.8.1 to 4.0.0 (#593)

Bumps [django-debug-toolbar](https://github.com/jazzband/django-debug-toolbar) from 3.8.1 to 4.0.0.
- [Release notes](https://github.com/jazzband/django-debug-toolbar/releases)
- [Changelog](https://github.com/jazzband/django-debug-toolbar/blob/main/docs/changes.rst)
- [Commits](https://github.com/jazzband/django-debug-toolbar/compare/3.8.1...4.0.0)

---
updated-dependencies:
- dependency-name: django-debug-toolbar
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* [UPDATE] Bump cryptography from 37.0.4 to 40.0.1 (#594)

* [UPDATE] Bump cryptography from 37.0.4 to 40.0.1

Bumps [cryptography](https://github.com/pyca/cryptography) from 37.0.4 to 40.0.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/37.0.4...40.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Updated pyOpenSSL to match cryptography requirements

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Julien Constant <julienconstant190@gmail.com>

* Mise à jour de Black vers la version 23.3 (#629)

* update link for poetry install

* [UPDATE] Bump django-countries from 7.5 to 7.5.1 (#624)

Bumps [django-countries](https://github.com/SmileyChris/django-countries) from 7.5 to 7.5.1.
- [Release notes](https://github.com/SmileyChris/django-countries/releases)
- [Changelog](https://github.com/SmileyChris/django-countries/blob/main/CHANGES.rst)
- [Commits](https://github.com/SmileyChris/django-countries/compare/v7.5...v7.5.1)

---
updated-dependencies:
- dependency-name: django-countries
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* [UPDATE] Bump sentry-sdk from 1.19.1 to 1.21.0

Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.19.1 to 1.21.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/1.19.1...1.21.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Speed up tests (#638)

* Better usage of cache for groups and clubs related operations (#634)

* Better usage of cache for group retrieval

* Cache clearing on object deletion or update

* replace signals by save and delete override

* add is_anonymous check in is_owned_by

Add in many is_owned_by(self, user) methods that user is not anonymous. Since many of those functions do db queries, this should reduce a little bit the load of the db.

* Stricter usage of User.is_in_group

Constrain the parameters that can be passed to the function to make sure only a str or an int can be used. Also force to explicitly specify if the group id or the group name is used.

* write test and correct bugs

* remove forgotten populate commands

* Correct test

* [FIX] Correction de bugs (#617)

* Fix #600

* Fix #602

* Fixes & améliorations du nouveau CSS (#616)

* Fix #604

* should fix #605

* Fix #608

* Update core/views/site.py

Co-Authored-By: thomas girod <56346771+imperosol@users.noreply.github.com>

* Added back the permission denied

* Should fix #609

* Fix failing test when 2 user are merged

* Should fix #610

* Should fix #627

* Should fix #109

Block les URLs suivantes lorsque le fichier se trouve dans le dir `profiles` ou `SAS` :
- `/file/<id>/`
- `/file/<id>/[delete|prop|edit]`

> Les urls du SAS restent accessiblent pour les roots & les admins SAS
> Les urls de profiles sont uniquement accessiblent aux roots

* Fix root dir of SAS being unnaccessible for sas admins

⚠️ need to edit the SAS directory & save it (no changes required in sas directory properties)

* Remove overwritten code

* Should fix duplicated albums in user profile (wtf)

* Fix typo

* Extended profiles picture access to board members

* Should fix #607

* Fix keyboard navigation not working properly

* Fix user tagged pictures section inside python rather than in the template

* Update utils.py

* Apply suggested changes

* Fix #604

* Fix #608

* Added back the permission denied

* Should fix duplicated albums in user profile (wtf)

* Fix user tagged pictures section inside python rather than in the template

* Apply suggested changes

---------

Co-authored-by: thomas girod <56346771+imperosol@users.noreply.github.com>

* Remove duplicated css

* Galaxy improvements (#628)

* galaxy: improve logging and performance reporting

* galaxy: add a full galaxy state test

* galaxy: optimize user self score computation

* galaxy: add 'generate_galaxy_test_data' command for development at scale

* galaxy: big refactor

Main changes:
  - Multiple Galaxy objects can now exist at the same time in DB. This allows for ruling a new galaxy while still
    displaying the old one.
  - The criteria to quickly know whether a user is a possible citizen is now a simple query on picture count. This
    avoids a very complicated query to database, that could often result in huge working memory load. With this change,
    it should be possible to run the galaxy even on a vanilla Postgres that didn't receive fine tuning for the Sith's
    galaxy.

* galaxy: template: make the galaxy graph work and be usable with a lot of stars

- Display focused star and its connections clearly
- Display star label faintly by default for other stars to avoid overloading the graph
- Hide non-focused lanes
- Avoid clicks on non-highlighted, too far stars
- Make the canva adapt its width to initial screen size, doesn't work dynamically

* galaxy: better docstrings

* galaxy: use bulk_create whenever possible

This is a big performance gain, especially for the tests.

Examples:

----

`./manage.py test galaxy.tests.GalaxyTest.test_full_galaxy_state`

Measurements averaged over 3 run on *my machine*™:
Before: 2min15s
After: 1m41s

----

`./manage.py generate_galaxy_test_data --user-pack-count 1`

Before: 48s
After: 25s

----

`./manage.py rule_galaxy` (for 600 citizen, corresponding to 1 user-pack)

Before: 14m4s
After: 12m34s

* core: populate: use a less ambiguous 'timezone.now()'

When running the tests around midnight, the day is changing, leading to some values being offset to the next day
depending on the timezone, and making some tests to fail. This ensure to use a less ambiguous `now` when populating
the database.

* write more extensive documentation

- add documentation to previously documented classes and functions and refactor some of the documented one, in accordance to the PEP257 and ReStructuredText standards ;
- add some type hints ;
- use a NamedTuple for the `Galaxy.compute_users_score` method instead of a raw tuple. Also change a little bit the logic in the function which call the latter ;
- add some additional parameter checks on a few functions ;
- change a little bit the logic of the log level setting for the galaxy related commands.

* galaxy: tests: split Model and View for more efficient data usage

---------

Co-authored-by: maréchal <thgirod@hotmail.com>

* [UPDATE] Bump libsass from 0.21.0 to 0.22.0 (#640)

Bumps [libsass](https://github.com/sass/libsass-python) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/sass/libsass-python/releases)
- [Changelog](https://github.com/sass/libsass-python/blob/main/docs/changes.rst)
- [Commits](https://github.com/sass/libsass-python/compare/0.21.0...0.22.0)

---
updated-dependencies:
- dependency-name: libsass
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* [FIX] Fix cached groups (#647)

* Bump sqlparse from 0.4.3 to 0.4.4 (#645)

Bumps [sqlparse](https://github.com/andialbrecht/sqlparse) from 0.4.3 to 0.4.4.
- [Release notes](https://github.com/andialbrecht/sqlparse/releases)
- [Changelog](https://github.com/andialbrecht/sqlparse/blob/master/CHANGELOG)
- [Commits](https://github.com/andialbrecht/sqlparse/compare/0.4.3...0.4.4)

---
updated-dependencies:
- dependency-name: sqlparse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* [UPDATE] Bump django-ordered-model from 3.6 to 3.7.4 (#625)

Bumps [django-ordered-model](https://github.com/django-ordered-model/django-ordered-model) from 3.6 to 3.7.4.
- [Release notes](https://github.com/django-ordered-model/django-ordered-model/releases)
- [Changelog](https://github.com/django-ordered-model/django-ordered-model/blob/master/CHANGES.md)
- [Commits](https://github.com/django-ordered-model/django-ordered-model/compare/3.6...3.7.4)

---
updated-dependencies:
- dependency-name: django-ordered-model
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix immutable default variable in `get_start_of_semester` (#656)

Le serveur ne percevait pas le changement de semestre, parce
que la valeur par défaut passée à la fonction `get_start_of_semester()` était une fonction appelée une seule fois, lors du lancement du serveur. Bref, c'était ça : https://beta.ruff.rs/docs/rules/function-call-in-default-argument/

---------

Co-authored-by: imperosol <thgirod@hotmail.com>

* Add missing method on AnonymousUser (#649)

* Add eurocks partnership in the eboutic (#661)

* Add eurocks partnership in the eboutic (#661)

Revert "Add eurocks partnership in the eboutic (#661)"

This reverts commit 193c820757.

Add eurocks partnership in the eboutic (#661)

* Update workflow

Following this update : https://github.blog/changelog/2023-09-13-github-actions-updates-to-github_ref-and-github-ref/

* Update workflow

* Remove eurocks tickets from eboutic (event is finished)

* Links update & translations typos fixes (#671)

* Remove BDF link (as BDF is now part of AE)

* Remove unused pages

* Fix typos

* Fix typo again

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Thomas Girod <thgirod@hotmail.com>
Co-authored-by: thomas girod <56346771+imperosol@users.noreply.github.com>
Co-authored-by: Théo DURR <git@theodurr.fr>
Co-authored-by: Skia <skia@hya.sk>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bartuccio Antoine <klmp200@users.noreply.github.com>
2023-10-10 15:41:19 +02:00
240 changed files with 4452 additions and 4600 deletions

View File

@ -7,7 +7,7 @@ runs:
uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: gettext libgraphviz-dev
version: 1.0 # increment to reset cache
version: 1.0 # increment to reset cache
- name: Install dependencies
run: |
@ -25,7 +25,7 @@ runs:
uses: actions/cache@v3
with:
path: ~/.local
key: poetry-0 # increment to reset cache
key: poetry-0 # increment to reset cache
- name: Install Poetry
if: steps.cached-poetry.outputs.cache-hit != 'true'
@ -45,11 +45,7 @@ runs:
${{ runner.os }}-poetry-
- name: Install dependencies
run: poetry install --with docs,tests
shell: bash
- name: Install xapian
run: poetry run ./manage.py install_xapian
run: poetry install -E testing -E docs
shell: bash
- name: Compile gettext messages

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

@ -2,35 +2,38 @@ name: Sith 3 CI
on:
push:
branches: [master, taiste]
branches: [master, taiste, features/**]
pull_request:
branches: [master, taiste]
workflow_dispatch:
jobs:
ruff:
name: Ruff lint & format
black:
name: Black 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
- name: Check out repository
uses: actions/checkout@v3
- name: Setup Project
uses: ./.github/actions/setup_project
- run: poetry run black --check .
tests:
name: Run tests and generate coverage report
runs-on: ubuntu-latest
container:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.14
env:
discovery.type: single-node
ports:
- 9200
steps:
- name: Check out repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- uses: ./.github/actions/setup_project
- uses: ./.github/actions/setup_xapian
- uses: ./.github/actions/compile_messages
- name: Run tests
run: poetry run coverage run -m pytest
run: poetry run coverage run ./manage.py test
- name: Generate coverage report
run: |
poetry run coverage report

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

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2016 Skia
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,19 +1,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -1,27 +1,24 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.contrib import admin
from accounting.models import *
admin.site.register(BankAccount)
admin.site.register(ClubAccount)
admin.site.register(GeneralJournal)

View File

@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models
import django.core.validators
import accounting.models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import phonenumber_field.modelfields
from django.db import migrations, models
import phonenumber_field.modelfields
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,36 +1,32 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 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.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.template import defaultfilters
from phonenumber_field.modelfields import PhoneNumberField
from decimal import Decimal
from core.models import User, SithFile
from club.models import Club
from core.models import SithFile, User
class CurrencyField(models.DecimalField):

View File

@ -1,99 +1,100 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 datetime import date, timedelta
from django.test import TestCase
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 (
AccountingType,
GeneralJournal,
Label,
Operation,
Label,
AccountingType,
SimplifiedAccountingType,
)
from core.models import User
class RefoundAccountTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.skia = User.objects.get(username="skia")
def setUp(self):
self.skia = User.objects.filter(username="skia").first()
# reffil skia's account
cls.skia.customer.amount = 800
cls.skia.customer.save()
cls.refound_account_url = reverse("accounting:refound_account")
self.skia.customer.amount = 800
self.skia.customer.save()
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(
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)
assert response_get.status_code == 403
assert response_post.status_code == 403
response_get = self.client.get(reverse("accounting:refound_account"))
self.assertTrue(response_get.status_code == 403)
self.assertTrue(response_post.status_code == 403)
def test_root_granteed(self):
self.client.force_login(User.objects.get(username="root"))
response = self.client.post(self.refound_account_url, {"user": self.skia.id})
self.assertRedirects(response, self.refound_account_url)
self.skia.refresh_from_db()
response = self.client.get(self.refound_account_url)
assert response.status_code == 200
assert '<form action="" method="post">' in str(response.content)
assert self.skia.customer.amount == 0
self.client.login(username="root", password="plop")
response_post = self.client.post(
reverse("accounting:refound_account"), {"user": self.skia.id}
)
self.skia = User.objects.filter(username="skia").first()
response_get = self.client.get(reverse("accounting:refound_account"))
self.assertFalse(response_get.status_code == 403)
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):
self.client.force_login(User.objects.get(username="comptable"))
response = self.client.post(self.refound_account_url, {"user": self.skia.id})
self.assertRedirects(response, self.refound_account_url)
self.skia.refresh_from_db()
response = self.client.get(self.refound_account_url)
assert response.status_code == 200
assert '<form action="" method="post">' in str(response.content)
assert self.skia.customer.amount == 0
self.client.login(username="comptable", password="plop")
response_post = self.client.post(
reverse("accounting:refound_account"), {"user": self.skia.id}
)
self.skia = User.objects.filter(username="skia").first()
response_get = self.client.get(reverse("accounting:refound_account"))
self.assertFalse(response_get.status_code == 403)
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):
@classmethod
def setUpTestData(cls):
cls.journal = GeneralJournal.objects.get(id=1)
def setUp(self):
self.journal = GeneralJournal.objects.filter(id=1).first()
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(
reverse("accounting:journal_details", args=[self.journal.id])
)
assert response_get.status_code == 200
assert "<td>M\\xc3\\xa9thode de paiement</td>" in str(response_get.content)
self.assertTrue(response_get.status_code == 200)
self.assertTrue(
"<td>M\\xc3\\xa9thode de paiement</td>" in str(response_get.content)
)
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(
reverse("accounting:journal_details", args=[self.journal.id])
)
assert response_get.status_code == 403
assert "<td>M\xc3\xa9thode de paiement</td>" not in str(response_get.content)
self.assertTrue(response_get.status_code == 403)
self.assertFalse(
"<td>M\xc3\xa9thode de paiement</td>" in str(response_get.content)
)
class OperationTest(TestCase):
@ -107,8 +108,9 @@ class OperationTest(TestCase):
code="443", label="Ce code n'existe pas", movement_type="CREDIT"
)
at.save()
l = Label.objects.create(club_account=self.journal.club_account, name="bob")
self.client.force_login(User.objects.get(username="comptable"))
l = Label(club_account=self.journal.club_account, name="bob")
l.save()
self.client.login(username="comptable", password="plop")
self.op1 = Operation(
journal=self.journal,
date=date.today(),
@ -137,7 +139,8 @@ class OperationTest(TestCase):
self.op2.save()
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(
reverse("accounting:op_new", args=[self.journal.id]),
{
@ -169,7 +172,8 @@ class OperationTest(TestCase):
self.assertTrue("<td>Le fantome de la nuit</td>" in str(response_get.content))
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(
reverse("accounting:op_new", args=[self.journal.id]),
{
@ -195,7 +199,7 @@ class OperationTest(TestCase):
)
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()
response = self.client.post(
reverse("accounting:op_new", args=[self.journal.id]),
@ -222,6 +226,7 @@ class OperationTest(TestCase):
)
def test__operation_simple_accounting(self):
self.client.login(username="comptable", password="plop")
sat = SimplifiedAccountingType.objects.all().first()
response = self.client.post(
reverse("accounting:op_new", args=[self.journal.id]),
@ -258,12 +263,14 @@ class OperationTest(TestCase):
)
def test_nature_statement(self):
self.client.login(username="comptable", password="plop")
response = self.client.get(
reverse("accounting:journal_nature_statement", args=[self.journal.id])
)
self.assertContains(response, "bob (Troll Penché) : 3.00", status_code=200)
def test_person_statement(self):
self.client.login(username="comptable", password="plop")
response = self.client.get(
reverse("accounting:journal_person_statement", args=[self.journal.id])
)
@ -285,6 +292,7 @@ class OperationTest(TestCase):
)
def test_accounting_statement(self):
self.client.login(username="comptable", password="plop")
response = self.client.get(
reverse("accounting:journal_accounting_statement", args=[self.journal.id])
)

View File

@ -1,21 +1,17 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.urls import path

View File

@ -1,58 +1,54 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 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
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 (
CanCreateMixin,
CanViewMixin,
CanEditMixin,
CanEditPropMixin,
CanViewMixin,
CanCreateMixin,
TabedViewMixin,
)
from core.views.forms import SelectDate, SelectFile
from counter.models import Counter, Product, Selling
from core.views.forms import SelectFile, SelectDate
from accounting.models import (
BankAccount,
ClubAccount,
GeneralJournal,
Operation,
AccountingType,
Company,
SimplifiedAccountingType,
Label,
)
from counter.models import Counter, Selling, Product
# Main accounting view
@ -525,14 +521,14 @@ class OperationPDFView(CanViewMixin, DetailView):
pk_url_kwarg = "op_id"
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.pagesizes import letter
from reportlab.lib.units import cm
from reportlab.lib.utils import ImageReader
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from reportlab.platypus import Table, TableStyle
from reportlab.pdfbase import pdfmetrics
pdfmetrics.registerFont(TTFont("DejaVu", "DejaVuSerif.ttf"))
@ -603,7 +599,7 @@ class OperationPDFView(CanViewMixin, DetailView):
payment_mode = ""
for m in settings.SITH_ACCOUNTING_PAYMENT_METHOD:
if m[0] == mode:
payment_mode += "[\u00d7]"
payment_mode += "[\u00D7]"
else:
payment_mode += "[ ]"
payment_mode += " %s\n" % (m[1])

View File

@ -1,19 +1,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -1,21 +1,19 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.contrib import admin
# Register your models here.

View File

@ -1,21 +1,19 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.db import models
# Create your models here.

View File

@ -1,21 +1,19 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.test import TestCase
# Create your tests here.

View File

@ -1,27 +1,23 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.urls import include, path, re_path
from rest_framework import routers
from django.urls import re_path, path, include
from api.views import *
from rest_framework import routers
# Router config
router = routers.DefaultRouter()

View File

@ -1,30 +1,26 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 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 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):
@ -68,10 +64,10 @@ class RightModelViewSet(ManageModelMixin, viewsets.ModelViewSet):
from .api import *
from .club import *
from .counter import *
from .user import *
from .club import *
from .group import *
from .launderette import *
from .sas import *
from .user import *
from .uv import *
from .sas import *

View File

@ -1,26 +1,22 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 rest_framework.response import Response
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import StaticHTMLRenderer
from rest_framework.response import Response
from core.templatetags.renderer import markdown

View File

@ -1,32 +1,30 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.conf import settings
from django.core.exceptions import PermissionDenied
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.decorators import api_view, renderer_classes
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 club.models import Club, Mailing
class ClubSerializer(serializers.ModelSerializer):

View File

@ -1,29 +1,26 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.decorators import action
from counter.models import Counter
from api.views import RightModelViewSet
from counter.models import Counter
class CounterSerializer(serializers.ModelSerializer):

View File

@ -1,28 +1,25 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 rest_framework import serializers
from api.views import RightModelViewSet
from core.models import RealGroup
from api.views import RightModelViewSet
class GroupSerializer(serializers.ModelSerializer):
class Meta:

View File

@ -1,29 +1,26 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 rest_framework import serializers
from rest_framework.decorators import action
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 launderette.models import Launderette, Machine, Token
class LaunderettePlaceSerializer(serializers.ModelSerializer):

View File

@ -1,5 +1,4 @@
from typing import List
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.exceptions import PermissionDenied
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.response import Response
from core.models import User
from core.views import can_edit
from core.models import User
from sas.models import Picture

View File

@ -1,31 +1,28 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#
import datetime
from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.decorators import action
from core.models import User
from api.views import RightModelViewSet
from core.models import User
class UserSerializer(serializers.ModelSerializer):

View File

@ -1,12 +1,11 @@
import json
import urllib.request
from django.conf import settings
from django.core.exceptions import PermissionDenied
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.decorators import api_view, renderer_classes
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

View File

@ -1,19 +1,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -1,21 +1,17 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 ajax_select import make_ajax_form
from django.contrib import admin

View File

@ -1,32 +1,40 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 import forms
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.views.forms import SelectDate, TzAwareDateTimeField
from core.views.forms import SelectDate, SelectDateTime
from counter.models import Counter
from core.views.forms import TzAwareDateTimeField
class ClubEditForm(forms.ModelForm):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.utils.timezone
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
from django.db import migrations, models
class Migration(migrations.Migration):

View File

@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import re
import django.core.validators
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):

View File

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
from club.models import Club
from core.operations import PsqlRunOnly
import django.db.models.deletion
def generate_club_pages(apps, schema_editor):

View File

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
import club.models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,37 +1,44 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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.core import validators
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.validators import RegexValidator, validate_email
from django.db import models, transaction
from django.db import models
from django.core import validators
from django.conf import settings
from django.db.models import Q
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError, ObjectDoesNotExist
from django.db import transaction
from django.urls import reverse
from django.utils import timezone
from django.core.validators import RegexValidator, validate_email
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.

View File

@ -1,35 +1,32 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 datetime import timedelta
from django.conf import settings
from django.core.cache import cache
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from django.utils.timezone import localtime, now
from django.utils import timezone, html
from django.utils.timezone import now, localtime
from django.utils.translation import gettext as _
from django.urls import reverse
from django.core.management import call_command
from core.models import User, AnonymousUser
from club.models import Club, Membership, Mailing
from club.forms import MailingForm
from club.models import Club, Mailing, Membership
from core.models import AnonymousUser, User
from sith.settings import SITH_BAR_MANAGER, SITH_MAIN_CLUB_ID
@ -53,7 +50,6 @@ class ClubTest(TestCase):
cls.richard = User.objects.get(username="rbatsbak")
cls.comptable = User.objects.get(username="comptable")
cls.sli = User.objects.get(username="sli")
cls.root = User.objects.get(username="root")
# subscribed users - not initial members
cls.krophil = User.objects.get(username="krophil")
@ -107,42 +103,45 @@ class MembershipQuerySetTest(ClubTest):
Test that the ongoing queryset method returns the memberships that
are not ended.
"""
current_members = list(self.club.members.ongoing().order_by("id"))
current_members = self.club.members.ongoing()
expected = [
self.skia.memberships.get(club=self.club),
self.comptable.memberships.get(club=self.club),
self.richard.memberships.get(club=self.club),
]
expected.sort(key=lambda i: i.id)
assert current_members == expected
self.assertEqual(len(current_members), len(expected))
for member in current_members:
self.assertIn(member, expected)
def test_board(self):
"""
Test that the board queryset method returns the memberships
of user in the club board
"""
board_members = list(self.club.members.board().order_by("id"))
board_members = list(self.club.members.board())
expected = [
self.skia.memberships.get(club=self.club),
self.comptable.memberships.get(club=self.club),
# sli is no more member, but he was in the board
self.sli.memberships.get(club=self.club),
]
expected.sort(key=lambda i: i.id)
assert board_members == expected
self.assertEqual(len(board_members), len(expected))
for member in board_members:
self.assertIn(member, expected)
def test_ongoing_board(self):
"""
Test that combining ongoing and board returns users
who are currently board members of the club
"""
members = list(self.club.members.ongoing().board().order_by("id"))
members = list(self.club.members.ongoing().board())
expected = [
self.skia.memberships.get(club=self.club),
self.comptable.memberships.get(club=self.club),
]
expected.sort(key=lambda i: i.id)
assert members == expected
self.assertEqual(len(members), len(expected))
for member in members:
self.assertIn(member, expected)
def test_update_invalidate_cache(self):
"""
@ -151,9 +150,8 @@ class MembershipQuerySetTest(ClubTest):
mem_skia = self.skia.memberships.get(club=self.club)
cache.set(f"membership_{mem_skia.club_id}_{mem_skia.user_id}", mem_skia)
self.skia.memberships.update(end_date=localtime(now()).date())
assert (
cache.get(f"membership_{mem_skia.club_id}_{mem_skia.user_id}")
== "not_member"
self.assertEqual(
cache.get(f"membership_{mem_skia.club_id}_{mem_skia.user_id}"), "not_member"
)
mem_richard = self.richard.memberships.get(club=self.club)
@ -162,8 +160,8 @@ class MembershipQuerySetTest(ClubTest):
)
self.richard.memberships.update(role=5)
new_mem = self.richard.memberships.get(club=self.club)
assert new_mem != "not_member"
assert new_mem.role == 5
self.assertNotEqual(new_mem, "not_member")
self.assertEqual(new_mem.role, 5)
def test_delete_invalidate_cache(self):
"""
@ -180,39 +178,40 @@ class MembershipQuerySetTest(ClubTest):
# should delete the subscriptions of skia and comptable
self.club.members.ongoing().board().delete()
assert (
cache.get(f"membership_{mem_skia.club_id}_{mem_skia.user_id}")
== "not_member"
self.assertEqual(
cache.get(f"membership_{mem_skia.club_id}_{mem_skia.user_id}"), "not_member"
)
assert (
cache.get(f"membership_{mem_comptable.club_id}_{mem_comptable.user_id}")
== "not_member",
self.assertEqual(
cache.get(f"membership_{mem_comptable.club_id}_{mem_comptable.user_id}"),
"not_member",
)
class ClubModelTest(ClubTest):
def assert_membership_started_today(self, user: User, role: int):
def assert_membership_just_started(self, user: User, role: int):
"""
Assert that the given membership is active and started today
"""
membership = user.memberships.ongoing().filter(club=self.club).first()
assert membership is not None
assert localtime(now()).date() == membership.start_date
assert membership.end_date is None
assert membership.role == role
assert membership.club.get_membership_for(user) == membership
self.assertIsNotNone(membership)
self.assertEqual(localtime(now()).date(), membership.start_date)
self.assertIsNone(membership.end_date)
self.assertEqual(membership.role, role)
self.assertEqual(membership.club.get_membership_for(user), membership)
member_group = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
board_group = self.club.unix_name + settings.SITH_BOARD_SUFFIX
assert user.is_in_group(name=member_group)
assert user.is_in_group(name=board_group)
self.assertTrue(user.is_in_group(name=member_group))
self.assertTrue(user.is_in_group(name=board_group))
def assert_membership_ended_today(self, user: User):
def assert_membership_just_ended(self, user: User):
"""
Assert that the given user have a membership which ended today
"""
today = localtime(now()).date()
assert user.memberships.filter(club=self.club, end_date=today).exists()
assert self.club.get_membership_for(user) is None
self.assertIsNotNone(
user.memberships.filter(club=self.club, end_date=today).first()
)
self.assertIsNone(self.club.get_membership_for(user))
def test_access_unauthorized(self):
"""
@ -220,20 +219,20 @@ class ClubModelTest(ClubTest):
cannot see the page
"""
response = self.client.post(self.members_url)
assert response.status_code == 403
self.assertEqual(response.status_code, 403)
self.client.force_login(self.public)
self.client.login(username="public", password="plop")
response = self.client.post(self.members_url)
assert response.status_code == 403
self.assertEqual(response.status_code, 403)
def test_display(self):
"""
Test that a GET request return a page where the requested
information are displayed.
"""
self.client.force_login(self.skia)
self.client.login(username=self.skia.username, password="plop")
response = self.client.get(self.members_url)
assert response.status_code == 200
self.assertEqual(response.status_code, 200)
expected_html = (
"<table><thead><tr>"
"<td>Utilisateur</td><td>Rôle</td><td>Description</td>"
@ -266,20 +265,20 @@ class ClubModelTest(ClubTest):
"""
Test that root users can add members to clubs, one at a time
"""
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
response = self.client.post(
self.members_url,
{"users": self.subscriber.id, "role": 3},
)
self.assertRedirects(response, self.members_url)
self.subscriber.refresh_from_db()
self.assert_membership_started_today(self.subscriber, role=3)
self.assert_membership_just_started(self.subscriber, role=3)
def test_root_add_multiple_club_member(self):
"""
Test that root users can add multiple members at once to clubs
"""
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
response = self.client.post(
self.members_url,
{
@ -289,36 +288,36 @@ class ClubModelTest(ClubTest):
)
self.assertRedirects(response, self.members_url)
self.subscriber.refresh_from_db()
self.assert_membership_started_today(self.subscriber, role=3)
self.assert_membership_started_today(self.krophil, role=3)
self.assert_membership_just_started(self.subscriber, role=3)
self.assert_membership_just_started(self.krophil, role=3)
def test_add_unauthorized_members(self):
"""
Test that users who are not currently subscribed
cannot be members of clubs.
"""
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
response = self.client.post(
self.members_url,
{"users": self.public.id, "role": 1},
)
assert not self.public.memberships.filter(club=self.club).exists()
assert '<ul class="errorlist"><li>' in response.content.decode()
self.assertIsNone(self.public.memberships.filter(club=self.club).first())
self.assertTrue('<ul class="errorlist"><li>' in str(response.content))
response = self.client.post(
self.members_url,
{"users": self.old_subscriber.id, "role": 1},
)
assert not self.public.memberships.filter(club=self.club).exists()
assert self.club.get_membership_for(self.public) is None
assert '<ul class="errorlist"><li>' in response.content.decode()
self.assertIsNone(self.public.memberships.filter(club=self.club).first())
self.assertIsNone(self.club.get_membership_for(self.public))
self.assertTrue('<ul class="errorlist"><li>' in str(response.content))
def test_add_members_already_members(self):
"""
Test that users who are already members of a club
cannot be added again to this club
"""
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
current_membership = self.skia.memberships.ongoing().get(club=self.club)
nb_memberships = self.skia.memberships.count()
self.client.post(
@ -326,10 +325,10 @@ class ClubModelTest(ClubTest):
{"users": self.skia.id, "role": current_membership.role + 1},
)
self.skia.refresh_from_db()
assert nb_memberships == self.skia.memberships.count()
self.assertEqual(nb_memberships, self.skia.memberships.count())
new_membership = self.skia.memberships.ongoing().get(club=self.club)
assert current_membership == new_membership
assert self.club.get_membership_for(self.skia) == new_membership
self.assertEqual(current_membership, new_membership)
self.assertEqual(self.club.get_membership_for(self.skia), new_membership)
def test_add_not_existing_users(self):
"""
@ -337,16 +336,15 @@ class ClubModelTest(ClubTest):
If one user in the request is invalid, no membership creation at all
can take place.
"""
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
nb_memberships = self.club.members.count()
response = self.client.post(
self.members_url,
{"users": [9999], "role": 1},
)
assert response.status_code == 200
assert '<ul class="errorlist"><li>' in response.content.decode()
self.assertContains(response, '<ul class="errorlist"><li>')
self.club.refresh_from_db()
assert self.club.members.count() == nb_memberships
self.assertEqual(self.club.members.count(), nb_memberships)
response = self.client.post(
self.members_url,
{
@ -355,10 +353,9 @@ class ClubModelTest(ClubTest):
"role": 3,
},
)
assert response.status_code == 200
assert '<ul class="errorlist"><li>' in response.content.decode()
self.assertContains(response, '<ul class="errorlist"><li>')
self.club.refresh_from_db()
assert self.club.members.count() == nb_memberships
self.assertEqual(self.club.members.count(), nb_memberships)
def test_president_add_members(self):
"""
@ -367,7 +364,7 @@ class ClubModelTest(ClubTest):
president = self.club.members.get(role=10).user
nb_club_membership = self.club.members.count()
nb_subscriber_memberships = self.subscriber.memberships.count()
self.client.force_login(president)
self.client.login(username=president.username, password="plop")
response = self.client.post(
self.members_url,
{"users": self.subscriber.id, "role": 9},
@ -375,55 +372,56 @@ class ClubModelTest(ClubTest):
self.assertRedirects(response, self.members_url)
self.club.refresh_from_db()
self.subscriber.refresh_from_db()
assert self.club.members.count() == nb_club_membership + 1
assert self.subscriber.memberships.count() == nb_subscriber_memberships + 1
self.assert_membership_started_today(self.subscriber, role=9)
self.assertEqual(self.club.members.count(), nb_club_membership + 1)
self.assertEqual(
self.subscriber.memberships.count(), nb_subscriber_memberships + 1
)
self.assert_membership_just_started(self.subscriber, role=9)
def test_add_member_greater_role(self):
"""
Test that a member of the club member cannot create
a membership with a greater role than its own.
"""
self.client.force_login(self.skia)
self.client.login(username=self.skia.username, password="plop")
nb_memberships = self.club.members.count()
response = self.client.post(
self.members_url,
{"users": self.subscriber.id, "role": 10},
)
assert response.status_code == 200
self.assertEqual(response.status_code, 200)
self.assertInHTML(
"<li>Vous n'avez pas la permission de faire cela</li>",
response.content.decode(),
)
self.club.refresh_from_db()
assert nb_memberships == self.club.members.count()
assert not self.subscriber.memberships.filter(club=self.club).exists()
self.assertEqual(nb_memberships, self.club.members.count())
self.assertIsNone(self.subscriber.memberships.filter(club=self.club).first())
def test_add_member_without_role(self):
"""
Test that trying to add members without specifying their role fails
"""
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
response = self.client.post(
self.members_url,
{"users": self.subscriber.id, "start_date": "12/06/2016"},
)
assert (
'<ul class="errorlist"><li>Vous devez choisir un r'
in response.content.decode()
self.assertTrue(
'<ul class="errorlist"><li>Vous devez choisir un r' in str(response.content)
)
def test_end_membership_self(self):
"""
Test that a member can end its own membership
"""
self.client.force_login(self.skia)
self.client.login(username="skia", password="plop")
self.client.post(
self.members_url,
{"users_old": self.skia.id},
)
self.skia.refresh_from_db()
self.assert_membership_ended_today(self.skia)
self.assert_membership_just_ended(self.skia)
def test_end_membership_lower_role(self):
"""
@ -431,14 +429,14 @@ class ClubModelTest(ClubTest):
of users with lower roles
"""
# remainder : skia has role 3, comptable has role 10, richard has role 1
self.client.force_login(self.skia)
self.client.login(username=self.skia.username, password="plop")
response = self.client.post(
self.members_url,
{"users_old": self.richard.id},
)
self.assertRedirects(response, self.members_url)
self.club.refresh_from_db()
self.assert_membership_ended_today(self.richard)
self.assert_membership_just_ended(self.richard)
def test_end_membership_higher_role(self):
"""
@ -446,18 +444,18 @@ class ClubModelTest(ClubTest):
of users with higher roles
"""
membership = self.comptable.memberships.filter(club=self.club).first()
self.client.force_login(self.skia)
self.client.login(username=self.skia.username, password="plop")
self.client.post(
self.members_url,
{"users_old": self.comptable.id},
)
self.club.refresh_from_db()
new_membership = self.club.get_membership_for(self.comptable)
assert new_membership is not None
assert new_membership == membership
self.assertIsNotNone(new_membership)
self.assertEqual(new_membership, membership)
membership = self.comptable.memberships.filter(club=self.club).first()
assert membership.end_date is None
self.assertIsNone(membership.end_date)
def test_end_membership_as_main_club_board(self):
"""
@ -469,29 +467,29 @@ class ClubModelTest(ClubTest):
Membership.objects.create(club=self.ae, user=self.subscriber, role=3)
nb_memberships = self.club.members.count()
self.client.force_login(self.subscriber)
self.client.login(username=self.subscriber.username, password="plop")
response = self.client.post(
self.members_url,
{"users_old": self.comptable.id},
)
self.assertRedirects(response, self.members_url)
self.assert_membership_ended_today(self.comptable)
assert self.club.members.ongoing().count() == nb_memberships - 1
self.assert_membership_just_ended(self.comptable)
self.assertEqual(self.club.members.ongoing().count(), nb_memberships - 1)
def test_end_membership_as_root(self):
"""
Test that root users can end the membership of anyone
"""
nb_memberships = self.club.members.count()
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
response = self.client.post(
self.members_url,
{"users_old": [self.comptable.id]},
)
self.assertRedirects(response, self.members_url)
self.assert_membership_ended_today(self.comptable)
assert self.club.members.ongoing().count() == nb_memberships - 1
assert self.club.members.count() == nb_memberships
self.assert_membership_just_ended(self.comptable)
self.assertEqual(self.club.members.ongoing().count(), nb_memberships - 1)
self.assertEqual(self.club.members.count(), nb_memberships)
def test_end_membership_as_foreigner(self):
"""
@ -499,15 +497,16 @@ class ClubModelTest(ClubTest):
"""
nb_memberships = self.club.members.count()
membership = self.richard.memberships.filter(club=self.club).first()
self.client.force_login(self.subscriber)
self.client.login(username="subscriber", password="root")
self.client.post(
self.members_url,
{"users_old": [self.richard.id]},
)
# nothing should have changed
new_mem = self.club.get_membership_for(self.richard)
assert self.club.members.count() == nb_memberships
assert membership == new_mem
self.assertIsNotNone(new_mem)
self.assertEqual(self.club.members.count(), nb_memberships)
self.assertEqual(membership, new_mem)
def test_delete_remove_from_meta_group(self):
"""
@ -520,7 +519,7 @@ class ClubModelTest(ClubTest):
self.club.delete()
for user in users:
assert not user.is_in_group(name=meta_group)
self.assertFalse(user.is_in_group(name=meta_group))
def test_add_to_meta_group(self):
"""
@ -528,11 +527,11 @@ class ClubModelTest(ClubTest):
"""
group_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
board_members = self.club.unix_name + settings.SITH_BOARD_SUFFIX
assert not self.subscriber.is_in_group(name=group_members)
assert not self.subscriber.is_in_group(name=board_members)
self.assertFalse(self.subscriber.is_in_group(name=group_members))
self.assertFalse(self.subscriber.is_in_group(name=board_members))
Membership.objects.create(club=self.club, user=self.subscriber, role=3)
assert self.subscriber.is_in_group(name=group_members)
assert self.subscriber.is_in_group(name=board_members)
self.assertTrue(self.subscriber.is_in_group(name=group_members))
self.assertTrue(self.subscriber.is_in_group(name=board_members))
def test_remove_from_meta_group(self):
"""
@ -540,24 +539,24 @@ class ClubModelTest(ClubTest):
"""
group_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
board_members = self.club.unix_name + settings.SITH_BOARD_SUFFIX
assert self.comptable.is_in_group(name=group_members)
assert self.comptable.is_in_group(name=board_members)
self.assertTrue(self.comptable.is_in_group(name=group_members))
self.assertTrue(self.comptable.is_in_group(name=board_members))
self.comptable.memberships.update(end_date=localtime(now()))
assert not self.comptable.is_in_group(name=group_members)
assert not self.comptable.is_in_group(name=board_members)
self.assertFalse(self.comptable.is_in_group(name=group_members))
self.assertFalse(self.comptable.is_in_group(name=board_members))
def test_club_owner(self):
"""
Test that a club is owned only by board members of the main club
"""
anonymous = AnonymousUser()
assert not self.club.is_owned_by(anonymous)
assert not self.club.is_owned_by(self.subscriber)
self.assertFalse(self.club.is_owned_by(anonymous))
self.assertFalse(self.club.is_owned_by(self.subscriber))
# make sli a board member
self.sli.memberships.all().delete()
Membership(club=self.ae, user=self.sli, role=3).save()
assert self.club.is_owned_by(self.sli)
self.assertTrue(self.club.is_owned_by(self.sli))
class MailingFormTest(TestCase):
@ -565,13 +564,11 @@ class MailingFormTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.skia = User.objects.get(username="skia")
cls.rbatsbak = User.objects.get(username="rbatsbak")
cls.krophil = User.objects.get(username="krophil")
cls.comunity = User.objects.get(username="comunity")
cls.root = User.objects.get(username="root")
cls.bdf = Club.objects.get(unix_name=SITH_BAR_MANAGER["unix_name"])
cls.mail_url = reverse("club:mailing", kwargs={"club_id": cls.bdf.id})
cls.skia = User.objects.filter(username="skia").first()
cls.rbatsbak = User.objects.filter(username="rbatsbak").first()
cls.krophil = User.objects.filter(username="krophil").first()
cls.comunity = User.objects.filter(username="comunity").first()
cls.bdf = Club.objects.filter(unix_name=SITH_BAR_MANAGER["unix_name"]).first()
def setUp(self):
Membership(
@ -583,125 +580,134 @@ class MailingFormTest(TestCase):
def test_mailing_list_add_no_moderation(self):
# Test with Communication admin
self.client.force_login(self.comunity)
response = self.client.post(
self.mail_url,
self.client.login(username="comunity", password="plop")
self.client.post(
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "foyer"},
)
self.assertRedirects(response, self.mail_url)
response = self.client.get(self.mail_url)
assert response.status_code == 200
assert "Liste de diffusion foyer@utbm.fr" in response.content.decode()
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, text="Liste de diffusion foyer@utbm.fr")
# Test with Root
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
assert "Liste de diffusion mde@utbm.fr" in response.content.decode()
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, text="Liste de diffusion mde@utbm.fr")
def test_mailing_list_add_moderation(self):
self.client.force_login(self.rbatsbak)
self.client.login(username="rbatsbak", password="plop")
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
content = response.content.decode()
assert "Liste de diffusion mde@utbm.fr" not in content
assert "<p>Listes de diffusions en attente de modération</p>" in content
assert "<li>mde@utbm.fr" in content
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertNotContains(response, text="Liste de diffusion mde@utbm.fr")
self.assertContains(
response, text="<p>Listes de diffusions en attente de modération</p>"
)
self.assertContains(response, "<li>mde@utbm.fr")
def test_mailing_list_forbidden(self):
# With anonymous user
response = self.client.get(self.mail_url)
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, "", status_code=403)
# With user not in club
self.client.force_login(self.krophil)
response = self.client.get(self.mail_url)
assert response.status_code == 403
self.client.login(username="krophil", password="plop")
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, "", status_code=403)
def test_add_new_subscription_fail_not_moderated(self):
self.client.force_login(self.rbatsbak)
self.client.login(username="rbatsbak", password="plop")
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
)
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": self.skia.id,
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
assert "skia@git.an" not in response.content.decode()
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertNotContains(response, "skia@git.an")
def test_add_new_subscription_success(self):
# Prepare mailing list
self.client.force_login(self.comunity)
self.client.login(username="comunity", password="plop")
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
)
# Add single user
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": self.skia.id,
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
assert "skia@git.an" in response.content.decode()
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, "skia@git.an")
# Add multiple users
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": "|%s|%s|" % (self.comunity.id, self.rbatsbak.id),
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
content = response.content.decode()
assert "richard@git.an" in content
assert "comunity@git.an" in content
assert "skia@git.an" in content
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, "richard@git.an")
self.assertContains(response, "comunity@git.an")
self.assertContains(response, "skia@git.an")
# Add arbitrary email
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_email": "arbitrary@git.an",
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
content = response.content.decode()
assert "richard@git.an" in content
assert "comunity@git.an" in content
assert "skia@git.an" in content
assert "arbitrary@git.an" in content
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, "richard@git.an")
self.assertContains(response, "comunity@git.an")
self.assertContains(response, "skia@git.an")
self.assertContains(response, "arbitrary@git.an")
# Add user and arbitrary email
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_email": "more.arbitrary@git.an",
@ -709,61 +715,57 @@ class MailingFormTest(TestCase):
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
content = response.content.decode()
assert "richard@git.an" in content
assert "comunity@git.an" in content
assert "skia@git.an" in content
assert "arbitrary@git.an" in content
assert "more.arbitrary@git.an" in content
assert "krophil@git.an" in content
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
self.assertContains(response, "richard@git.an")
self.assertContains(response, "comunity@git.an")
self.assertContains(response, "skia@git.an")
self.assertContains(response, "arbitrary@git.an")
self.assertContains(response, "more.arbitrary@git.an")
self.assertContains(response, "krophil@git.an")
def test_add_new_subscription_fail_form_errors(self):
# Prepare mailing list
self.client.force_login(self.comunity)
self.client.login(username="comunity", password="plop")
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
)
# Neither email or email is specified
response = self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
assert response.status_code
self.assertInHTML(
_("You must specify at least an user or an email address"),
response.content.decode(),
self.assertContains(
response, text=_("You must specify at least an user or an email address")
)
# No mailing specified
response = self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": self.krophil.id,
},
)
assert response.status_code == 200
assert _("This field is required") in response.content.decode()
self.assertContains(response, text=_("This field is required"))
# One of the selected users doesn't exist
response = self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": "|789|",
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
assert response.status_code == 200
self.assertInHTML(
_("One of the selected users doesn't exist"), response.content.decode()
self.assertContains(
response, text=html.escape(_("One of the selected users doesn't exist"))
)
# An user has no email adress
@ -771,17 +773,18 @@ class MailingFormTest(TestCase):
self.krophil.save()
response = self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": self.krophil.id,
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
assert response.status_code == 200
self.assertInHTML(
_("One of the selected users doesn't have an email address"),
response.content.decode(),
self.assertContains(
response,
text=html.escape(
_("One of the selected users doesn't have an email address")
),
)
self.krophil.email = "krophil@git.an"
@ -790,7 +793,7 @@ class MailingFormTest(TestCase):
# An user is added twice
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": self.krophil.id,
@ -799,29 +802,28 @@ class MailingFormTest(TestCase):
)
response = self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": self.krophil.id,
"subscription_mailing": Mailing.objects.get(email="mde").id,
},
)
assert response.status_code == 200
self.assertInHTML(
_("This email is already suscribed in this mailing"),
response.content.decode(),
self.assertContains(
response,
text=html.escape(_("This email is already suscribed in this mailing")),
)
def test_remove_subscription_success(self):
# Prepare mailing list
self.client.force_login(self.comunity)
self.client.login(username="comunity", password="plop")
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"},
)
mde = Mailing.objects.get(email="mde")
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_NEW_SUBSCRIPTION,
"subscription_users": "|%s|%s|%s|"
@ -830,36 +832,37 @@ class MailingFormTest(TestCase):
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
content = response.content.decode()
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
assert "comunity@git.an" in content
assert "richard@git.an" in content
assert "krophil@git.an" in content
self.assertContains(response, "comunity@git.an")
self.assertContains(response, "richard@git.an")
self.assertContains(response, "krophil@git.an")
# Delete one user
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_REMOVE_SUBSCRIPTION,
"removal_%d" % mde.id: mde.subscriptions.get(user=self.krophil).id,
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
content = response.content.decode()
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
assert "comunity@git.an" in content
assert "richard@git.an" in content
assert "krophil@git.an" not in content
self.assertContains(response, "comunity@git.an")
self.assertContains(response, "richard@git.an")
self.assertNotContains(response, "krophil@git.an")
# Delete multiple users
self.client.post(
self.mail_url,
reverse("club:mailing", kwargs={"club_id": self.bdf.id}),
{
"action": MailingForm.ACTION_REMOVE_SUBSCRIPTION,
"removal_%d" % mde.id: [
"removal_%d"
% mde.id: [
user.id
for user in mde.subscriptions.filter(
user__in=[self.rbatsbak, self.comunity]
@ -867,13 +870,13 @@ class MailingFormTest(TestCase):
],
},
)
response = self.client.get(self.mail_url)
assert response.status_code == 200
content = response.content.decode()
response = self.client.get(
reverse("club:mailing", kwargs={"club_id": self.bdf.id})
)
assert "comunity@git.an" not in content
assert "richard@git.an" not in content
assert "krophil@git.an" not in content
self.assertNotContains(response, "comunity@git.an")
self.assertNotContains(response, "richard@git.an")
self.assertNotContains(response, "krophil@git.an")
class ClubSellingViewTest(TestCase):
@ -881,17 +884,15 @@ class ClubSellingViewTest(TestCase):
Perform basics tests to ensure that the page is available
"""
@classmethod
def setUpTestData(cls):
cls.ae = Club.objects.get(unix_name="ae")
cls.skia = User.objects.get(username="skia")
def setUp(self):
self.ae = Club.objects.filter(unix_name="ae").first()
def test_page_not_internal_error(self):
"""
Test that the page does not return and internal error
"""
self.client.force_login(self.skia)
self.client.login(username="skia", password="plop")
response = self.client.get(
reverse("club:club_sellings", kwargs={"club_id": self.ae.id})
)
assert response.status_code == 200
self.assertFalse(response.status_code == 500)

View File

@ -1,21 +1,26 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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

View File

@ -1,63 +1,76 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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
from django.conf import settings
from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied, ValidationError
from django.core.paginator import InvalidPage, Paginator
from django.db.models import Sum
from django import forms
from django.views.generic import ListView, DetailView, TemplateView, View
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 (
Http404,
HttpResponseRedirect,
HttpResponse,
Http404,
StreamingHttpResponse,
)
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 as _t
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, TemplateView, View
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.utils.translation import gettext as _t
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 (
CanCreateMixin,
CanViewMixin,
CanEditMixin,
CanEditPropMixin,
CanViewMixin,
DetailFormView,
PageEditViewBase,
TabedViewMixin,
UserIsRootMixin,
TabedViewMixin,
PageEditViewBase,
DetailFormView,
)
from core.models import PageRev
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):
def get_tabs_title(self):
@ -598,7 +611,7 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
}
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
"""
@ -615,7 +628,7 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView):
mailing.save()
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
"""

View File

@ -1,19 +1,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -1,21 +1,17 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 ajax_select import make_ajax_form
from django.contrib import admin

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,37 +1,44 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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.core.exceptions import ValidationError
from django.core.mail import EmailMultiAlternatives
from django.shortcuts import render
from django.db import models, transaction
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 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 club.models import Club
from core import utils
from core.models import Notification, Preferences, RealGroup, User
from core.models import User, Preferences, RealGroup, Notification, SithFile
from club.models import Club
class Sith(models.Model):

View File

@ -1,69 +1,63 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#
import pytest
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.conf import settings
from django.urls import reverse
from django.core.management import call_command
from django.utils import html
from django.utils.timezone import localtime, now
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 AnonymousUser, RealGroup, User
from com.models import Sith, News, Weekmail, WeekmailArticle, Poster
from core.models import User, RealGroup, AnonymousUser
@pytest.fixture()
def user_community():
return User.objects.get(username="comunity")
class ComAlertTest(TestCase):
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
@pytest.mark.parametrize(
"url",
[
reverse("com:alert_edit"),
reverse("com:info_edit"),
],
)
def test_com_page_is_working(client, url, user_community):
client.force_login(user_community)
response = client.get(url)
assert response.status_code == 200
class ComInfoTest(TestCase):
def test_page_is_working(self):
self.client.login(username="comunity", password="plop")
response = self.client.get(reverse("com:info_edit"))
self.assertNotEqual(response.status_code, 500)
self.assertEqual(response.status_code, 200)
class ComTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.skia = User.objects.get(username="skia")
cls.skia = User.objects.filter(username="skia").first()
cls.com_group = RealGroup.objects.filter(
id=settings.SITH_GROUP_COM_ADMIN_ID
).first()
cls.skia.groups.set([cls.com_group])
cls.skia.save()
def setUp(self):
self.client.force_login(self.skia)
self.client.login(username=self.skia.username, password="plop")
def test_alert_msg(self):
self.client.post(
response = self.client.post(
reverse("com:alert_edit"),
{
"alert_msg": """
@ -74,6 +68,7 @@ class ComTest(TestCase):
},
)
r = self.client.get(reverse("core:index"))
self.assertTrue(r.status_code == 200)
self.assertContains(
r,
"""<div id="alert_box">
@ -82,7 +77,7 @@ class ComTest(TestCase):
)
def test_info_msg(self):
self.client.post(
response = self.client.post(
reverse("com:info_edit"),
{
"info_msg": """
@ -91,6 +86,7 @@ class ComTest(TestCase):
},
)
r = self.client.get(reverse("core:index"))
self.assertTrue(r.status_code == 200)
self.assertContains(
r,
"""<div id="info_box">
@ -98,7 +94,7 @@ class ComTest(TestCase):
)
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"))
self.assertContains(
response,
@ -127,13 +123,13 @@ class SithTest(TestCase):
sith: Sith = Sith.objects.first()
com_admin = User.objects.get(username="comunity")
assert sith.is_owned_by(com_admin)
self.assertTrue(sith.is_owned_by(com_admin))
anonymous = AnonymousUser()
assert not sith.is_owned_by(anonymous)
self.assertFalse(sith.is_owned_by(anonymous))
sli = User.objects.get(username="sli")
assert not sith.is_owned_by(sli)
self.assertFalse(sith.is_owned_by(sli))
class NewsTest(TestCase):
@ -158,10 +154,10 @@ class NewsTest(TestCase):
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)
self.assertTrue(self.new.is_owned_by(self.com_admin))
self.assertTrue(self.new.is_owned_by(self.author))
self.assertFalse(self.new.is_owned_by(self.anonymous))
self.assertFalse(self.new.is_owned_by(self.sli))
def test_news_viewer(self):
"""
@ -169,26 +165,26 @@ class NewsTest(TestCase):
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.assertTrue(self.new.can_be_viewed_by(self.com_admin))
self.assertFalse(self.new.can_be_viewed_by(self.sli))
self.assertFalse(self.new.can_be_viewed_by(self.anonymous))
self.assertFalse(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)
self.assertTrue(self.new.can_be_viewed_by(self.com_admin))
self.assertTrue(self.new.can_be_viewed_by(self.sli))
self.assertTrue(self.new.can_be_viewed_by(self.anonymous))
self.assertTrue(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)
self.assertTrue(self.new.can_be_edited_by(self.com_admin))
self.assertFalse(self.new.can_be_edited_by(self.sli))
self.assertFalse(self.new.can_be_edited_by(self.anonymous))
self.assertFalse(self.new.can_be_edited_by(self.author))
class WeekmailArticleTest(TestCase):
@ -211,10 +207,10 @@ class WeekmailArticleTest(TestCase):
"""
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)
self.assertTrue(self.article.is_owned_by(self.com_admin))
self.assertFalse(self.article.is_owned_by(self.author))
self.assertFalse(self.article.is_owned_by(self.anonymous))
self.assertFalse(self.article.is_owned_by(self.sli))
class PosterTest(TestCase):
@ -237,8 +233,8 @@ class PosterTest(TestCase):
"""
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)
self.assertTrue(self.poster.is_owned_by(self.com_admin))
self.assertFalse(self.poster.is_owned_by(self.anonymous))
assert not self.poster.is_owned_by(self.susbcriber)
assert self.poster.is_owned_by(self.sli)
self.assertFalse(self.poster.is_owned_by(self.susbcriber))
self.assertTrue(self.poster.is_owned_by(self.sli))

View File

@ -1,21 +1,17 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 django.urls import path

View File

@ -1,52 +1,60 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.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 smtplib import SMTPRecipientsRefused
from django import forms
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 com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle, Screen, Poster
from core.views import (
CanCreateMixin,
CanViewMixin,
CanEditMixin,
CanEditPropMixin,
CanViewMixin,
QuickNotifMixin,
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

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,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -1,29 +1,25 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 ajax_select import make_ajax_form
from django.contrib import admin
from ajax_select import make_ajax_form
from core.models import User, Page, RealGroup, MetaGroup, SithFile
from django.contrib.auth.models import Group as AuthGroup
from haystack.admin import SearchModelAdmin
from core.models import MetaGroup, Page, RealGroup, SithFile, User
admin.site.unregister(AuthGroup)
admin.site.register(MetaGroup)

View File

@ -1,21 +1,25 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2017
# - Skia <skia@libskia.so>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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
@ -30,8 +34,8 @@ class SithConfig(AppConfig):
verbose_name = "Core app of the Sith"
def ready(self):
import core.signals # noqa F401
from forum.models import Forum
import core.signals
cache.clear()

View File

@ -1,23 +1,3 @@
# -*- 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

View File

@ -1,31 +1,28 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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 ajax_select import LookupChannel, register
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 counter.models import Counter, Customer, Product
from core.models import User, Group, SithFile
from club.models import Club
from counter.models import Product, Counter, Customer
from accounting.models import ClubAccount, Company
from eboutic.models import BasketItem
def check_token(request):

View File

@ -1,19 +1,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -1,19 +1,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -23,8 +23,8 @@
#
import os
from django.core.management.base import BaseCommand
from django.core.management import call_command
from core.models import SithFile

View File

@ -1,27 +1,30 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2019
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 os
from django.core.management.commands import compilemessages

View File

@ -1,29 +1,32 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2017
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 os
import sass
from django.conf import settings
from django.core.management.base import BaseCommand
from django.conf import settings
class Command(BaseCommand):

View File

@ -1,28 +1,33 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2019
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 os
import signal
import sys
from http.server import CGIHTTPRequestHandler, test
import signal
from http.server import test, CGIHTTPRequestHandler
from django.core.management.base import BaseCommand
from django.utils import autoreload

View File

@ -1,68 +0,0 @@
# -*- coding:utf-8 -*
#
# Copyright 2024 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# You can find the source code of the website 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"
#
#
import os
import subprocess
from pathlib import Path
import tomli
from django.core.management.base import BaseCommand, CommandParser
class Command(BaseCommand):
help = "Install xapian"
def add_arguments(self, parser: CommandParser):
parser.add_argument(
"-f",
"--force",
action="store_true",
help="Force installation even if already installed",
)
def _current_version(self) -> str | None:
try:
import xapian
except ImportError:
return None
return xapian.version_string()
def _desired_version(self) -> str:
with open(
Path(__file__).parent.parent.parent.parent / "pyproject.toml", "rb"
) as f:
pyproject = tomli.load(f)
return pyproject["tool"]["xapian"]["version"]
def handle(self, force: bool, *args, **options):
if not os.environ.get("VIRTUAL_ENV", None):
print("No virtual environment detected, this command can't be used")
return
desired = self._desired_version()
if desired == self._current_version():
if not force:
print(
f"Version {desired} is already installed, use --force to re-install"
)
return
print(f"Version {desired} is already installed, re-installing")
print(f"Installing xapian version {desired} at {os.environ['VIRTUAL_ENV']}")
subprocess.run(
[str(Path(__file__).parent / "install_xapian.sh"), desired],
env=dict(os.environ),
).check_returncode()
print("Installation success")

View File

@ -1,47 +0,0 @@
#!/usr/bin/env bash
# Originates from https://gist.github.com/jorgecarleitao/ab6246c86c936b9c55fd
# first argument of the script is Xapian version (e.g. 1.2.19)
VERSION=$1
# Cleanup env vars for auto discovery mechanism
export CPATH=
export LIBRARY_PATH=
export CFLAGS=
export LDFLAGS=
export CCFLAGS=
export CXXFLAGS=
export CPPFLAGS=
# prepare
rm -rf "$VIRTUAL_ENV/packages"
mkdir -p "$VIRTUAL_ENV/packages" && cd "$VIRTUAL_ENV/packages" || exit 1
CORE=xapian-core-$VERSION
BINDINGS=xapian-bindings-$VERSION
# download
echo "Downloading source..."
curl -O "https://oligarchy.co.uk/xapian/$VERSION/${CORE}.tar.xz"
curl -O "https://oligarchy.co.uk/xapian/$VERSION/${BINDINGS}.tar.xz"
# extract
echo "Extracting source..."
tar xf "${CORE}.tar.xz"
tar xf "${BINDINGS}.tar.xz"
# install
echo "Installing Xapian-core..."
cd "$VIRTUAL_ENV/packages/${CORE}" || exit 1
./configure --prefix="$VIRTUAL_ENV" && make && make install
PYTHON_FLAG=--with-python3
echo "Installing Xapian-bindings..."
cd "$VIRTUAL_ENV/packages/${BINDINGS}" || exit 1
./configure --prefix="$VIRTUAL_ENV" $PYTHON_FLAG XAPIAN_CONFIG="$VIRTUAL_ENV/bin/xapian-config" && make && make install
# clean
rm -rf "$VIRTUAL_ENV/packages"
# test
python -c "import xapian"

View File

@ -1,25 +1,28 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2017
# - Skia <skia@libskia.so>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 os
from django.core.management.base import BaseCommand
from core.markdown import markdown

View File

@ -24,37 +24,38 @@
import os
from datetime import date, datetime, timedelta
from io import BytesIO, StringIO
from io import StringIO, BytesIO
from pathlib import Path
from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.sites.models import Site
from django.core.management import call_command
from django.core.management.base import BaseCommand
from django.core.management import call_command
from django.conf import settings
from django.db import connection
from django.contrib.sites.models import Site
from django.utils import timezone
from PIL import Image
from core.models import Group, User, Page, PageRev, SithFile
from accounting.models import (
AccountingType,
GeneralJournal,
BankAccount,
ClubAccount,
Company,
GeneralJournal,
Operation,
AccountingType,
SimplifiedAccountingType,
Company,
)
from club.models import Club, Membership
from com.models import News, NewsDate, Sith, Weekmail
from core.models import Group, Page, PageRev, SithFile, User
from core.utils import resize_image
from counter.models import Counter, Customer, Product, ProductType, Selling, StudentCard
from election.models import Candidature, Election, ElectionList, Role
from club.models import Club, Membership
from subscription.models import Subscription
from counter.models import Customer, ProductType, Product, Counter, Selling, StudentCard
from com.models import Sith, Weekmail, News, NewsDate
from election.models import Election, Role, Candidature, ElectionList
from forum.models import Forum, ForumTopic
from pedagogy.models import UV
from sas.models import Album, PeoplePictureRelation, Picture
from subscription.models import Subscription
from sas.models import Album, Picture, PeoplePictureRelation
class Command(BaseCommand):

View File

@ -23,8 +23,8 @@
#
import os
from django.core.management.base import BaseCommand
from django.core.management import call_command
from core.models import SithFile

View File

@ -1,27 +1,22 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#
import os
from django.core.management import call_command
from django.core.management.base import BaseCommand
from django.core.management import call_command
class Command(BaseCommand):

View File

@ -1,28 +1,23 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#
import os
import re
from mistune import Renderer, InlineGrammar, InlineLexer, Markdown, escape, escape_link
from django.urls import reverse
from mistune import InlineGrammar, InlineLexer, Markdown, Renderer, escape, escape_link
class SithRenderer(Renderer):

View File

@ -1,32 +1,27 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#
import importlib
import threading
from django.conf import settings
from django.utils.functional import SimpleLazyObject
from django.contrib.auth import get_user
from django.contrib.auth.middleware import (
AuthenticationMiddleware as DjangoAuthenticationMiddleware,
)
from django.utils.functional import SimpleLazyObject
module, klass = settings.AUTH_ANONYMOUS_MODEL.rsplit(".", 1)
AnonymousUser = getattr(importlib.import_module(module), klass)

View File

@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.contrib.auth.models
import django.core.validators
import django.db.models.deletion
import django.core.validators
import core.models
import phonenumber_field.modelfields
from django.conf import settings
from django.db import migrations, models
import core.models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.core.validators
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
class Migration(migrations.Migration):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
import django.db.models.deletion
import core.models

View File

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.utils.timezone
from django.db import migrations, models
import django.utils.timezone
import core.models

View File

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.utils.timezone
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.core.validators
class Migration(migrations.Migration):

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.core.validators
class Migration(migrations.Migration):

View File

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
from django.conf import settings
import django.utils.timezone
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django.db.models.deletion
from django.db import migrations, models
import core.models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,8 +1,8 @@
# Generated by Django 2.2.6 on 2019-11-14 15:10
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):

View File

@ -1,56 +1,58 @@
## -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017,2018
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 importlib
import os
import unicodedata
from datetime import date, timedelta
from typing import List, Optional, Union
from typing import Union, Optional, List
from django.conf import settings
from django.core.cache import cache
from django.core.mail import send_mail
from django.contrib.auth.models import (
AbstractBaseUser,
UserManager,
)
from django.contrib.auth.models import (
Group as AuthGroup,
GroupManager as AuthGroupManager,
AnonymousUser as AuthAnonymousUser,
)
from django.contrib.auth.models import (
Group as AuthGroup,
)
from django.contrib.auth.models import (
GroupManager as AuthGroupManager,
)
from django.contrib.staticfiles.storage import staticfiles_storage
from django.core import validators
from django.core.cache import cache
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.mail import send_mail
from django.db import models, transaction
from django.urls import reverse
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django.core import validators
from django.core.exceptions import ValidationError, PermissionDenied
from django.urls import reverse
from django.conf import settings
from django.db import models, transaction
from django.contrib.staticfiles.storage import staticfiles_storage
from django.utils.html import escape
from django.utils.functional import cached_property
import os
from core import utils
from phonenumber_field.modelfields import PhoneNumberField
from core import utils
from datetime import timedelta, date
import unicodedata
class RealGroupManager(AuthGroupManager):
@ -696,11 +698,9 @@ class User(AbstractBaseUser):
<em>%s</em>
</a>
""" % (
(
self.profile_pict.get_download_url()
if self.profile_pict
else staticfiles_storage.url("core/img/unknown.jpg")
),
self.profile_pict.get_download_url()
if self.profile_pict
else staticfiles_storage.url("core/img/unknown.jpg"),
_("Profile"),
escape(self.get_display_name()),
)

View File

@ -1,27 +1,31 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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"
#
"""
This page is useful for custom migration tricks.
Sometimes, when you need to have a migration hack and you think it can be
useful again, put it there, we never know if we might need the hack again.
This page is useful for custom migration tricks.
Sometimes, when you need to have a migration hack and you think it can be
useful again, put it there, we never know if we might need the hack again.
"""
from django.db import connection, migrations

View File

@ -1,27 +1,30 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 os
from collections import OrderedDict
from django.conf import settings
from django.contrib.staticfiles.finders import FileSystemFinder
from django.core.files.storage import FileSystemStorage

View File

@ -1,33 +1,35 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2017
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 os
from urllib.parse import urljoin
import sass
from django.conf import settings
from urllib.parse import urljoin
from django.utils.encoding import force_bytes, iri_to_uri
from django.core.files.base import ContentFile
from django.templatetags.static import static
from django.utils.encoding import force_bytes, iri_to_uri
from django.conf import settings
from core.scss.storage import ScssFileStorage, find_file

View File

@ -1,22 +1,26 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2017
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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

View File

@ -1,24 +1,30 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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
from haystack import indexes, signals
from core.models import User

View File

@ -8,10 +8,10 @@ from core.models import User
@receiver(m2m_changed, sender=User.groups.through, dispatch_uid="user_groups_changed")
def user_groups_changed(sender, instance: User, **kwargs):
"""
Clear the cached groups of the user
Clear the cached clubs of the user
"""
# As a m2m relationship doesn't live within the model
# but rather on an intermediary table, there is no
# model method to override, meaning we must use
# a signal to invalidate the cache when a user is removed from a group
cache.delete(f"user_{instance.pk}_groups")
# a signal to invalidate the cache when a user is removed from a club
cache.delete(f"user_{instance.id}_groups")

View File

@ -1,19 +1,15 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#

View File

@ -1,33 +1,38 @@
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# 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 phonenumbers
from django import template
from django.template.defaultfilters import stringfilter
from django.utils.safestring import mark_safe
from django.utils.translation import ngettext
from core.scss.processor import ScssProcessor
from core.markdown import markdown as md
from core.scss.processor import ScssProcessor
register = template.Library()

View File

@ -1,6 +1,6 @@
from django.template.exceptions import TemplateSyntaxError
from django import template
from django.template.defaultfilters import stringfilter
from django.template.exceptions import TemplateSyntaxError
register = template.Library()

View File

@ -1,33 +1,27 @@
# -*- coding:utf-8 -*-
# -*- 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
# You can find the source code of the website 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"
#
import os
from datetime import date, timedelta
import freezegun
import pytest
from django.core.cache import cache
from django.test import TestCase
from django.test import Client, TestCase
from django.urls import reverse
from django.utils.timezone import now
from pytest_django.asserts import assertRedirects
from club.models import Membership
from core.markdown import markdown
@ -35,105 +29,270 @@ from core.models import AnonymousUser, Group, Page, User
from core.utils import get_semester_code, get_start_of_semester
from sith import settings
@pytest.mark.django_db
class TestUserRegistration:
@pytest.fixture()
def valid_payload(self):
return {
"first_name": "this user does not exist (yet)",
"last_name": "this user does not exist (yet)",
"email": "i-dont-exist-yet@git.an",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
}
def test_register_user_form_ok(self, client, valid_payload):
"""Should register a user correctly."""
response = client.post(reverse("core:register"), valid_payload)
assert response.status_code == 200
assert "TEST_REGISTER_USER_FORM_OK" in str(response.content)
@pytest.mark.parametrize(
"payload_edit",
[
{"password2": "not the same as password1"},
{"email": "not-an-email"},
{"first_name": ""},
{"last_name": ""},
{"captcha_1": "WRONG_CAPTCHA"},
],
)
def test_register_user_form_fail(self, client, valid_payload, payload_edit):
"""Should not register a user correctly."""
payload = valid_payload | payload_edit
response = client.post(reverse("core:register"), payload)
assert response.status_code == 200
assert "TEST_REGISTER_USER_FORM_FAIL" in str(response.content)
def test_register_user_form_fail_already_exists(self, client, valid_payload):
"""Should not register a user correctly if it already exists."""
# create the user, then try to create it again
client.post(reverse("core:register"), valid_payload)
response = client.post(reverse("core:register"), valid_payload)
assert response.status_code == 200
assert "TEST_REGISTER_USER_FORM_FAIL" in str(response.content)
"""
to run these tests :
python3 manage.py test
"""
@pytest.mark.django_db
class TestUserLogin:
@pytest.fixture()
def user(self) -> User:
return User.objects.first()
class UserRegistrationTest(TestCase):
@classmethod
def setUpTestData(cls):
User.objects.all().delete()
def test_login_fail(self, client, user):
def test_register_user_form_ok(self):
"""
Should not login a user correctly
Should register a user correctly
"""
response = client.post(
reverse("core:login"),
{"username": user.username, "password": "wrong-password"},
c = Client()
response = c.post(
reverse("core:register"),
{
"first_name": "Guy",
"last_name": "Carlier",
"email": "guy@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
assert response.status_code == 200
assert (
'<p class="alert alert-red">Votre nom d\'utilisateur '
"et votre mot de passe ne correspondent pas. Merci de réessayer.</p>"
) in str(response.content.decode())
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_OK" in str(response.content))
def test_login_success(self, client, user):
def test_register_user_form_fail_password(self):
"""
Should not register a user correctly
"""
c = Client()
response = c.post(
reverse("core:register"),
{
"first_name": "Guy",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop2",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
def test_register_user_form_fail_email(self):
"""
Should not register a user correctly
"""
c = Client()
response = c.post(
reverse("core:register"),
{
"first_name": "Guy",
"last_name": "Carlier",
"email": "bibou.git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
def test_register_user_form_fail_missing_name(self):
"""
Should not register a user correctly
"""
c = Client()
response = c.post(
reverse("core:register"),
{
"first_name": "Guy",
"last_name": "",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
def test_register_user_form_fail_missing_date_of_birth(self):
"""
Should not register a user correctly
"""
c = Client()
response = c.post(
reverse("core:register"),
{
"first_name": "",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
def test_register_user_form_fail_missing_first_name(self):
"""
Should not register a user correctly
"""
c = Client()
response = c.post(
reverse("core:register"),
{
"first_name": "",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
def test_register_user_form_fail_wrong_captcha(self):
"""
Should not register a user correctly
"""
c = Client()
response = c.post(
reverse("core:register"),
{
"first_name": "Bibou",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "WRONG_CAPTCHA",
},
)
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
def test_register_user_form_fail_already_exists(self):
"""
Should not register a user correctly
"""
c = Client()
c.post(
reverse("core:register"),
{
"first_name": "Guy",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
response = c.post(
reverse("core:register"),
{
"first_name": "Bibou",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
self.assertTrue(response.status_code == 200)
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
def test_login_success(self):
"""
Should login a user correctly
"""
response = client.post(
reverse("core:login"), {"username": user.username, "password": "plop"}
c = Client()
c.post(
reverse("core:register"),
{
"first_name": "Guy",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
response = c.post(
reverse("core:login"), {"username": "gcarlier", "password": "plop"}
)
self.assertTrue(response.status_code == 302)
# self.assertTrue('Hello, world' in str(response.content))
def test_login_fail(self):
"""
Should not login a user correctly
"""
c = Client()
c.post(
reverse("core:register"),
{
"first_name": "Guy",
"last_name": "Carlier",
"email": "bibou@git.an",
"date_of_birth": "12/6/1942",
"password1": "plop",
"password2": "plop",
"captcha_0": "dummy-value",
"captcha_1": "PASSED",
},
)
response = c.post(
reverse("core:login"), {"username": "gcarlier", "password": "guy"}
)
self.assertTrue(response.status_code == 200)
self.assertTrue(
"""<p class="alert alert-red">Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>"""
in str(response.content)
)
assertRedirects(response, reverse("core:index"))
def test_full_markdown_syntax():
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md_file:
md = md_file.read()
with open(os.path.join(root_path) + "/doc/SYNTAX.html", "r") as html_file:
html = html_file.read()
result = markdown(md)
assert result == html
class MarkdownTest(TestCase):
def test_full_markdown_syntax(self):
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md_file:
md = md_file.read()
with open(os.path.join(root_path) + "/doc/SYNTAX.html", "r") as html_file:
html = html_file.read()
result = markdown(md)
self.assertTrue(result == html)
class PageHandlingTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.root = User.objects.get(username="root")
cls.root_group = Group.objects.get(name="Root")
def setUp(self):
self.client.force_login(self.root)
self.client.login(username="root", password="plop")
self.root_group = Group.objects.get(name="Root")
def test_create_page_ok(self):
"""Should create a page correctly."""
"""
Should create a page correctly
"""
response = self.client.post(
reverse("core:page_new"),
@ -142,17 +301,19 @@ class PageHandlingTest(TestCase):
self.assertRedirects(
response, reverse("core:page", kwargs={"page_name": "guy"})
)
assert Page.objects.filter(name="guy").exists()
self.assertTrue(Page.objects.filter(name="guy").exists())
response = self.client.get(reverse("core:page", kwargs={"page_name": "guy"}))
assert response.status_code == 200
self.assertEqual(response.status_code, 200)
html = response.content.decode()
assert '<a href="/page/guy/hist/">' in html
assert '<a href="/page/guy/edit/">' in html
assert '<a href="/page/guy/prop/">' in html
self.assertIn('<a href="/page/guy/hist/">', html)
self.assertIn('<a href="/page/guy/edit/">', html)
self.assertIn('<a href="/page/guy/prop/">', html)
def test_create_child_page_ok(self):
"""Should create a page correctly."""
"""
Should create a page correctly
"""
# remove all other pages to make sure there is no side effect
Page.objects.all().delete()
self.client.post(
@ -160,7 +321,7 @@ class PageHandlingTest(TestCase):
{"parent": "", "name": "guy", "owner_group": str(self.root_group.id)},
)
page = Page.objects.first()
self.client.post(
response = self.client.post(
reverse("core:page_new"),
{
"parent": str(page.id),
@ -171,8 +332,8 @@ class PageHandlingTest(TestCase):
response = self.client.get(
reverse("core:page", kwargs={"page_name": "guy/bibou"})
)
assert response.status_code == 200
assert '<a href="/page/guy/bibou/">' in str(response.content)
self.assertTrue(response.status_code == 200)
self.assertTrue('<a href="/page/guy/bibou/">' in str(response.content))
def test_access_child_page_ok(self):
"""
@ -185,7 +346,7 @@ class PageHandlingTest(TestCase):
response = self.client.get(
reverse("core:page", kwargs={"page_name": "guy/bibou"})
)
assert response.status_code == 200
self.assertTrue(response.status_code == 200)
html = response.content.decode()
self.assertIn('<a href="/page/guy/bibou/edit/">', html)
@ -194,7 +355,7 @@ class PageHandlingTest(TestCase):
Should not display a page correctly
"""
response = self.client.get(reverse("core:page", kwargs={"page_name": "swagg"}))
assert response.status_code == 200
self.assertTrue(response.status_code == 200)
html = response.content.decode()
self.assertIn('<a href="/page/create/?page=swagg">', html)
@ -222,8 +383,8 @@ http://git.an
},
)
response = self.client.get(reverse("core:page", kwargs={"page_name": "guy"}))
assert response.status_code == 200
assert (
self.assertTrue(response.status_code == 200)
self.assertTrue(
'<p>Guy <em>bibou</em></p>\\n<p><a href="http://git.an">http://git.an</a></p>\\n'
+ "<h1>Swag</h1>\\n&lt;guy&gt;Bibou&lt;/guy&gt;"
+ "&lt;script&gt;alert(\\'Guy\\');&lt;/script&gt;"
@ -231,19 +392,35 @@ http://git.an
)
class UserToolsTest:
def test_anonymous_user_unauthorized(self, client):
"""An anonymous user shouldn't have access to the tools page"""
response = client.get(reverse("core:user_tools"))
assert response.status_code == 403
class UserToolsTest(TestCase):
def test_anonymous_user_unauthorized(self):
response = self.client.get(reverse("core:user_tools"))
self.assertEqual(response.status_code, 403)
@pytest.mark.parametrize("username", ["guy", "root", "skia", "comunity"])
def test_page_is_working(self, client, username):
"""All existing users should be able to see the test page"""
def test_page_is_working(self):
# Test for simple user
client.force_login(User.objects.get(username=username))
response = client.get(reverse("core:user_tools"))
assert response.status_code == 200
self.client.login(username="guy", password="plop")
response = self.client.get(reverse("core:user_tools"))
self.assertNotEqual(response.status_code, 500)
self.assertEqual(response.status_code, 200)
# Test for root
self.client.login(username="root", password="plop")
response = self.client.get(reverse("core:user_tools"))
self.assertNotEqual(response.status_code, 500)
self.assertEqual(response.status_code, 200)
# Test for skia
self.client.login(username="skia", password="plop")
response = self.client.get(reverse("core:user_tools"))
self.assertNotEqual(response.status_code, 500)
self.assertEqual(response.status_code, 200)
# Test for comunity
self.client.login(username="comunity", password="plop")
response = self.client.get(reverse("core:user_tools"))
self.assertNotEqual(response.status_code, 500)
self.assertEqual(response.status_code, 200)
# TODO: many tests on the pages:
@ -265,12 +442,12 @@ class FileHandlingTest(TestCase):
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}),
{"folder_name": "GUY_folder_test"},
)
assert response.status_code == 302
self.assertTrue(response.status_code == 302)
response = self.client.get(
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id})
)
assert response.status_code == 200
assert "GUY_folder_test</a>" in str(response.content)
self.assertTrue(response.status_code == 200)
self.assertTrue("GUY_folder_test</a>" in str(response.content))
def test_upload_file_home(self):
with open("/bin/ls", "rb") as f:
@ -280,12 +457,12 @@ class FileHandlingTest(TestCase):
),
{"file_field": f},
)
assert response.status_code == 302
self.assertTrue(response.status_code == 302)
response = self.client.get(
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id})
)
assert response.status_code == 200
assert "ls</a>" in str(response.content)
self.assertTrue(response.status_code == 200)
self.assertTrue("ls</a>" in str(response.content))
class UserIsInGroupTest(TestCase):
@ -300,10 +477,6 @@ class UserIsInGroupTest(TestCase):
cls.root_group = Group.objects.get(name="Root")
cls.public = Group.objects.get(name="Public")
cls.skia = User.objects.get(username="skia")
cls.toto = User.objects.create(
username="toto", first_name="a", last_name="b", email="a.b@toto.fr"
)
cls.subscribers = Group.objects.get(name="Subscribers")
cls.old_subscribers = Group.objects.get(name="Old subscribers")
cls.accounting_admin = Group.objects.get(name="Accounting admin")
@ -320,15 +493,21 @@ class UserIsInGroupTest(TestCase):
)
cls.main_club = Club.objects.get(id=1)
def setUp(self) -> None:
self.toto = User.objects.create(
username="toto", first_name="a", last_name="b", email="a.b@toto.fr"
)
self.skia = User.objects.get(username="skia")
def assert_in_public_group(self, user):
assert user.is_in_group(pk=self.public.id)
assert user.is_in_group(name=self.public.name)
self.assertTrue(user.is_in_group(pk=self.public.id))
self.assertTrue(user.is_in_group(name=self.public.name))
def assert_in_club_metagroups(self, user, club):
meta_groups_board = club.unix_name + settings.SITH_BOARD_SUFFIX
meta_groups_members = club.unix_name + settings.SITH_MEMBER_SUFFIX
assert user.is_in_group(name=meta_groups_board) is False
assert user.is_in_group(name=meta_groups_members) is False
self.assertFalse(user.is_in_group(name=meta_groups_board))
self.assertFalse(user.is_in_group(name=meta_groups_members))
def assert_only_in_public_group(self, user):
self.assert_in_public_group(user)
@ -340,12 +519,12 @@ class UserIsInGroupTest(TestCase):
self.subscribers,
self.old_subscribers,
):
assert not user.is_in_group(pk=group.pk)
assert not user.is_in_group(name=group.name)
self.assertFalse(user.is_in_group(pk=group.pk))
self.assertFalse(user.is_in_group(name=group.name))
meta_groups_board = self.club.unix_name + settings.SITH_BOARD_SUFFIX
meta_groups_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
assert user.is_in_group(name=meta_groups_board) is False
assert user.is_in_group(name=meta_groups_members) is False
self.assertFalse(user.is_in_group(name=meta_groups_board))
self.assertFalse(user.is_in_group(name=meta_groups_members))
def test_anonymous_user(self):
"""
@ -404,13 +583,15 @@ class UserIsInGroupTest(TestCase):
)
meta_groups_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
cache.clear()
assert self.toto.is_in_group(name=meta_groups_members) is True
assert membership == cache.get(f"membership_{self.club.id}_{self.toto.id}")
self.assertTrue(self.toto.is_in_group(name=meta_groups_members))
self.assertEqual(
membership, cache.get(f"membership_{self.club.id}_{self.toto.id}")
)
membership.end_date = now() - timedelta(minutes=5)
membership.save()
cached_membership = cache.get(f"membership_{self.club.id}_{self.toto.id}")
assert cached_membership == "not_member"
assert self.toto.is_in_group(name=meta_groups_members) is False
self.assertEqual(cached_membership, "not_member")
self.assertFalse(self.toto.is_in_group(name=meta_groups_members))
def test_cache_properly_cleared_group(self):
"""
@ -419,24 +600,24 @@ class UserIsInGroupTest(TestCase):
"""
# testing with pk
self.toto.groups.add(self.com_admin.pk)
assert self.toto.is_in_group(pk=self.com_admin.pk) is True
self.assertTrue(self.toto.is_in_group(pk=self.com_admin.pk))
self.toto.groups.remove(self.com_admin.pk)
assert self.toto.is_in_group(pk=self.com_admin.pk) is False
self.assertFalse(self.toto.is_in_group(pk=self.com_admin.pk))
# testing with name
self.toto.groups.add(self.sas_admin.pk)
assert self.toto.is_in_group(name="SAS admin") is True
self.assertTrue(self.toto.is_in_group(name="SAS admin"))
self.toto.groups.remove(self.sas_admin.pk)
assert self.toto.is_in_group(name="SAS admin") is False
self.assertFalse(self.toto.is_in_group(name="SAS admin"))
def test_not_existing_group(self):
"""
Test that searching for a not existing group
returns False
"""
assert self.skia.is_in_group(name="This doesn't exist") is False
self.assertFalse(self.skia.is_in_group(name="This doesn't exist"))
class DateUtilsTest(TestCase):
@ -458,25 +639,29 @@ class DateUtilsTest(TestCase):
"""
Test that the get_semester function returns the correct semester string
"""
assert get_semester_code(self.autumn_semester_january) == "A24"
assert get_semester_code(self.autumn_semester_september) == "A24"
assert get_semester_code(self.autumn_first_day) == "A24"
self.assertEqual(get_semester_code(self.autumn_semester_january), "A24")
self.assertEqual(get_semester_code(self.autumn_semester_september), "A24")
self.assertEqual(get_semester_code(self.autumn_first_day), "A24")
assert get_semester_code(self.spring_semester_march) == "P23"
assert get_semester_code(self.spring_first_day) == "P23"
self.assertEqual(get_semester_code(self.spring_semester_march), "P23")
self.assertEqual(get_semester_code(self.spring_first_day), "P23")
def test_get_start_of_semester_fixed_date(self):
"""
Test that the get_start_of_semester correctly the starting date of the semester.
"""
automn_2024 = date(2024, self.autumn_month, self.autumn_day)
assert get_start_of_semester(self.autumn_semester_january) == automn_2024
assert get_start_of_semester(self.autumn_semester_september) == automn_2024
assert get_start_of_semester(self.autumn_first_day) == automn_2024
self.assertEqual(
get_start_of_semester(self.autumn_semester_january), automn_2024
)
self.assertEqual(
get_start_of_semester(self.autumn_semester_september), automn_2024
)
self.assertEqual(get_start_of_semester(self.autumn_first_day), automn_2024)
spring_2023 = date(2023, self.spring_month, self.spring_day)
assert get_start_of_semester(self.spring_semester_march) == spring_2023
assert get_start_of_semester(self.spring_first_day) == spring_2023
self.assertEqual(get_start_of_semester(self.spring_semester_march), spring_2023)
self.assertEqual(get_start_of_semester(self.spring_first_day), spring_2023)
def test_get_start_of_semester_today(self):
"""
@ -484,10 +669,10 @@ class DateUtilsTest(TestCase):
when no date is given
"""
with freezegun.freeze_time(self.autumn_semester_september):
assert get_start_of_semester() == self.autumn_first_day
self.assertEqual(get_start_of_semester(), self.autumn_first_day)
with freezegun.freeze_time(self.spring_semester_march):
assert get_start_of_semester() == self.spring_first_day
self.assertEqual(get_start_of_semester(), self.spring_first_day)
def test_get_start_of_semester_changing_date(self):
"""
@ -500,8 +685,8 @@ class DateUtilsTest(TestCase):
mid_autumn = autumn_2023 + timedelta(days=45)
with freezegun.freeze_time(mid_spring) as frozen_time:
assert get_start_of_semester() == spring_2023
self.assertEqual(get_start_of_semester(), spring_2023)
# forward time to the middle of the next semester
frozen_time.move_to(mid_autumn)
assert get_start_of_semester() == autumn_2023
self.assertEqual(get_start_of_semester(), autumn_2023)

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