mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-26 11:04:20 +00:00
Merge branch 'black' into 'master'
Passer black sur tout le repo et l'imposer See merge request ae/Sith!159
This commit is contained in:
commit
a88430d43b
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@ db.sqlite3
|
|||||||
*.mo
|
*.mo
|
||||||
*__pycache__*
|
*__pycache__*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.vscode/
|
||||||
env/
|
env/
|
||||||
doc/html
|
doc/html
|
||||||
data/
|
data/
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
|
stages:
|
||||||
|
- test
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
stage: test
|
||||||
script:
|
script:
|
||||||
- apt-get update
|
- apt-get update
|
||||||
- apt-get install -y gettext
|
- apt-get install -y gettext
|
||||||
@ -11,3 +15,9 @@ test:
|
|||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- coverage_report/
|
- coverage_report/
|
||||||
|
|
||||||
|
black:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- pip install black
|
||||||
|
- black --check .
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
Hey ! Tu veux devenir un mec bien et en plus devenir bon en python si tu l'es pas déjà ?
|
Hey ! Tu veux devenir un mec bien et en plus devenir bon en python si tu l'es pas déjà ?
|
||||||
Il se trouve que le sith AE prévu pour l'été 2016 a besoin de toi !
|
Il se trouve que le sith AE prévu pour l'été 2016 a besoin de toi !
|
||||||
|
|
||||||
Pour faire le sith, on utilise le framework Web [Django](https://docs.djangoproject.com/fr/1.8/intro/)
|
Pour faire le sith, on utilise le framework Web [Django](https://docs.djangoproject.com/fr/1.11/intro/)
|
||||||
N'hésite pas à lire les tutos et à nous demander (ae.info@utbm.fr).
|
N'hésite pas à lire les tutos et à nous demander (ae.info@utbm.fr).
|
||||||
|
|
||||||
Bon, passons aux choses sérieuses, pour bidouiller le sith sans le casser :
|
Bon, passons aux choses sérieuses, pour bidouiller le sith sans le casser :
|
||||||
@ -17,31 +17,81 @@ Ensuite, tu fais :
|
|||||||
`git clone https://ae-dev.utbm.fr/ae/Sith.git`
|
`git clone https://ae-dev.utbm.fr/ae/Sith.git`
|
||||||
Avec cette commande, tu clones le sith AE dans le dossier courant.
|
Avec cette commande, tu clones le sith AE dans le dossier courant.
|
||||||
|
|
||||||
|
```bash
|
||||||
cd Sith
|
cd Sith
|
||||||
virtualenv --clear --python=python3 env_sith
|
virtualenv --clear --python=python3 env_sith
|
||||||
source env_sith/bin/activate
|
source env_sith/bin/activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
Maintenant, faut passer le sith en mode debug dans le fichier de settings personnalisé.
|
Maintenant, faut passer le sith en mode debug dans le fichier de settings personnalisé.
|
||||||
|
|
||||||
|
```bash
|
||||||
echo "DEBUG=True" > sith/settings_custom.py
|
echo "DEBUG=True" > sith/settings_custom.py
|
||||||
echo 'EXTERNAL_RES = "False"' >> sith/settings_custom.py
|
echo 'EXTERNAL_RES = "False"' >> sith/settings_custom.py
|
||||||
echo 'SITH_URL = "localhost:8000"' >> sith/settings_custom.py
|
echo 'SITH_URL = "localhost:8000"' >> sith/settings_custom.py
|
||||||
|
```
|
||||||
|
|
||||||
Enfin, il s'agit de créer la base de donnée de test lors de la première utilisation
|
Enfin, il s'agit de créer la base de donnée de test lors de la première utilisation
|
||||||
|
|
||||||
|
```bash
|
||||||
./manage.py setup
|
./manage.py setup
|
||||||
répondre no
|
```
|
||||||
|
|
||||||
Et pour lancer le sith, tu fais `python3 manage.py runserver`
|
Et pour lancer le sith, tu fais `python3 manage.py runserver`
|
||||||
|
|
||||||
Voilà, c'est le sith AE. Il y a des issues dans le gitlab qui sont à régler. Si tu as un domaine qui t'intéresse, une appli que tu voudrais développer, n'hésites pas et contacte-nous.
|
Voilà, c'est le sith AE. Il y a des issues dans le gitlab qui sont à régler. Si tu as un domaine qui t'intéresse, une appli que tu voudrais développer, n'hésites pas et contacte-nous.
|
||||||
Va, et que l'AE soit avec toi.
|
Va, et que l'AE soit avec toi.
|
||||||
|
|
||||||
|
# Black
|
||||||
|
|
||||||
|
Pour uniformiser le formattage du code nous utilisons [Black](https://github.com/ambv/black). Cela permet d'avoir le même codestyle et donc le codereview prend moins de temps. Tout étant dans le même format, il est plus facile pour chacun de comprendre le code de chacun ! Cela permet aussi d'éviter des erreurs (y parait 🤷♀️).
|
||||||
|
|
||||||
|
Installation de black:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install black
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sous VsCode:
|
||||||
|
Attention, pour VsCode, Black doit être installé dans votre virtualenv !
|
||||||
|
Ajouter ces deux lignes dans les settings de VsCode
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"python.formatting.provider": "black",
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sous Sublime Text
|
||||||
|
Il faut installer le plugin [sublack](https://packagecontrol.io/packages/sublack) depuis Package Control.
|
||||||
|
|
||||||
|
Il suffit ensuite d'ajouter dans les settings du projet (ou en global)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sublack.black_on_save": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Si vous utilisez le plugin [anaconda](http://damnwidget.github.io/anaconda/), pensez à modifier les paramètres du linter pep8 pour éviter de recevoir des warnings dans le formatage de black
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pep8_ignore": [
|
||||||
|
"E203",
|
||||||
|
"E266",
|
||||||
|
"E501",
|
||||||
|
"W503"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Sites et doc cools
|
Sites et doc cools
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
[Classy Class-Based Views](http://ccbv.co.uk/projects/Django/1.8/)
|
[Classy Class-Based Views](http://ccbv.co.uk/projects/Django/1.11/)
|
||||||
|
|
||||||
Helpers:
|
Helpers:
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
[![pipeline status](https://ae-dev.utbm.fr/ae/Sith/badges/master/pipeline.svg)](https://ae-dev.utbm.fr/ae/Sith/commits/master)
|
[![pipeline status](https://ae-dev.utbm.fr/ae/Sith/badges/master/pipeline.svg)](https://ae-dev.utbm.fr/ae/Sith/commits/master)
|
||||||
[![coverage report](https://ae-dev.utbm.fr/ae/Sith/badges/master/coverage.svg)](https://ae-dev.utbm.fr/ae/Sith/commits/master)
|
[![coverage report](https://ae-dev.utbm.fr/ae/Sith/badges/master/coverage.svg)](https://ae-dev.utbm.fr/ae/Sith/commits/master)
|
||||||
|
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
|
||||||
|
|
||||||
## Sith AE
|
## Sith AE
|
||||||
|
|
||||||
|
@ -21,4 +21,3 @@
|
|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -8,103 +8,271 @@ import accounting.models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = []
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='AccountingType',
|
name="AccountingType",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('code', models.CharField(max_length=16, verbose_name='code', validators=[django.core.validators.RegexValidator('^[0-9]*$', 'An accounting type code contains only numbers')])),
|
"id",
|
||||||
('label', models.CharField(max_length=128, verbose_name='label')),
|
models.AutoField(
|
||||||
('movement_type', models.CharField(choices=[('CREDIT', 'Credit'), ('DEBIT', 'Debit'), ('NEUTRAL', 'Neutral')], max_length=12, verbose_name='movement type')),
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"code",
|
||||||
|
models.CharField(
|
||||||
|
max_length=16,
|
||||||
|
verbose_name="code",
|
||||||
|
validators=[
|
||||||
|
django.core.validators.RegexValidator(
|
||||||
|
"^[0-9]*$",
|
||||||
|
"An accounting type code contains only numbers",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("label", models.CharField(max_length=128, verbose_name="label")),
|
||||||
|
(
|
||||||
|
"movement_type",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("CREDIT", "Credit"),
|
||||||
|
("DEBIT", "Debit"),
|
||||||
|
("NEUTRAL", "Neutral"),
|
||||||
|
],
|
||||||
|
max_length=12,
|
||||||
|
verbose_name="movement type",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'accounting type',
|
"verbose_name": "accounting type",
|
||||||
'ordering': ['movement_type', 'code'],
|
"ordering": ["movement_type", "code"],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='BankAccount',
|
name="BankAccount",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('name', models.CharField(max_length=30, verbose_name='name')),
|
"id",
|
||||||
('iban', models.CharField(max_length=255, blank=True, verbose_name='iban')),
|
models.AutoField(
|
||||||
('number', models.CharField(max_length=255, blank=True, verbose_name='account number')),
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=30, verbose_name="name")),
|
||||||
|
(
|
||||||
|
"iban",
|
||||||
|
models.CharField(max_length=255, blank=True, verbose_name="iban"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"number",
|
||||||
|
models.CharField(
|
||||||
|
max_length=255, blank=True, verbose_name="account number"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={"verbose_name": "Bank account", "ordering": ["club", "name"]},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="ClubAccount",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=30, verbose_name="name")),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Bank account',
|
"verbose_name": "Club account",
|
||||||
'ordering': ['club', 'name'],
|
"ordering": ["bank_account", "name"],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ClubAccount',
|
name="Company",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('name', models.CharField(max_length=30, verbose_name='name')),
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=60, verbose_name="name")),
|
||||||
],
|
],
|
||||||
options={
|
options={"verbose_name": "company"},
|
||||||
'verbose_name': 'Club account',
|
|
||||||
'ordering': ['bank_account', 'name'],
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Company',
|
name="GeneralJournal",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('name', models.CharField(max_length=60, verbose_name='name')),
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("start_date", models.DateField(verbose_name="start date")),
|
||||||
|
(
|
||||||
|
"end_date",
|
||||||
|
models.DateField(
|
||||||
|
null=True, verbose_name="end date", default=None, blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=40, verbose_name="name")),
|
||||||
|
(
|
||||||
|
"closed",
|
||||||
|
models.BooleanField(verbose_name="is closed", default=False),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"amount",
|
||||||
|
accounting.models.CurrencyField(
|
||||||
|
decimal_places=2,
|
||||||
|
default=0,
|
||||||
|
verbose_name="amount",
|
||||||
|
max_digits=12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"effective_amount",
|
||||||
|
accounting.models.CurrencyField(
|
||||||
|
decimal_places=2,
|
||||||
|
default=0,
|
||||||
|
verbose_name="effective_amount",
|
||||||
|
max_digits=12,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={"verbose_name": "General journal", "ordering": ["-start_date"]},
|
||||||
'verbose_name': 'company',
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='GeneralJournal',
|
name="Operation",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('start_date', models.DateField(verbose_name='start date')),
|
"id",
|
||||||
('end_date', models.DateField(null=True, verbose_name='end date', default=None, blank=True)),
|
models.AutoField(
|
||||||
('name', models.CharField(max_length=40, verbose_name='name')),
|
primary_key=True,
|
||||||
('closed', models.BooleanField(verbose_name='is closed', default=False)),
|
serialize=False,
|
||||||
('amount', accounting.models.CurrencyField(decimal_places=2, default=0, verbose_name='amount', max_digits=12)),
|
verbose_name="ID",
|
||||||
('effective_amount', accounting.models.CurrencyField(decimal_places=2, default=0, verbose_name='effective_amount', max_digits=12)),
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("number", models.IntegerField(verbose_name="number")),
|
||||||
|
(
|
||||||
|
"amount",
|
||||||
|
accounting.models.CurrencyField(
|
||||||
|
decimal_places=2, max_digits=12, verbose_name="amount"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("date", models.DateField(verbose_name="date")),
|
||||||
|
("remark", models.CharField(max_length=128, verbose_name="comment")),
|
||||||
|
(
|
||||||
|
"mode",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("CHECK", "Check"),
|
||||||
|
("CASH", "Cash"),
|
||||||
|
("TRANSFERT", "Transfert"),
|
||||||
|
("CARD", "Credit card"),
|
||||||
],
|
],
|
||||||
options={
|
max_length=255,
|
||||||
'verbose_name': 'General journal',
|
verbose_name="payment method",
|
||||||
'ordering': ['-start_date'],
|
),
|
||||||
},
|
),
|
||||||
|
(
|
||||||
|
"cheque_number",
|
||||||
|
models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
null=True,
|
||||||
|
verbose_name="cheque number",
|
||||||
|
default="",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("done", models.BooleanField(verbose_name="is done", default=False)),
|
||||||
|
(
|
||||||
|
"target_type",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("USER", "User"),
|
||||||
|
("CLUB", "Club"),
|
||||||
|
("ACCOUNT", "Account"),
|
||||||
|
("COMPANY", "Company"),
|
||||||
|
("OTHER", "Other"),
|
||||||
|
],
|
||||||
|
max_length=10,
|
||||||
|
verbose_name="target type",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"target_id",
|
||||||
|
models.IntegerField(
|
||||||
|
null=True, verbose_name="target id", blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"target_label",
|
||||||
|
models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="target label",
|
||||||
|
default="",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"accounting_type",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
related_name="operations",
|
||||||
|
verbose_name="accounting type",
|
||||||
|
to="accounting.AccountingType",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={"ordering": ["-number"]},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Operation',
|
name="SimplifiedAccountingType",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('number', models.IntegerField(verbose_name='number')),
|
"id",
|
||||||
('amount', accounting.models.CurrencyField(decimal_places=2, max_digits=12, verbose_name='amount')),
|
models.AutoField(
|
||||||
('date', models.DateField(verbose_name='date')),
|
primary_key=True,
|
||||||
('remark', models.CharField(max_length=128, verbose_name='comment')),
|
serialize=False,
|
||||||
('mode', models.CharField(choices=[('CHECK', 'Check'), ('CASH', 'Cash'), ('TRANSFERT', 'Transfert'), ('CARD', 'Credit card')], max_length=255, verbose_name='payment method')),
|
verbose_name="ID",
|
||||||
('cheque_number', models.CharField(max_length=32, null=True, verbose_name='cheque number', default='', blank=True)),
|
auto_created=True,
|
||||||
('done', models.BooleanField(verbose_name='is done', default=False)),
|
),
|
||||||
('target_type', models.CharField(choices=[('USER', 'User'), ('CLUB', 'Club'), ('ACCOUNT', 'Account'), ('COMPANY', 'Company'), ('OTHER', 'Other')], max_length=10, verbose_name='target type')),
|
),
|
||||||
('target_id', models.IntegerField(null=True, verbose_name='target id', blank=True)),
|
("label", models.CharField(max_length=128, verbose_name="label")),
|
||||||
('target_label', models.CharField(max_length=32, blank=True, verbose_name='target label', default='')),
|
(
|
||||||
('accounting_type', models.ForeignKey(null=True, related_name='operations', verbose_name='accounting type', to='accounting.AccountingType', blank=True)),
|
"accounting_type",
|
||||||
],
|
models.ForeignKey(
|
||||||
options={
|
verbose_name="simplified accounting types",
|
||||||
'ordering': ['-number'],
|
to="accounting.AccountingType",
|
||||||
},
|
related_name="simplified_types",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name='SimplifiedAccountingType',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
|
||||||
('label', models.CharField(max_length=128, verbose_name='label')),
|
|
||||||
('accounting_type', models.ForeignKey(verbose_name='simplified accounting types', to='accounting.AccountingType', related_name='simplified_types')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'simplified type',
|
"verbose_name": "simplified type",
|
||||||
'ordering': ['accounting_type__movement_type', 'accounting_type__code'],
|
"ordering": ["accounting_type__movement_type", "accounting_type__code"],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -7,54 +7,88 @@ from django.db import migrations, models
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('club', '0001_initial'),
|
("club", "0001_initial"),
|
||||||
('accounting', '0001_initial'),
|
("accounting", "0001_initial"),
|
||||||
('core', '0001_initial'),
|
("core", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='operation',
|
model_name="operation",
|
||||||
name='invoice',
|
name="invoice",
|
||||||
field=models.ForeignKey(null=True, related_name='operations', verbose_name='invoice', to='core.SithFile', blank=True),
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
related_name="operations",
|
||||||
|
verbose_name="invoice",
|
||||||
|
to="core.SithFile",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='operation',
|
model_name="operation",
|
||||||
name='journal',
|
name="journal",
|
||||||
field=models.ForeignKey(verbose_name='journal', to='accounting.GeneralJournal', related_name='operations'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="journal",
|
||||||
|
to="accounting.GeneralJournal",
|
||||||
|
related_name="operations",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='operation',
|
model_name="operation",
|
||||||
name='linked_operation',
|
name="linked_operation",
|
||||||
field=models.OneToOneField(blank=True, to='accounting.Operation', null=True, related_name='operation_linked_to', verbose_name='linked operation', default=None),
|
field=models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
to="accounting.Operation",
|
||||||
|
null=True,
|
||||||
|
related_name="operation_linked_to",
|
||||||
|
verbose_name="linked operation",
|
||||||
|
default=None,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='operation',
|
model_name="operation",
|
||||||
name='simpleaccounting_type',
|
name="simpleaccounting_type",
|
||||||
field=models.ForeignKey(null=True, related_name='operations', verbose_name='simple type', to='accounting.SimplifiedAccountingType', blank=True),
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
related_name="operations",
|
||||||
|
verbose_name="simple type",
|
||||||
|
to="accounting.SimplifiedAccountingType",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='generaljournal',
|
model_name="generaljournal",
|
||||||
name='club_account',
|
name="club_account",
|
||||||
field=models.ForeignKey(verbose_name='club account', to='accounting.ClubAccount', related_name='journals'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="club account",
|
||||||
|
to="accounting.ClubAccount",
|
||||||
|
related_name="journals",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='clubaccount',
|
model_name="clubaccount",
|
||||||
name='bank_account',
|
name="bank_account",
|
||||||
field=models.ForeignKey(verbose_name='bank account', to='accounting.BankAccount', related_name='club_accounts'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="bank account",
|
||||||
|
to="accounting.BankAccount",
|
||||||
|
related_name="club_accounts",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='clubaccount',
|
model_name="clubaccount",
|
||||||
name='club',
|
name="club",
|
||||||
field=models.ForeignKey(verbose_name='club', to='club.Club', related_name='club_account'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="club", to="club.Club", related_name="club_account"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='bankaccount',
|
model_name="bankaccount",
|
||||||
name='club',
|
name="club",
|
||||||
field=models.ForeignKey(verbose_name='club', to='club.Club', related_name='bank_accounts'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="club", to="club.Club", related_name="bank_accounts"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
migrations.AlterUniqueTogether(
|
||||||
name='operation',
|
name="operation", unique_together=set([("number", "journal")])
|
||||||
unique_together=set([('number', 'journal')]),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -7,44 +7,44 @@ import phonenumber_field.modelfields
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("accounting", "0002_auto_20160824_2152")]
|
||||||
('accounting', '0002_auto_20160824_2152'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='company',
|
model_name="company",
|
||||||
name='city',
|
name="city",
|
||||||
field=models.CharField(blank=True, verbose_name='city', max_length=60),
|
field=models.CharField(blank=True, verbose_name="city", max_length=60),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='company',
|
model_name="company",
|
||||||
name='country',
|
name="country",
|
||||||
field=models.CharField(blank=True, verbose_name='country', max_length=32),
|
field=models.CharField(blank=True, verbose_name="country", max_length=32),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='company',
|
model_name="company",
|
||||||
name='email',
|
name="email",
|
||||||
field=models.EmailField(blank=True, verbose_name='email', max_length=254),
|
field=models.EmailField(blank=True, verbose_name="email", max_length=254),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='company',
|
model_name="company",
|
||||||
name='phone',
|
name="phone",
|
||||||
field=phonenumber_field.modelfields.PhoneNumberField(blank=True, verbose_name='phone', max_length=128),
|
field=phonenumber_field.modelfields.PhoneNumberField(
|
||||||
|
blank=True, verbose_name="phone", max_length=128
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='company',
|
model_name="company",
|
||||||
name='postcode',
|
name="postcode",
|
||||||
field=models.CharField(blank=True, verbose_name='postcode', max_length=10),
|
field=models.CharField(blank=True, verbose_name="postcode", max_length=10),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='company',
|
model_name="company",
|
||||||
name='street',
|
name="street",
|
||||||
field=models.CharField(blank=True, verbose_name='street', max_length=60),
|
field=models.CharField(blank=True, verbose_name="street", max_length=60),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='company',
|
model_name="company",
|
||||||
name='website',
|
name="website",
|
||||||
field=models.CharField(blank=True, verbose_name='website', max_length=64),
|
field=models.CharField(blank=True, verbose_name="website", max_length=64),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -7,26 +7,45 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("accounting", "0003_auto_20160824_2203")]
|
||||||
('accounting', '0003_auto_20160824_2203'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Label',
|
name="Label",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
(
|
||||||
('name', models.CharField(max_length=64, verbose_name='label')),
|
"id",
|
||||||
('club_account', models.ForeignKey(related_name='labels', verbose_name='club account', to='accounting.ClubAccount')),
|
models.AutoField(
|
||||||
|
verbose_name="ID",
|
||||||
|
primary_key=True,
|
||||||
|
auto_created=True,
|
||||||
|
serialize=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=64, verbose_name="label")),
|
||||||
|
(
|
||||||
|
"club_account",
|
||||||
|
models.ForeignKey(
|
||||||
|
related_name="labels",
|
||||||
|
verbose_name="club account",
|
||||||
|
to="accounting.ClubAccount",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='operation',
|
model_name="operation",
|
||||||
name='label',
|
name="label",
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, related_name='operations', null=True, blank=True, verbose_name='label', to='accounting.Label'),
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="operations",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="label",
|
||||||
|
to="accounting.Label",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
migrations.AlterUniqueTogether(
|
||||||
name='label',
|
name="label", unique_together=set([("name", "club_account")])
|
||||||
unique_together=set([('name', 'club_account')]),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,14 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("accounting", "0004_auto_20161005_1505")]
|
||||||
('accounting', '0004_auto_20161005_1505'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='operation',
|
model_name="operation",
|
||||||
name='remark',
|
name="remark",
|
||||||
field=models.CharField(null=True, max_length=128, blank=True, verbose_name='comment'),
|
field=models.CharField(
|
||||||
|
null=True, max_length=128, blank=True, verbose_name="comment"
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -41,9 +41,10 @@ class CurrencyField(models.DecimalField):
|
|||||||
"""
|
"""
|
||||||
This is a custom database field used for currency
|
This is a custom database field used for currency
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['max_digits'] = 12
|
kwargs["max_digits"] = 12
|
||||||
kwargs['decimal_places'] = 2
|
kwargs["decimal_places"] = 2
|
||||||
super(CurrencyField, self).__init__(*args, **kwargs)
|
super(CurrencyField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
@ -52,18 +53,19 @@ class CurrencyField(models.DecimalField):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
# Accounting classes
|
# Accounting classes
|
||||||
|
|
||||||
|
|
||||||
class Company(models.Model):
|
class Company(models.Model):
|
||||||
name = models.CharField(_('name'), max_length=60)
|
name = models.CharField(_("name"), max_length=60)
|
||||||
street = models.CharField(_('street'), max_length=60, blank=True)
|
street = models.CharField(_("street"), max_length=60, blank=True)
|
||||||
city = models.CharField(_('city'), max_length=60, blank=True)
|
city = models.CharField(_("city"), max_length=60, blank=True)
|
||||||
postcode = models.CharField(_('postcode'), max_length=10, blank=True)
|
postcode = models.CharField(_("postcode"), max_length=10, blank=True)
|
||||||
country = models.CharField(_('country'), max_length=32, blank=True)
|
country = models.CharField(_("country"), max_length=32, blank=True)
|
||||||
phone = PhoneNumberField(_('phone'), blank=True)
|
phone = PhoneNumberField(_("phone"), blank=True)
|
||||||
email = models.EmailField(_('email'), blank=True)
|
email = models.EmailField(_("email"), blank=True)
|
||||||
website = models.CharField(_('website'), max_length=64, blank=True)
|
website = models.CharField(_("website"), max_length=64, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("company")
|
verbose_name = _("company")
|
||||||
@ -81,7 +83,7 @@ class Company(models.Model):
|
|||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
for club in user.memberships.filter(end_date=None).all():
|
for club in user.memberships.filter(end_date=None).all():
|
||||||
if club and club.role == settings.SITH_CLUB_ROLES_ID['Treasurer']:
|
if club and club.role == settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -90,12 +92,12 @@ class Company(models.Model):
|
|||||||
Method to see if that object can be viewed by the given user
|
Method to see if that object can be viewed by the given user
|
||||||
"""
|
"""
|
||||||
for club in user.memberships.filter(end_date=None).all():
|
for club in user.memberships.filter(end_date=None).all():
|
||||||
if club and club.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
|
if club and club.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:co_edit', kwargs={'co_id': self.id})
|
return reverse("accounting:co_edit", kwargs={"co_id": self.id})
|
||||||
|
|
||||||
def get_display_name(self):
|
def get_display_name(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -105,14 +107,14 @@ class Company(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class BankAccount(models.Model):
|
class BankAccount(models.Model):
|
||||||
name = models.CharField(_('name'), max_length=30)
|
name = models.CharField(_("name"), max_length=30)
|
||||||
iban = models.CharField(_('iban'), max_length=255, blank=True)
|
iban = models.CharField(_("iban"), max_length=255, blank=True)
|
||||||
number = models.CharField(_('account number'), max_length=255, blank=True)
|
number = models.CharField(_("account number"), max_length=255, blank=True)
|
||||||
club = models.ForeignKey(Club, related_name="bank_accounts", verbose_name=_("club"))
|
club = models.ForeignKey(Club, related_name="bank_accounts", verbose_name=_("club"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Bank account")
|
verbose_name = _("Bank account")
|
||||||
ordering = ['club', 'name']
|
ordering = ["club", "name"]
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
"""
|
"""
|
||||||
@ -121,25 +123,27 @@ class BankAccount(models.Model):
|
|||||||
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
|
||||||
return True
|
return True
|
||||||
m = self.club.get_membership_for(user)
|
m = self.club.get_membership_for(user)
|
||||||
if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
|
if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:bank_details', kwargs={'b_account_id': self.id})
|
return reverse("accounting:bank_details", kwargs={"b_account_id": self.id})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class ClubAccount(models.Model):
|
class ClubAccount(models.Model):
|
||||||
name = models.CharField(_('name'), max_length=30)
|
name = models.CharField(_("name"), max_length=30)
|
||||||
club = models.ForeignKey(Club, related_name="club_account", verbose_name=_("club"))
|
club = models.ForeignKey(Club, related_name="club_account", verbose_name=_("club"))
|
||||||
bank_account = models.ForeignKey(BankAccount, related_name="club_accounts", verbose_name=_("bank account"))
|
bank_account = models.ForeignKey(
|
||||||
|
BankAccount, related_name="club_accounts", verbose_name=_("bank account")
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Club account")
|
verbose_name = _("Club account")
|
||||||
ordering = ['bank_account', 'name']
|
ordering = ["bank_account", "name"]
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
"""
|
"""
|
||||||
@ -154,7 +158,7 @@ class ClubAccount(models.Model):
|
|||||||
Method to see if that object can be edited by the given user
|
Method to see if that object can be edited by the given user
|
||||||
"""
|
"""
|
||||||
m = self.club.get_membership_for(user)
|
m = self.club.get_membership_for(user)
|
||||||
if m and m.role == settings.SITH_CLUB_ROLES_ID['Treasurer']:
|
if m and m.role == settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -163,7 +167,7 @@ class ClubAccount(models.Model):
|
|||||||
Method to see if that object can be viewed by the given user
|
Method to see if that object can be viewed by the given user
|
||||||
"""
|
"""
|
||||||
m = self.club.get_membership_for(user)
|
m = self.club.get_membership_for(user)
|
||||||
if m and m.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
|
if m and m.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -177,30 +181,36 @@ class ClubAccount(models.Model):
|
|||||||
return self.journals.filter(closed=False).first()
|
return self.journals.filter(closed=False).first()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:club_details', kwargs={'c_account_id': self.id})
|
return reverse("accounting:club_details", kwargs={"c_account_id": self.id})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_display_name(self):
|
def get_display_name(self):
|
||||||
return _("%(club_account)s on %(bank_account)s") % {"club_account": self.name, "bank_account": self.bank_account}
|
return _("%(club_account)s on %(bank_account)s") % {
|
||||||
|
"club_account": self.name,
|
||||||
|
"bank_account": self.bank_account,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GeneralJournal(models.Model):
|
class GeneralJournal(models.Model):
|
||||||
"""
|
"""
|
||||||
Class storing all the operations for a period of time
|
Class storing all the operations for a period of time
|
||||||
"""
|
"""
|
||||||
start_date = models.DateField(_('start date'))
|
|
||||||
end_date = models.DateField(_('end date'), null=True, blank=True, default=None)
|
start_date = models.DateField(_("start date"))
|
||||||
name = models.CharField(_('name'), max_length=40)
|
end_date = models.DateField(_("end date"), null=True, blank=True, default=None)
|
||||||
closed = models.BooleanField(_('is closed'), default=False)
|
name = models.CharField(_("name"), max_length=40)
|
||||||
club_account = models.ForeignKey(ClubAccount, related_name="journals", null=False, verbose_name=_("club account"))
|
closed = models.BooleanField(_("is closed"), default=False)
|
||||||
amount = CurrencyField(_('amount'), default=0)
|
club_account = models.ForeignKey(
|
||||||
effective_amount = CurrencyField(_('effective_amount'), default=0)
|
ClubAccount, related_name="journals", null=False, verbose_name=_("club account")
|
||||||
|
)
|
||||||
|
amount = CurrencyField(_("amount"), default=0)
|
||||||
|
effective_amount = CurrencyField(_("effective_amount"), default=0)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("General journal")
|
verbose_name = _("General journal")
|
||||||
ordering = ['-start_date']
|
ordering = ["-start_date"]
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
"""
|
"""
|
||||||
@ -226,7 +236,7 @@ class GeneralJournal(models.Model):
|
|||||||
return self.club_account.can_be_viewed_by(user)
|
return self.club_account.can_be_viewed_by(user)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:journal_details', kwargs={'j_id': self.id})
|
return reverse("accounting:journal_details", kwargs={"j_id": self.id})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -250,31 +260,79 @@ class Operation(models.Model):
|
|||||||
"""
|
"""
|
||||||
An operation is a line in the journal, a debit or a credit
|
An operation is a line in the journal, a debit or a credit
|
||||||
"""
|
"""
|
||||||
number = models.IntegerField(_('number'))
|
|
||||||
journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False, verbose_name=_("journal"))
|
number = models.IntegerField(_("number"))
|
||||||
amount = CurrencyField(_('amount'))
|
journal = models.ForeignKey(
|
||||||
date = models.DateField(_('date'))
|
GeneralJournal, related_name="operations", null=False, verbose_name=_("journal")
|
||||||
remark = models.CharField(_('comment'), max_length=128, null=True, blank=True)
|
)
|
||||||
mode = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD)
|
amount = CurrencyField(_("amount"))
|
||||||
cheque_number = models.CharField(_('cheque number'), max_length=32, default="", null=True, blank=True)
|
date = models.DateField(_("date"))
|
||||||
invoice = models.ForeignKey(SithFile, related_name='operations', verbose_name=_("invoice"), null=True, blank=True)
|
remark = models.CharField(_("comment"), max_length=128, null=True, blank=True)
|
||||||
done = models.BooleanField(_('is done'), default=False)
|
mode = models.CharField(
|
||||||
simpleaccounting_type = models.ForeignKey('SimplifiedAccountingType', related_name="operations",
|
_("payment method"),
|
||||||
verbose_name=_("simple type"), null=True, blank=True)
|
max_length=255,
|
||||||
accounting_type = models.ForeignKey('AccountingType', related_name="operations",
|
choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD,
|
||||||
verbose_name=_("accounting type"), null=True, blank=True)
|
)
|
||||||
label = models.ForeignKey('Label', related_name="operations",
|
cheque_number = models.CharField(
|
||||||
verbose_name=_("label"), null=True, blank=True, on_delete=models.SET_NULL)
|
_("cheque number"), max_length=32, default="", null=True, blank=True
|
||||||
target_type = models.CharField(_('target type'), max_length=10,
|
)
|
||||||
choices=[('USER', _('User')), ('CLUB', _('Club')), ('ACCOUNT', _('Account')), ('COMPANY', _('Company')), ('OTHER', _('Other'))])
|
invoice = models.ForeignKey(
|
||||||
target_id = models.IntegerField(_('target id'), null=True, blank=True)
|
SithFile,
|
||||||
target_label = models.CharField(_('target label'), max_length=32, default="", blank=True)
|
related_name="operations",
|
||||||
linked_operation = models.OneToOneField('self', related_name='operation_linked_to', verbose_name=_("linked operation"),
|
verbose_name=_("invoice"),
|
||||||
null=True, blank=True, default=None)
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
done = models.BooleanField(_("is done"), default=False)
|
||||||
|
simpleaccounting_type = models.ForeignKey(
|
||||||
|
"SimplifiedAccountingType",
|
||||||
|
related_name="operations",
|
||||||
|
verbose_name=_("simple type"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
accounting_type = models.ForeignKey(
|
||||||
|
"AccountingType",
|
||||||
|
related_name="operations",
|
||||||
|
verbose_name=_("accounting type"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
label = models.ForeignKey(
|
||||||
|
"Label",
|
||||||
|
related_name="operations",
|
||||||
|
verbose_name=_("label"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
)
|
||||||
|
target_type = models.CharField(
|
||||||
|
_("target type"),
|
||||||
|
max_length=10,
|
||||||
|
choices=[
|
||||||
|
("USER", _("User")),
|
||||||
|
("CLUB", _("Club")),
|
||||||
|
("ACCOUNT", _("Account")),
|
||||||
|
("COMPANY", _("Company")),
|
||||||
|
("OTHER", _("Other")),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
target_id = models.IntegerField(_("target id"), null=True, blank=True)
|
||||||
|
target_label = models.CharField(
|
||||||
|
_("target label"), max_length=32, default="", blank=True
|
||||||
|
)
|
||||||
|
linked_operation = models.OneToOneField(
|
||||||
|
"self",
|
||||||
|
related_name="operation_linked_to",
|
||||||
|
verbose_name=_("linked operation"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('number', 'journal')
|
unique_together = ("number", "journal")
|
||||||
ordering = ['-number']
|
ordering = ["-number"]
|
||||||
|
|
||||||
def __getattribute__(self, attr):
|
def __getattribute__(self, attr):
|
||||||
if attr == "target":
|
if attr == "target":
|
||||||
@ -287,14 +345,29 @@ class Operation(models.Model):
|
|||||||
if self.date is None:
|
if self.date is None:
|
||||||
raise ValidationError(_("The date must be set."))
|
raise ValidationError(_("The date must be set."))
|
||||||
elif self.date < self.journal.start_date:
|
elif self.date < self.journal.start_date:
|
||||||
raise ValidationError(_("""The date can not be before the start date of the journal, which is
|
raise ValidationError(
|
||||||
%(start_date)s.""") % {'start_date': defaultfilters.date(self.journal.start_date, settings.DATE_FORMAT)})
|
_(
|
||||||
|
"""The date can not be before the start date of the journal, which is
|
||||||
|
%(start_date)s."""
|
||||||
|
)
|
||||||
|
% {
|
||||||
|
"start_date": defaultfilters.date(
|
||||||
|
self.journal.start_date, settings.DATE_FORMAT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
if self.target_type != "OTHER" and self.get_target() is None:
|
if self.target_type != "OTHER" and self.get_target() is None:
|
||||||
raise ValidationError(_("Target does not exists"))
|
raise ValidationError(_("Target does not exists"))
|
||||||
if self.target_type == "OTHER" and self.target_label == "":
|
if self.target_type == "OTHER" and self.target_label == "":
|
||||||
raise ValidationError(_("Please add a target label if you set no existing target"))
|
raise ValidationError(
|
||||||
|
_("Please add a target label if you set no existing target")
|
||||||
|
)
|
||||||
if not self.accounting_type and not self.simpleaccounting_type:
|
if not self.accounting_type and not self.simpleaccounting_type:
|
||||||
raise ValidationError(_("You need to provide ether a simplified accounting type or a standard accounting type"))
|
raise ValidationError(
|
||||||
|
_(
|
||||||
|
"You need to provide ether a simplified accounting type or a standard accounting type"
|
||||||
|
)
|
||||||
|
)
|
||||||
if self.simpleaccounting_type:
|
if self.simpleaccounting_type:
|
||||||
self.accounting_type = self.simpleaccounting_type.accounting_type
|
self.accounting_type = self.simpleaccounting_type.accounting_type
|
||||||
|
|
||||||
@ -329,7 +402,7 @@ class Operation(models.Model):
|
|||||||
if self.journal.closed:
|
if self.journal.closed:
|
||||||
return False
|
return False
|
||||||
m = self.journal.club_account.club.get_membership_for(user)
|
m = self.journal.club_account.club.get_membership_for(user)
|
||||||
if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID['Treasurer']:
|
if m is not None and m.role >= settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -342,16 +415,19 @@ class Operation(models.Model):
|
|||||||
if self.journal.closed:
|
if self.journal.closed:
|
||||||
return False
|
return False
|
||||||
m = self.journal.club_account.club.get_membership_for(user)
|
m = self.journal.club_account.club.get_membership_for(user)
|
||||||
if m is not None and m.role == settings.SITH_CLUB_ROLES_ID['Treasurer']:
|
if m is not None and m.role == settings.SITH_CLUB_ROLES_ID["Treasurer"]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:journal_details', kwargs={'j_id': self.journal.id})
|
return reverse("accounting:journal_details", kwargs={"j_id": self.journal.id})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%d € | %s | %s | %s" % (
|
return "%d € | %s | %s | %s" % (
|
||||||
self.amount, self.date, self.accounting_type, self.done,
|
self.amount,
|
||||||
|
self.date,
|
||||||
|
self.accounting_type,
|
||||||
|
self.done,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -361,18 +437,30 @@ class AccountingType(models.Model):
|
|||||||
|
|
||||||
Thoses are numbers used in accounting to classify operations
|
Thoses are numbers used in accounting to classify operations
|
||||||
"""
|
"""
|
||||||
code = models.CharField(_('code'), max_length=16,
|
|
||||||
|
code = models.CharField(
|
||||||
|
_("code"),
|
||||||
|
max_length=16,
|
||||||
validators=[
|
validators=[
|
||||||
validators.RegexValidator(r'^[0-9]*$', _('An accounting type code contains only numbers')),
|
validators.RegexValidator(
|
||||||
|
r"^[0-9]*$", _("An accounting type code contains only numbers")
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
label = models.CharField(_('label'), max_length=128)
|
label = models.CharField(_("label"), max_length=128)
|
||||||
movement_type = models.CharField(_('movement type'), choices=[('CREDIT', _('Credit')), ('DEBIT', _('Debit')),
|
movement_type = models.CharField(
|
||||||
('NEUTRAL', _('Neutral'))], max_length=12)
|
_("movement type"),
|
||||||
|
choices=[
|
||||||
|
("CREDIT", _("Credit")),
|
||||||
|
("DEBIT", _("Debit")),
|
||||||
|
("NEUTRAL", _("Neutral")),
|
||||||
|
],
|
||||||
|
max_length=12,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("accounting type")
|
verbose_name = _("accounting type")
|
||||||
ordering = ['movement_type', 'code']
|
ordering = ["movement_type", "code"]
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
"""
|
"""
|
||||||
@ -383,7 +471,7 @@ class AccountingType(models.Model):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:type_list')
|
return reverse("accounting:type_list")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.code + " - " + self.get_movement_type_display() + " - " + self.label
|
return self.code + " - " + self.get_movement_type_display() + " - " + self.label
|
||||||
@ -393,13 +481,17 @@ class SimplifiedAccountingType(models.Model):
|
|||||||
"""
|
"""
|
||||||
Class describing the simplified accounting types.
|
Class describing the simplified accounting types.
|
||||||
"""
|
"""
|
||||||
label = models.CharField(_('label'), max_length=128)
|
|
||||||
accounting_type = models.ForeignKey(AccountingType, related_name="simplified_types",
|
label = models.CharField(_("label"), max_length=128)
|
||||||
verbose_name=_("simplified accounting types"))
|
accounting_type = models.ForeignKey(
|
||||||
|
AccountingType,
|
||||||
|
related_name="simplified_types",
|
||||||
|
verbose_name=_("simplified accounting types"),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("simplified type")
|
verbose_name = _("simplified type")
|
||||||
ordering = ['accounting_type__movement_type', 'accounting_type__code']
|
ordering = ["accounting_type__movement_type", "accounting_type__code"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def movement_type(self):
|
def movement_type(self):
|
||||||
@ -409,25 +501,36 @@ class SimplifiedAccountingType(models.Model):
|
|||||||
return self.accounting_type.get_movement_type_display()
|
return self.accounting_type.get_movement_type_display()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:simple_type_list')
|
return reverse("accounting:simple_type_list")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.get_movement_type_display() + " - " + self.accounting_type.code + " - " + self.label
|
return (
|
||||||
|
self.get_movement_type_display()
|
||||||
|
+ " - "
|
||||||
|
+ self.accounting_type.code
|
||||||
|
+ " - "
|
||||||
|
+ self.label
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Label(models.Model):
|
class Label(models.Model):
|
||||||
"""Label allow a club to sort its operations"""
|
"""Label allow a club to sort its operations"""
|
||||||
name = models.CharField(_('label'), max_length=64)
|
|
||||||
club_account = models.ForeignKey(ClubAccount, related_name="labels", verbose_name=_("club account"))
|
name = models.CharField(_("label"), max_length=64)
|
||||||
|
club_account = models.ForeignKey(
|
||||||
|
ClubAccount, related_name="labels", verbose_name=_("club account")
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('name', 'club_account')
|
unique_together = ("name", "club_account")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s (%s)" % (self.name, self.club_account.name)
|
return "%s (%s)" % (self.name, self.club_account.name)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('accounting:label_list', kwargs={'clubaccount_id': self.club_account.id})
|
return reverse(
|
||||||
|
"accounting:label_list", kwargs={"clubaccount_id": self.club_account.id}
|
||||||
|
)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return self.club_account.is_owned_by(user)
|
return self.club_account.is_owned_by(user)
|
||||||
|
@ -28,7 +28,13 @@ from django.core.management import call_command
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
from core.models import User
|
from core.models import User
|
||||||
from accounting.models import GeneralJournal, Operation, Label, AccountingType, SimplifiedAccountingType
|
from accounting.models import (
|
||||||
|
GeneralJournal,
|
||||||
|
Operation,
|
||||||
|
Label,
|
||||||
|
AccountingType,
|
||||||
|
SimplifiedAccountingType,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RefoundAccountTest(TestCase):
|
class RefoundAccountTest(TestCase):
|
||||||
@ -40,18 +46,20 @@ class RefoundAccountTest(TestCase):
|
|||||||
self.skia.customer.save()
|
self.skia.customer.save()
|
||||||
|
|
||||||
def test_permission_denied(self):
|
def test_permission_denied(self):
|
||||||
self.client.login(username='guy', password='plop')
|
self.client.login(username="guy", password="plop")
|
||||||
response_post = self.client.post(reverse("accounting:refound_account"),
|
response_post = self.client.post(
|
||||||
{"user": self.skia.id})
|
reverse("accounting:refound_account"), {"user": self.skia.id}
|
||||||
|
)
|
||||||
response_get = self.client.get(reverse("accounting:refound_account"))
|
response_get = self.client.get(reverse("accounting:refound_account"))
|
||||||
self.assertTrue(response_get.status_code == 403)
|
self.assertTrue(response_get.status_code == 403)
|
||||||
self.assertTrue(response_post.status_code == 403)
|
self.assertTrue(response_post.status_code == 403)
|
||||||
|
|
||||||
def test_root_granteed(self):
|
def test_root_granteed(self):
|
||||||
self.client.login(username='root', password='plop')
|
self.client.login(username="root", password="plop")
|
||||||
response_post = self.client.post(reverse("accounting:refound_account"),
|
response_post = self.client.post(
|
||||||
{"user": self.skia.id})
|
reverse("accounting:refound_account"), {"user": self.skia.id}
|
||||||
self.skia = User.objects.filter(username='skia').first()
|
)
|
||||||
|
self.skia = User.objects.filter(username="skia").first()
|
||||||
response_get = self.client.get(reverse("accounting:refound_account"))
|
response_get = self.client.get(reverse("accounting:refound_account"))
|
||||||
self.assertFalse(response_get.status_code == 403)
|
self.assertFalse(response_get.status_code == 403)
|
||||||
self.assertTrue('<form action="" method="post">' in str(response_get.content))
|
self.assertTrue('<form action="" method="post">' in str(response_get.content))
|
||||||
@ -59,10 +67,11 @@ class RefoundAccountTest(TestCase):
|
|||||||
self.assertTrue(self.skia.customer.amount == 0)
|
self.assertTrue(self.skia.customer.amount == 0)
|
||||||
|
|
||||||
def test_comptable_granteed(self):
|
def test_comptable_granteed(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
response_post = self.client.post(reverse("accounting:refound_account"),
|
response_post = self.client.post(
|
||||||
{"user": self.skia.id})
|
reverse("accounting:refound_account"), {"user": self.skia.id}
|
||||||
self.skia = User.objects.filter(username='skia').first()
|
)
|
||||||
|
self.skia = User.objects.filter(username="skia").first()
|
||||||
response_get = self.client.get(reverse("accounting:refound_account"))
|
response_get = self.client.get(reverse("accounting:refound_account"))
|
||||||
self.assertFalse(response_get.status_code == 403)
|
self.assertFalse(response_get.status_code == 403)
|
||||||
self.assertTrue('<form action="" method="post">' in str(response_get.content))
|
self.assertTrue('<form action="" method="post">' in str(response_get.content))
|
||||||
@ -76,146 +85,217 @@ class JournalTest(TestCase):
|
|||||||
self.journal = GeneralJournal.objects.filter(id=1).first()
|
self.journal = GeneralJournal.objects.filter(id=1).first()
|
||||||
|
|
||||||
def test_permission_granted(self):
|
def test_permission_granted(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id]))
|
response_get = self.client.get(
|
||||||
|
reverse("accounting:journal_details", args=[self.journal.id])
|
||||||
|
)
|
||||||
|
|
||||||
self.assertTrue(response_get.status_code == 200)
|
self.assertTrue(response_get.status_code == 200)
|
||||||
self.assertTrue('<td>M\\xc3\\xa9thode de paiement</td>' in str(response_get.content))
|
self.assertTrue(
|
||||||
|
"<td>M\\xc3\\xa9thode de paiement</td>" in str(response_get.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_permission_not_granted(self):
|
def test_permission_not_granted(self):
|
||||||
self.client.login(username='skia', password='plop')
|
self.client.login(username="skia", password="plop")
|
||||||
response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id]))
|
response_get = self.client.get(
|
||||||
|
reverse("accounting:journal_details", args=[self.journal.id])
|
||||||
|
)
|
||||||
|
|
||||||
self.assertTrue(response_get.status_code == 403)
|
self.assertTrue(response_get.status_code == 403)
|
||||||
self.assertFalse('<td>M\xc3\xa9thode de paiement</td>' in str(response_get.content))
|
self.assertFalse(
|
||||||
|
"<td>M\xc3\xa9thode de paiement</td>" in str(response_get.content)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OperationTest(TestCase):
|
class OperationTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
call_command("populate")
|
||||||
self.journal = GeneralJournal.objects.filter(id=1).first()
|
self.journal = GeneralJournal.objects.filter(id=1).first()
|
||||||
self.skia = User.objects.filter(username='skia').first()
|
self.skia = User.objects.filter(username="skia").first()
|
||||||
at = AccountingType(code='443', label="Ce code n'existe pas", movement_type='CREDIT')
|
at = AccountingType(
|
||||||
|
code="443", label="Ce code n'existe pas", movement_type="CREDIT"
|
||||||
|
)
|
||||||
at.save()
|
at.save()
|
||||||
l = Label(club_account=self.journal.club_account, name='bob')
|
l = Label(club_account=self.journal.club_account, name="bob")
|
||||||
l.save()
|
l.save()
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
self.op1 = Operation(journal=self.journal, date=date.today(), amount=1,
|
self.op1 = Operation(
|
||||||
remark="Test bilan", mode='CASH', done=True, label=l,
|
journal=self.journal,
|
||||||
accounting_type=at, target_type='USER', target_id=self.skia.id)
|
date=date.today(),
|
||||||
|
amount=1,
|
||||||
|
remark="Test bilan",
|
||||||
|
mode="CASH",
|
||||||
|
done=True,
|
||||||
|
label=l,
|
||||||
|
accounting_type=at,
|
||||||
|
target_type="USER",
|
||||||
|
target_id=self.skia.id,
|
||||||
|
)
|
||||||
self.op1.save()
|
self.op1.save()
|
||||||
self.op2 = Operation(journal=self.journal, date=date.today(), amount=2,
|
self.op2 = Operation(
|
||||||
remark="Test bilan", mode='CASH', done=True, label=l,
|
journal=self.journal,
|
||||||
accounting_type=at, target_type='USER', target_id=self.skia.id)
|
date=date.today(),
|
||||||
|
amount=2,
|
||||||
|
remark="Test bilan",
|
||||||
|
mode="CASH",
|
||||||
|
done=True,
|
||||||
|
label=l,
|
||||||
|
accounting_type=at,
|
||||||
|
target_type="USER",
|
||||||
|
target_id=self.skia.id,
|
||||||
|
)
|
||||||
self.op2.save()
|
self.op2.save()
|
||||||
|
|
||||||
def test_new_operation(self):
|
def test_new_operation(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
at = AccountingType.objects.filter(code='604').first()
|
at = AccountingType.objects.filter(code="604").first()
|
||||||
response = self.client.post(reverse('accounting:op_new',
|
response = self.client.post(
|
||||||
args=[self.journal.id]),
|
reverse("accounting:op_new", args=[self.journal.id]),
|
||||||
{'amount': 30,
|
{
|
||||||
'remark': "Un gros test",
|
"amount": 30,
|
||||||
'journal': self.journal.id,
|
"remark": "Un gros test",
|
||||||
'target_type': 'OTHER',
|
"journal": self.journal.id,
|
||||||
'target_id': '',
|
"target_type": "OTHER",
|
||||||
'target_label': "Le fantome de la nuit",
|
"target_id": "",
|
||||||
'date': '04/12/2020',
|
"target_label": "Le fantome de la nuit",
|
||||||
'mode': 'CASH',
|
"date": "04/12/2020",
|
||||||
'cheque_number': '',
|
"mode": "CASH",
|
||||||
'invoice': '',
|
"cheque_number": "",
|
||||||
'simpleaccounting_type': '',
|
"invoice": "",
|
||||||
'accounting_type': at.id,
|
"simpleaccounting_type": "",
|
||||||
'label': '',
|
"accounting_type": at.id,
|
||||||
'done': False,
|
"label": "",
|
||||||
})
|
"done": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertFalse(response.status_code == 403)
|
self.assertFalse(response.status_code == 403)
|
||||||
self.assertTrue(self.journal.operations.filter(target_label="Le fantome de la nuit").exists())
|
self.assertTrue(
|
||||||
response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id]))
|
self.journal.operations.filter(
|
||||||
self.assertTrue('<td>Le fantome de la nuit</td>' in str(response_get.content))
|
target_label="Le fantome de la nuit"
|
||||||
|
).exists()
|
||||||
|
)
|
||||||
|
response_get = self.client.get(
|
||||||
|
reverse("accounting:journal_details", args=[self.journal.id])
|
||||||
|
)
|
||||||
|
self.assertTrue("<td>Le fantome de la nuit</td>" in str(response_get.content))
|
||||||
|
|
||||||
def test_bad_new_operation(self):
|
def test_bad_new_operation(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
AccountingType.objects.filter(code='604').first()
|
AccountingType.objects.filter(code="604").first()
|
||||||
response = self.client.post(reverse('accounting:op_new',
|
response = self.client.post(
|
||||||
args=[self.journal.id]),
|
reverse("accounting:op_new", args=[self.journal.id]),
|
||||||
{'amount': 30,
|
{
|
||||||
'remark': "Un gros test",
|
"amount": 30,
|
||||||
'journal': self.journal.id,
|
"remark": "Un gros test",
|
||||||
'target_type': 'OTHER',
|
"journal": self.journal.id,
|
||||||
'target_id': '',
|
"target_type": "OTHER",
|
||||||
'target_label': "Le fantome de la nuit",
|
"target_id": "",
|
||||||
'date': '04/12/2020',
|
"target_label": "Le fantome de la nuit",
|
||||||
'mode': 'CASH',
|
"date": "04/12/2020",
|
||||||
'cheque_number': '',
|
"mode": "CASH",
|
||||||
'invoice': '',
|
"cheque_number": "",
|
||||||
'simpleaccounting_type': '',
|
"invoice": "",
|
||||||
'accounting_type': '',
|
"simpleaccounting_type": "",
|
||||||
'label': '',
|
"accounting_type": "",
|
||||||
'done': False,
|
"label": "",
|
||||||
})
|
"done": False,
|
||||||
self.assertTrue('Vous devez fournir soit un type comptable simplifi\\xc3\\xa9 ou un type comptable standard' in str(response.content))
|
},
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
"Vous devez fournir soit un type comptable simplifi\\xc3\\xa9 ou un type comptable standard"
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_new_operation_not_authorized(self):
|
def test_new_operation_not_authorized(self):
|
||||||
self.client.login(username='skia', password='plop')
|
self.client.login(username="skia", password="plop")
|
||||||
at = AccountingType.objects.filter(code='604').first()
|
at = AccountingType.objects.filter(code="604").first()
|
||||||
response = self.client.post(reverse('accounting:op_new',
|
response = self.client.post(
|
||||||
args=[self.journal.id]),
|
reverse("accounting:op_new", args=[self.journal.id]),
|
||||||
{'amount': 30,
|
{
|
||||||
'remark': "Un gros test",
|
"amount": 30,
|
||||||
'journal': self.journal.id,
|
"remark": "Un gros test",
|
||||||
'target_type': 'OTHER',
|
"journal": self.journal.id,
|
||||||
'target_id': '',
|
"target_type": "OTHER",
|
||||||
'target_label': "Le fantome du jour",
|
"target_id": "",
|
||||||
'date': '04/12/2020',
|
"target_label": "Le fantome du jour",
|
||||||
'mode': 'CASH',
|
"date": "04/12/2020",
|
||||||
'cheque_number': '',
|
"mode": "CASH",
|
||||||
'invoice': '',
|
"cheque_number": "",
|
||||||
'simpleaccounting_type': '',
|
"invoice": "",
|
||||||
'accounting_type': at.id,
|
"simpleaccounting_type": "",
|
||||||
'label': '',
|
"accounting_type": at.id,
|
||||||
'done': False,
|
"label": "",
|
||||||
})
|
"done": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 403)
|
self.assertTrue(response.status_code == 403)
|
||||||
self.assertFalse(self.journal.operations.filter(target_label="Le fantome du jour").exists())
|
self.assertFalse(
|
||||||
|
self.journal.operations.filter(target_label="Le fantome du jour").exists()
|
||||||
|
)
|
||||||
|
|
||||||
def test__operation_simple_accounting(self):
|
def test__operation_simple_accounting(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
sat = SimplifiedAccountingType.objects.all().first()
|
sat = SimplifiedAccountingType.objects.all().first()
|
||||||
response = self.client.post(reverse('accounting:op_new',
|
response = self.client.post(
|
||||||
args=[self.journal.id]),
|
reverse("accounting:op_new", args=[self.journal.id]),
|
||||||
{'amount': 23,
|
{
|
||||||
'remark': "Un gros test",
|
"amount": 23,
|
||||||
'journal': self.journal.id,
|
"remark": "Un gros test",
|
||||||
'target_type': 'OTHER',
|
"journal": self.journal.id,
|
||||||
'target_id': '',
|
"target_type": "OTHER",
|
||||||
'target_label': "Le fantome de l'aurore",
|
"target_id": "",
|
||||||
'date': '04/12/2020',
|
"target_label": "Le fantome de l'aurore",
|
||||||
'mode': 'CASH',
|
"date": "04/12/2020",
|
||||||
'cheque_number': '',
|
"mode": "CASH",
|
||||||
'invoice': '',
|
"cheque_number": "",
|
||||||
'simpleaccounting_type': sat.id,
|
"invoice": "",
|
||||||
'accounting_type': '',
|
"simpleaccounting_type": sat.id,
|
||||||
'label': '',
|
"accounting_type": "",
|
||||||
'done': False,
|
"label": "",
|
||||||
})
|
"done": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertFalse(response.status_code == 403)
|
self.assertFalse(response.status_code == 403)
|
||||||
self.assertTrue(self.journal.operations.filter(amount=23).exists())
|
self.assertTrue(self.journal.operations.filter(amount=23).exists())
|
||||||
response_get = self.client.get(reverse("accounting:journal_details", args=[self.journal.id]))
|
response_get = self.client.get(
|
||||||
self.assertTrue("<td>Le fantome de l'aurore</td>" in str(response_get.content))
|
reverse("accounting:journal_details", args=[self.journal.id])
|
||||||
self.assertTrue(self.journal.operations.filter(amount=23).values('accounting_type').first()['accounting_type'] == AccountingType.objects.filter(code=6).values('id').first()['id'])
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
"<td>Le fantome de l'aurore</td>" in str(response_get.content)
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
self.journal.operations.filter(amount=23)
|
||||||
|
.values("accounting_type")
|
||||||
|
.first()["accounting_type"]
|
||||||
|
== AccountingType.objects.filter(code=6).values("id").first()["id"]
|
||||||
|
)
|
||||||
|
|
||||||
def test_nature_statement(self):
|
def test_nature_statement(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
response_get = self.client.get(reverse("accounting:journal_nature_statement", args=[self.journal.id]))
|
response_get = self.client.get(
|
||||||
self.assertTrue("bob (Troll Pench\\xc3\\xa9) : 3.00" in str(response_get.content))
|
reverse("accounting:journal_nature_statement", args=[self.journal.id])
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
"bob (Troll Pench\\xc3\\xa9) : 3.00" in str(response_get.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_person_statement(self):
|
def test_person_statement(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
response_get = self.client.get(reverse("accounting:journal_person_statement", args=[self.journal.id]))
|
response_get = self.client.get(
|
||||||
self.assertTrue("<td>3.00</td>" in str(response_get.content) and '<td><a href="/user/1/">S' Kia</a></td>' in str(response_get.content))
|
reverse("accounting:journal_person_statement", args=[self.journal.id])
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
"<td>3.00</td>" in str(response_get.content)
|
||||||
|
and '<td><a href="/user/1/">S' Kia</a></td>'
|
||||||
|
in str(response_get.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_accounting_statement(self):
|
def test_accounting_statement(self):
|
||||||
self.client.login(username='comptable', password='plop')
|
self.client.login(username="comptable", password="plop")
|
||||||
response_get = self.client.get(reverse("accounting:journal_accounting_statement", args=[self.journal.id]))
|
response_get = self.client.get(
|
||||||
self.assertTrue("<td>443 - Cr\\xc3\\xa9dit - Ce code n'existe pas</td>" in str(response_get.content))
|
reverse("accounting:journal_accounting_statement", args=[self.journal.id])
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
"<td>443 - Cr\\xc3\\xa9dit - Ce code n'existe pas</td>"
|
||||||
|
in str(response_get.content)
|
||||||
|
)
|
||||||
|
@ -28,46 +28,125 @@ from accounting.views import *
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Accounting types
|
# Accounting types
|
||||||
url(r'^simple_type$', SimplifiedAccountingTypeListView.as_view(), name='simple_type_list'),
|
url(
|
||||||
url(r'^simple_type/create$', SimplifiedAccountingTypeCreateView.as_view(), name='simple_type_new'),
|
r"^simple_type$",
|
||||||
url(r'^simple_type/(?P<type_id>[0-9]+)/edit$', SimplifiedAccountingTypeEditView.as_view(), name='simple_type_edit'),
|
SimplifiedAccountingTypeListView.as_view(),
|
||||||
|
name="simple_type_list",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^simple_type/create$",
|
||||||
|
SimplifiedAccountingTypeCreateView.as_view(),
|
||||||
|
name="simple_type_new",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^simple_type/(?P<type_id>[0-9]+)/edit$",
|
||||||
|
SimplifiedAccountingTypeEditView.as_view(),
|
||||||
|
name="simple_type_edit",
|
||||||
|
),
|
||||||
# Accounting types
|
# Accounting types
|
||||||
url(r'^type$', AccountingTypeListView.as_view(), name='type_list'),
|
url(r"^type$", AccountingTypeListView.as_view(), name="type_list"),
|
||||||
url(r'^type/create$', AccountingTypeCreateView.as_view(), name='type_new'),
|
url(r"^type/create$", AccountingTypeCreateView.as_view(), name="type_new"),
|
||||||
url(r'^type/(?P<type_id>[0-9]+)/edit$', AccountingTypeEditView.as_view(), name='type_edit'),
|
url(
|
||||||
|
r"^type/(?P<type_id>[0-9]+)/edit$",
|
||||||
|
AccountingTypeEditView.as_view(),
|
||||||
|
name="type_edit",
|
||||||
|
),
|
||||||
# Bank accounts
|
# Bank accounts
|
||||||
url(r'^$', BankAccountListView.as_view(), name='bank_list'),
|
url(r"^$", BankAccountListView.as_view(), name="bank_list"),
|
||||||
url(r'^bank/create$', BankAccountCreateView.as_view(), name='bank_new'),
|
url(r"^bank/create$", BankAccountCreateView.as_view(), name="bank_new"),
|
||||||
url(r'^bank/(?P<b_account_id>[0-9]+)$', BankAccountDetailView.as_view(), name='bank_details'),
|
url(
|
||||||
url(r'^bank/(?P<b_account_id>[0-9]+)/edit$', BankAccountEditView.as_view(), name='bank_edit'),
|
r"^bank/(?P<b_account_id>[0-9]+)$",
|
||||||
url(r'^bank/(?P<b_account_id>[0-9]+)/delete$', BankAccountDeleteView.as_view(), name='bank_delete'),
|
BankAccountDetailView.as_view(),
|
||||||
|
name="bank_details",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^bank/(?P<b_account_id>[0-9]+)/edit$",
|
||||||
|
BankAccountEditView.as_view(),
|
||||||
|
name="bank_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^bank/(?P<b_account_id>[0-9]+)/delete$",
|
||||||
|
BankAccountDeleteView.as_view(),
|
||||||
|
name="bank_delete",
|
||||||
|
),
|
||||||
# Club accounts
|
# Club accounts
|
||||||
url(r'^club/create$', ClubAccountCreateView.as_view(), name='club_new'),
|
url(r"^club/create$", ClubAccountCreateView.as_view(), name="club_new"),
|
||||||
url(r'^club/(?P<c_account_id>[0-9]+)$', ClubAccountDetailView.as_view(), name='club_details'),
|
url(
|
||||||
url(r'^club/(?P<c_account_id>[0-9]+)/edit$', ClubAccountEditView.as_view(), name='club_edit'),
|
r"^club/(?P<c_account_id>[0-9]+)$",
|
||||||
url(r'^club/(?P<c_account_id>[0-9]+)/delete$', ClubAccountDeleteView.as_view(), name='club_delete'),
|
ClubAccountDetailView.as_view(),
|
||||||
|
name="club_details",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^club/(?P<c_account_id>[0-9]+)/edit$",
|
||||||
|
ClubAccountEditView.as_view(),
|
||||||
|
name="club_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^club/(?P<c_account_id>[0-9]+)/delete$",
|
||||||
|
ClubAccountDeleteView.as_view(),
|
||||||
|
name="club_delete",
|
||||||
|
),
|
||||||
# Journals
|
# Journals
|
||||||
url(r'^journal/create$', JournalCreateView.as_view(), name='journal_new'),
|
url(r"^journal/create$", JournalCreateView.as_view(), name="journal_new"),
|
||||||
url(r'^journal/(?P<j_id>[0-9]+)$', JournalDetailView.as_view(), name='journal_details'),
|
url(
|
||||||
url(r'^journal/(?P<j_id>[0-9]+)/edit$', JournalEditView.as_view(), name='journal_edit'),
|
r"^journal/(?P<j_id>[0-9]+)$",
|
||||||
url(r'^journal/(?P<j_id>[0-9]+)/delete$', JournalDeleteView.as_view(), name='journal_delete'),
|
JournalDetailView.as_view(),
|
||||||
url(r'^journal/(?P<j_id>[0-9]+)/statement/nature$', JournalNatureStatementView.as_view(), name='journal_nature_statement'),
|
name="journal_details",
|
||||||
url(r'^journal/(?P<j_id>[0-9]+)/statement/person$', JournalPersonStatementView.as_view(), name='journal_person_statement'),
|
),
|
||||||
url(r'^journal/(?P<j_id>[0-9]+)/statement/accounting$', JournalAccountingStatementView.as_view(), name='journal_accounting_statement'),
|
url(
|
||||||
|
r"^journal/(?P<j_id>[0-9]+)/edit$",
|
||||||
|
JournalEditView.as_view(),
|
||||||
|
name="journal_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^journal/(?P<j_id>[0-9]+)/delete$",
|
||||||
|
JournalDeleteView.as_view(),
|
||||||
|
name="journal_delete",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^journal/(?P<j_id>[0-9]+)/statement/nature$",
|
||||||
|
JournalNatureStatementView.as_view(),
|
||||||
|
name="journal_nature_statement",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^journal/(?P<j_id>[0-9]+)/statement/person$",
|
||||||
|
JournalPersonStatementView.as_view(),
|
||||||
|
name="journal_person_statement",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^journal/(?P<j_id>[0-9]+)/statement/accounting$",
|
||||||
|
JournalAccountingStatementView.as_view(),
|
||||||
|
name="journal_accounting_statement",
|
||||||
|
),
|
||||||
# Operations
|
# Operations
|
||||||
url(r'^operation/create/(?P<j_id>[0-9]+)$', OperationCreateView.as_view(), name='op_new'),
|
url(
|
||||||
url(r'^operation/(?P<op_id>[0-9]+)$', OperationEditView.as_view(), name='op_edit'),
|
r"^operation/create/(?P<j_id>[0-9]+)$",
|
||||||
url(r'^operation/(?P<op_id>[0-9]+)/pdf$', OperationPDFView.as_view(), name='op_pdf'),
|
OperationCreateView.as_view(),
|
||||||
|
name="op_new",
|
||||||
|
),
|
||||||
|
url(r"^operation/(?P<op_id>[0-9]+)$", OperationEditView.as_view(), name="op_edit"),
|
||||||
|
url(
|
||||||
|
r"^operation/(?P<op_id>[0-9]+)/pdf$", OperationPDFView.as_view(), name="op_pdf"
|
||||||
|
),
|
||||||
# Companies
|
# Companies
|
||||||
url(r'^company/list$', CompanyListView.as_view(), name='co_list'),
|
url(r"^company/list$", CompanyListView.as_view(), name="co_list"),
|
||||||
url(r'^company/create$', CompanyCreateView.as_view(), name='co_new'),
|
url(r"^company/create$", CompanyCreateView.as_view(), name="co_new"),
|
||||||
url(r'^company/(?P<co_id>[0-9]+)$', CompanyEditView.as_view(), name='co_edit'),
|
url(r"^company/(?P<co_id>[0-9]+)$", CompanyEditView.as_view(), name="co_edit"),
|
||||||
# Labels
|
# Labels
|
||||||
url(r'^label/new$', LabelCreateView.as_view(), name='label_new'),
|
url(r"^label/new$", LabelCreateView.as_view(), name="label_new"),
|
||||||
url(r'^label/(?P<clubaccount_id>[0-9]+)$', LabelListView.as_view(), name='label_list'),
|
url(
|
||||||
url(r'^label/(?P<label_id>[0-9]+)/edit$', LabelEditView.as_view(), name='label_edit'),
|
r"^label/(?P<clubaccount_id>[0-9]+)$",
|
||||||
url(r'^label/(?P<label_id>[0-9]+)/delete$', LabelDeleteView.as_view(), name='label_delete'),
|
LabelListView.as_view(),
|
||||||
|
name="label_list",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^label/(?P<label_id>[0-9]+)/edit$", LabelEditView.as_view(), name="label_edit"
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^label/(?P<label_id>[0-9]+)/delete$",
|
||||||
|
LabelDeleteView.as_view(),
|
||||||
|
name="label_delete",
|
||||||
|
),
|
||||||
# User account
|
# User account
|
||||||
url(r'^refound/account$', RefoundAccountView.as_view(), name='refound_account'),
|
url(r"^refound/account$", RefoundAccountView.as_view(), name="refound_account"),
|
||||||
]
|
]
|
||||||
|
@ -38,9 +38,24 @@ import collections
|
|||||||
|
|
||||||
from ajax_select.fields import AutoCompleteSelectField
|
from ajax_select.fields import AutoCompleteSelectField
|
||||||
|
|
||||||
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin
|
from core.views import (
|
||||||
|
CanViewMixin,
|
||||||
|
CanEditMixin,
|
||||||
|
CanEditPropMixin,
|
||||||
|
CanCreateMixin,
|
||||||
|
TabedViewMixin,
|
||||||
|
)
|
||||||
from core.views.forms import SelectFile, SelectDate
|
from core.views.forms import SelectFile, SelectDate
|
||||||
from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company, SimplifiedAccountingType, Label
|
from accounting.models import (
|
||||||
|
BankAccount,
|
||||||
|
ClubAccount,
|
||||||
|
GeneralJournal,
|
||||||
|
Operation,
|
||||||
|
AccountingType,
|
||||||
|
Company,
|
||||||
|
SimplifiedAccountingType,
|
||||||
|
Label,
|
||||||
|
)
|
||||||
from counter.models import Counter, Selling, Product
|
from counter.models import Counter, Selling, Product
|
||||||
|
|
||||||
# Main accounting view
|
# Main accounting view
|
||||||
@ -50,185 +65,228 @@ class BankAccountListView(CanViewMixin, ListView):
|
|||||||
"""
|
"""
|
||||||
A list view for the admins
|
A list view for the admins
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = BankAccount
|
model = BankAccount
|
||||||
template_name = 'accounting/bank_account_list.jinja'
|
template_name = "accounting/bank_account_list.jinja"
|
||||||
ordering = ['name']
|
ordering = ["name"]
|
||||||
|
|
||||||
|
|
||||||
# Simplified accounting types
|
# Simplified accounting types
|
||||||
|
|
||||||
|
|
||||||
class SimplifiedAccountingTypeListView(CanViewMixin, ListView):
|
class SimplifiedAccountingTypeListView(CanViewMixin, ListView):
|
||||||
"""
|
"""
|
||||||
A list view for the admins
|
A list view for the admins
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = SimplifiedAccountingType
|
model = SimplifiedAccountingType
|
||||||
template_name = 'accounting/simplifiedaccountingtype_list.jinja'
|
template_name = "accounting/simplifiedaccountingtype_list.jinja"
|
||||||
|
|
||||||
|
|
||||||
class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView):
|
class SimplifiedAccountingTypeEditView(CanViewMixin, UpdateView):
|
||||||
"""
|
"""
|
||||||
An edit view for the admins
|
An edit view for the admins
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = SimplifiedAccountingType
|
model = SimplifiedAccountingType
|
||||||
pk_url_kwarg = "type_id"
|
pk_url_kwarg = "type_id"
|
||||||
fields = ['label', 'accounting_type']
|
fields = ["label", "accounting_type"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
|
|
||||||
class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView):
|
class SimplifiedAccountingTypeCreateView(CanCreateMixin, CreateView):
|
||||||
"""
|
"""
|
||||||
Create an accounting type (for the admins)
|
Create an accounting type (for the admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = SimplifiedAccountingType
|
model = SimplifiedAccountingType
|
||||||
fields = ['label', 'accounting_type']
|
fields = ["label", "accounting_type"]
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
|
|
||||||
|
|
||||||
# Accounting types
|
# Accounting types
|
||||||
|
|
||||||
|
|
||||||
class AccountingTypeListView(CanViewMixin, ListView):
|
class AccountingTypeListView(CanViewMixin, ListView):
|
||||||
"""
|
"""
|
||||||
A list view for the admins
|
A list view for the admins
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = AccountingType
|
model = AccountingType
|
||||||
template_name = 'accounting/accountingtype_list.jinja'
|
template_name = "accounting/accountingtype_list.jinja"
|
||||||
|
|
||||||
|
|
||||||
class AccountingTypeEditView(CanViewMixin, UpdateView):
|
class AccountingTypeEditView(CanViewMixin, UpdateView):
|
||||||
"""
|
"""
|
||||||
An edit view for the admins
|
An edit view for the admins
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = AccountingType
|
model = AccountingType
|
||||||
pk_url_kwarg = "type_id"
|
pk_url_kwarg = "type_id"
|
||||||
fields = ['code', 'label', 'movement_type']
|
fields = ["code", "label", "movement_type"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
|
|
||||||
class AccountingTypeCreateView(CanCreateMixin, CreateView):
|
class AccountingTypeCreateView(CanCreateMixin, CreateView):
|
||||||
"""
|
"""
|
||||||
Create an accounting type (for the admins)
|
Create an accounting type (for the admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = AccountingType
|
model = AccountingType
|
||||||
fields = ['code', 'label', 'movement_type']
|
fields = ["code", "label", "movement_type"]
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
|
|
||||||
|
|
||||||
# BankAccount views
|
# BankAccount views
|
||||||
|
|
||||||
|
|
||||||
class BankAccountEditView(CanViewMixin, UpdateView):
|
class BankAccountEditView(CanViewMixin, UpdateView):
|
||||||
"""
|
"""
|
||||||
An edit view for the admins
|
An edit view for the admins
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = BankAccount
|
model = BankAccount
|
||||||
pk_url_kwarg = "b_account_id"
|
pk_url_kwarg = "b_account_id"
|
||||||
fields = ['name', 'iban', 'number', 'club']
|
fields = ["name", "iban", "number", "club"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
|
|
||||||
class BankAccountDetailView(CanViewMixin, DetailView):
|
class BankAccountDetailView(CanViewMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
A detail view, listing every club account
|
A detail view, listing every club account
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = BankAccount
|
model = BankAccount
|
||||||
pk_url_kwarg = "b_account_id"
|
pk_url_kwarg = "b_account_id"
|
||||||
template_name = 'accounting/bank_account_details.jinja'
|
template_name = "accounting/bank_account_details.jinja"
|
||||||
|
|
||||||
|
|
||||||
class BankAccountCreateView(CanCreateMixin, CreateView):
|
class BankAccountCreateView(CanCreateMixin, CreateView):
|
||||||
"""
|
"""
|
||||||
Create a bank account (for the admins)
|
Create a bank account (for the admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = BankAccount
|
model = BankAccount
|
||||||
fields = ['name', 'club', 'iban', 'number']
|
fields = ["name", "club", "iban", "number"]
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
|
|
||||||
|
|
||||||
class BankAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
|
class BankAccountDeleteView(
|
||||||
|
CanEditPropMixin, DeleteView
|
||||||
|
): # TODO change Delete to Close
|
||||||
"""
|
"""
|
||||||
Delete a bank account (for the admins)
|
Delete a bank account (for the admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = BankAccount
|
model = BankAccount
|
||||||
pk_url_kwarg = "b_account_id"
|
pk_url_kwarg = "b_account_id"
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
success_url = reverse_lazy('accounting:bank_list')
|
success_url = reverse_lazy("accounting:bank_list")
|
||||||
|
|
||||||
|
|
||||||
# ClubAccount views
|
# ClubAccount views
|
||||||
|
|
||||||
|
|
||||||
class ClubAccountEditView(CanViewMixin, UpdateView):
|
class ClubAccountEditView(CanViewMixin, UpdateView):
|
||||||
"""
|
"""
|
||||||
An edit view for the admins
|
An edit view for the admins
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClubAccount
|
model = ClubAccount
|
||||||
pk_url_kwarg = "c_account_id"
|
pk_url_kwarg = "c_account_id"
|
||||||
fields = ['name', 'club', 'bank_account']
|
fields = ["name", "club", "bank_account"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
|
|
||||||
class ClubAccountDetailView(CanViewMixin, DetailView):
|
class ClubAccountDetailView(CanViewMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
A detail view, listing every journal
|
A detail view, listing every journal
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClubAccount
|
model = ClubAccount
|
||||||
pk_url_kwarg = "c_account_id"
|
pk_url_kwarg = "c_account_id"
|
||||||
template_name = 'accounting/club_account_details.jinja'
|
template_name = "accounting/club_account_details.jinja"
|
||||||
|
|
||||||
|
|
||||||
class ClubAccountCreateView(CanCreateMixin, CreateView):
|
class ClubAccountCreateView(CanCreateMixin, CreateView):
|
||||||
"""
|
"""
|
||||||
Create a club account (for the admins)
|
Create a club account (for the admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClubAccount
|
model = ClubAccount
|
||||||
fields = ['name', 'club', 'bank_account']
|
fields = ["name", "club", "bank_account"]
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
ret = super(ClubAccountCreateView, self).get_initial()
|
ret = super(ClubAccountCreateView, self).get_initial()
|
||||||
if 'parent' in self.request.GET.keys():
|
if "parent" in self.request.GET.keys():
|
||||||
obj = BankAccount.objects.filter(id=int(self.request.GET['parent'])).first()
|
obj = BankAccount.objects.filter(id=int(self.request.GET["parent"])).first()
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
ret['bank_account'] = obj.id
|
ret["bank_account"] = obj.id
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class ClubAccountDeleteView(CanEditPropMixin, DeleteView): # TODO change Delete to Close
|
class ClubAccountDeleteView(
|
||||||
|
CanEditPropMixin, DeleteView
|
||||||
|
): # TODO change Delete to Close
|
||||||
"""
|
"""
|
||||||
Delete a club account (for the admins)
|
Delete a club account (for the admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = ClubAccount
|
model = ClubAccount
|
||||||
pk_url_kwarg = "c_account_id"
|
pk_url_kwarg = "c_account_id"
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
success_url = reverse_lazy('accounting:bank_list')
|
success_url = reverse_lazy("accounting:bank_list")
|
||||||
|
|
||||||
|
|
||||||
# Journal views
|
# Journal views
|
||||||
|
|
||||||
|
|
||||||
class JournalTabsMixin(TabedViewMixin):
|
class JournalTabsMixin(TabedViewMixin):
|
||||||
def get_tabs_title(self):
|
def get_tabs_title(self):
|
||||||
return _("Journal")
|
return _("Journal")
|
||||||
|
|
||||||
def get_list_of_tabs(self):
|
def get_list_of_tabs(self):
|
||||||
tab_list = []
|
tab_list = []
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('accounting:journal_details', kwargs={'j_id': self.object.id}),
|
{
|
||||||
'slug': 'journal',
|
"url": reverse(
|
||||||
'name': _("Journal"),
|
"accounting:journal_details", kwargs={"j_id": self.object.id}
|
||||||
})
|
),
|
||||||
tab_list.append({
|
"slug": "journal",
|
||||||
'url': reverse('accounting:journal_nature_statement', kwargs={'j_id': self.object.id}),
|
"name": _("Journal"),
|
||||||
'slug': 'nature_statement',
|
}
|
||||||
'name': _("Statement by nature"),
|
)
|
||||||
})
|
tab_list.append(
|
||||||
tab_list.append({
|
{
|
||||||
'url': reverse('accounting:journal_person_statement', kwargs={'j_id': self.object.id}),
|
"url": reverse(
|
||||||
'slug': 'person_statement',
|
"accounting:journal_nature_statement",
|
||||||
'name': _("Statement by person"),
|
kwargs={"j_id": self.object.id},
|
||||||
})
|
),
|
||||||
tab_list.append({
|
"slug": "nature_statement",
|
||||||
'url': reverse('accounting:journal_accounting_statement', kwargs={'j_id': self.object.id}),
|
"name": _("Statement by nature"),
|
||||||
'slug': 'accounting_statement',
|
}
|
||||||
'name': _("Accounting statement"),
|
)
|
||||||
})
|
tab_list.append(
|
||||||
|
{
|
||||||
|
"url": reverse(
|
||||||
|
"accounting:journal_person_statement",
|
||||||
|
kwargs={"j_id": self.object.id},
|
||||||
|
),
|
||||||
|
"slug": "person_statement",
|
||||||
|
"name": _("Statement by person"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
tab_list.append(
|
||||||
|
{
|
||||||
|
"url": reverse(
|
||||||
|
"accounting:journal_accounting_statement",
|
||||||
|
kwargs={"j_id": self.object.id},
|
||||||
|
),
|
||||||
|
"slug": "accounting_statement",
|
||||||
|
"name": _("Accounting statement"),
|
||||||
|
}
|
||||||
|
)
|
||||||
return tab_list
|
return tab_list
|
||||||
|
|
||||||
|
|
||||||
@ -236,17 +294,21 @@ class JournalCreateView(CanCreateMixin, CreateView):
|
|||||||
"""
|
"""
|
||||||
Create a general journal
|
Create a general journal
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = GeneralJournal
|
model = GeneralJournal
|
||||||
form_class = modelform_factory(GeneralJournal, fields=['name', 'start_date', 'club_account'],
|
form_class = modelform_factory(
|
||||||
widgets={'start_date': SelectDate, })
|
GeneralJournal,
|
||||||
template_name = 'core/create.jinja'
|
fields=["name", "start_date", "club_account"],
|
||||||
|
widgets={"start_date": SelectDate},
|
||||||
|
)
|
||||||
|
template_name = "core/create.jinja"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
ret = super(JournalCreateView, self).get_initial()
|
ret = super(JournalCreateView, self).get_initial()
|
||||||
if 'parent' in self.request.GET.keys():
|
if "parent" in self.request.GET.keys():
|
||||||
obj = ClubAccount.objects.filter(id=int(self.request.GET['parent'])).first()
|
obj = ClubAccount.objects.filter(id=int(self.request.GET["parent"])).first()
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
ret['club_account'] = obj.id
|
ret["club_account"] = obj.id
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@ -254,30 +316,33 @@ class JournalDetailView(JournalTabsMixin, CanViewMixin, DetailView):
|
|||||||
"""
|
"""
|
||||||
A detail view, listing every operation
|
A detail view, listing every operation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = GeneralJournal
|
model = GeneralJournal
|
||||||
pk_url_kwarg = "j_id"
|
pk_url_kwarg = "j_id"
|
||||||
template_name = 'accounting/journal_details.jinja'
|
template_name = "accounting/journal_details.jinja"
|
||||||
current_tab = 'journal'
|
current_tab = "journal"
|
||||||
|
|
||||||
|
|
||||||
class JournalEditView(CanEditMixin, UpdateView):
|
class JournalEditView(CanEditMixin, UpdateView):
|
||||||
"""
|
"""
|
||||||
Update a general journal
|
Update a general journal
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = GeneralJournal
|
model = GeneralJournal
|
||||||
pk_url_kwarg = "j_id"
|
pk_url_kwarg = "j_id"
|
||||||
fields = ['name', 'start_date', 'end_date', 'club_account', 'closed']
|
fields = ["name", "start_date", "end_date", "club_account", "closed"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
|
|
||||||
class JournalDeleteView(CanEditPropMixin, DeleteView):
|
class JournalDeleteView(CanEditPropMixin, DeleteView):
|
||||||
"""
|
"""
|
||||||
Delete a club account (for the admins)
|
Delete a club account (for the admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = GeneralJournal
|
model = GeneralJournal
|
||||||
pk_url_kwarg = "j_id"
|
pk_url_kwarg = "j_id"
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
success_url = reverse_lazy('accounting:club_details')
|
success_url = reverse_lazy("accounting:club_details")
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
@ -289,64 +354,105 @@ class JournalDeleteView(CanEditPropMixin, DeleteView):
|
|||||||
|
|
||||||
# Operation views
|
# Operation views
|
||||||
|
|
||||||
|
|
||||||
class OperationForm(forms.ModelForm):
|
class OperationForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Operation
|
model = Operation
|
||||||
fields = ['amount', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode',
|
fields = [
|
||||||
'cheque_number', 'invoice', 'simpleaccounting_type', 'accounting_type', 'label', 'done']
|
"amount",
|
||||||
|
"remark",
|
||||||
|
"journal",
|
||||||
|
"target_type",
|
||||||
|
"target_id",
|
||||||
|
"target_label",
|
||||||
|
"date",
|
||||||
|
"mode",
|
||||||
|
"cheque_number",
|
||||||
|
"invoice",
|
||||||
|
"simpleaccounting_type",
|
||||||
|
"accounting_type",
|
||||||
|
"label",
|
||||||
|
"done",
|
||||||
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'journal': HiddenInput,
|
"journal": HiddenInput,
|
||||||
'target_id': HiddenInput,
|
"target_id": HiddenInput,
|
||||||
'date': SelectDate,
|
"date": SelectDate,
|
||||||
'invoice': SelectFile,
|
"invoice": SelectFile,
|
||||||
}
|
}
|
||||||
user = AutoCompleteSelectField('users', help_text=None, required=False)
|
|
||||||
club_account = AutoCompleteSelectField('club_accounts', help_text=None, required=False)
|
user = AutoCompleteSelectField("users", help_text=None, required=False)
|
||||||
club = AutoCompleteSelectField('clubs', help_text=None, required=False)
|
club_account = AutoCompleteSelectField(
|
||||||
company = AutoCompleteSelectField('companies', help_text=None, required=False)
|
"club_accounts", help_text=None, required=False
|
||||||
need_link = forms.BooleanField(label=_("Link this operation to the target account"), required=False, initial=False)
|
)
|
||||||
|
club = AutoCompleteSelectField("clubs", help_text=None, required=False)
|
||||||
|
company = AutoCompleteSelectField("companies", help_text=None, required=False)
|
||||||
|
need_link = forms.BooleanField(
|
||||||
|
label=_("Link this operation to the target account"),
|
||||||
|
required=False,
|
||||||
|
initial=False,
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
club_account = kwargs.pop('club_account', None)
|
club_account = kwargs.pop("club_account", None)
|
||||||
super(OperationForm, self).__init__(*args, **kwargs)
|
super(OperationForm, self).__init__(*args, **kwargs)
|
||||||
if club_account:
|
if club_account:
|
||||||
self.fields['label'].queryset = club_account.labels.order_by('name').all()
|
self.fields["label"].queryset = club_account.labels.order_by("name").all()
|
||||||
if self.instance.target_type == "USER":
|
if self.instance.target_type == "USER":
|
||||||
self.fields['user'].initial = self.instance.target_id
|
self.fields["user"].initial = self.instance.target_id
|
||||||
elif self.instance.target_type == "ACCOUNT":
|
elif self.instance.target_type == "ACCOUNT":
|
||||||
self.fields['club_account'].initial = self.instance.target_id
|
self.fields["club_account"].initial = self.instance.target_id
|
||||||
elif self.instance.target_type == "CLUB":
|
elif self.instance.target_type == "CLUB":
|
||||||
self.fields['club'].initial = self.instance.target_id
|
self.fields["club"].initial = self.instance.target_id
|
||||||
elif self.instance.target_type == "COMPANY":
|
elif self.instance.target_type == "COMPANY":
|
||||||
self.fields['company'].initial = self.instance.target_id
|
self.fields["company"].initial = self.instance.target_id
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
self.cleaned_data = super(OperationForm, self).clean()
|
self.cleaned_data = super(OperationForm, self).clean()
|
||||||
if 'target_type' in self.cleaned_data.keys():
|
if "target_type" in self.cleaned_data.keys():
|
||||||
if self.cleaned_data.get("user") is None and self.cleaned_data.get("club") is None and self.cleaned_data.get("club_account") is None and self.cleaned_data.get("company") is None and self.cleaned_data.get("target_label") is None:
|
if (
|
||||||
self.add_error('target_type', ValidationError(_("The target must be set.")))
|
self.cleaned_data.get("user") is None
|
||||||
|
and self.cleaned_data.get("club") is None
|
||||||
|
and self.cleaned_data.get("club_account") is None
|
||||||
|
and self.cleaned_data.get("company") is None
|
||||||
|
and self.cleaned_data.get("target_label") is None
|
||||||
|
):
|
||||||
|
self.add_error(
|
||||||
|
"target_type", ValidationError(_("The target must be set."))
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if self.cleaned_data['target_type'] == "USER":
|
if self.cleaned_data["target_type"] == "USER":
|
||||||
self.cleaned_data['target_id'] = self.cleaned_data['user'].id
|
self.cleaned_data["target_id"] = self.cleaned_data["user"].id
|
||||||
elif self.cleaned_data['target_type'] == "ACCOUNT":
|
elif self.cleaned_data["target_type"] == "ACCOUNT":
|
||||||
self.cleaned_data['target_id'] = self.cleaned_data['club_account'].id
|
self.cleaned_data["target_id"] = self.cleaned_data[
|
||||||
elif self.cleaned_data['target_type'] == "CLUB":
|
"club_account"
|
||||||
self.cleaned_data['target_id'] = self.cleaned_data['club'].id
|
].id
|
||||||
elif self.cleaned_data['target_type'] == "COMPANY":
|
elif self.cleaned_data["target_type"] == "CLUB":
|
||||||
self.cleaned_data['target_id'] = self.cleaned_data['company'].id
|
self.cleaned_data["target_id"] = self.cleaned_data["club"].id
|
||||||
|
elif self.cleaned_data["target_type"] == "COMPANY":
|
||||||
|
self.cleaned_data["target_id"] = self.cleaned_data["company"].id
|
||||||
|
|
||||||
if self.cleaned_data.get("amount") is None:
|
if self.cleaned_data.get("amount") is None:
|
||||||
self.add_error('amount', ValidationError(_("The amount must be set.")))
|
self.add_error("amount", ValidationError(_("The amount must be set.")))
|
||||||
|
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
ret = super(OperationForm, self).save()
|
ret = super(OperationForm, self).save()
|
||||||
if self.instance.target_type == "ACCOUNT" and not self.instance.linked_operation and self.instance.target.has_open_journal() and self.cleaned_data['need_link']:
|
if (
|
||||||
|
self.instance.target_type == "ACCOUNT"
|
||||||
|
and not self.instance.linked_operation
|
||||||
|
and self.instance.target.has_open_journal()
|
||||||
|
and self.cleaned_data["need_link"]
|
||||||
|
):
|
||||||
inst = self.instance
|
inst = self.instance
|
||||||
club_account = inst.target
|
club_account = inst.target
|
||||||
acc_type = AccountingType.objects.exclude(movement_type="NEUTRAL").exclude(
|
acc_type = (
|
||||||
movement_type=inst.accounting_type.movement_type).order_by('code').first() # Select a random opposite accounting type
|
AccountingType.objects.exclude(movement_type="NEUTRAL")
|
||||||
|
.exclude(movement_type=inst.accounting_type.movement_type)
|
||||||
|
.order_by("code")
|
||||||
|
.first()
|
||||||
|
) # Select a random opposite accounting type
|
||||||
op = Operation(
|
op = Operation(
|
||||||
journal=club_account.get_open_journal(),
|
journal=club_account.get_open_journal(),
|
||||||
amount=inst.amount,
|
amount=inst.amount,
|
||||||
@ -373,26 +479,27 @@ class OperationCreateView(CanCreateMixin, CreateView):
|
|||||||
"""
|
"""
|
||||||
Create an operation
|
Create an operation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Operation
|
model = Operation
|
||||||
form_class = OperationForm
|
form_class = OperationForm
|
||||||
template_name = 'accounting/operation_edit.jinja'
|
template_name = "accounting/operation_edit.jinja"
|
||||||
|
|
||||||
def get_form(self, form_class=None):
|
def get_form(self, form_class=None):
|
||||||
self.journal = GeneralJournal.objects.filter(id=self.kwargs['j_id']).first()
|
self.journal = GeneralJournal.objects.filter(id=self.kwargs["j_id"]).first()
|
||||||
ca = self.journal.club_account if self.journal else None
|
ca = self.journal.club_account if self.journal else None
|
||||||
return self.form_class(club_account=ca, **self.get_form_kwargs())
|
return self.form_class(club_account=ca, **self.get_form_kwargs())
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
ret = super(OperationCreateView, self).get_initial()
|
ret = super(OperationCreateView, self).get_initial()
|
||||||
if self.journal is not None:
|
if self.journal is not None:
|
||||||
ret['journal'] = self.journal.id
|
ret["journal"] = self.journal.id
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
""" Add journal to the context """
|
""" Add journal to the context """
|
||||||
kwargs = super(OperationCreateView, self).get_context_data(**kwargs)
|
kwargs = super(OperationCreateView, self).get_context_data(**kwargs)
|
||||||
if self.journal:
|
if self.journal:
|
||||||
kwargs['object'] = self.journal
|
kwargs["object"] = self.journal
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -400,15 +507,16 @@ class OperationEditView(CanEditMixin, UpdateView):
|
|||||||
"""
|
"""
|
||||||
An edit view, working as detail for the moment
|
An edit view, working as detail for the moment
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Operation
|
model = Operation
|
||||||
pk_url_kwarg = "op_id"
|
pk_url_kwarg = "op_id"
|
||||||
form_class = OperationForm
|
form_class = OperationForm
|
||||||
template_name = 'accounting/operation_edit.jinja'
|
template_name = "accounting/operation_edit.jinja"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
""" Add journal to the context """
|
""" Add journal to the context """
|
||||||
kwargs = super(OperationEditView, self).get_context_data(**kwargs)
|
kwargs = super(OperationEditView, self).get_context_data(**kwargs)
|
||||||
kwargs['object'] = self.object.journal
|
kwargs["object"] = self.object.journal
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -430,7 +538,7 @@ class OperationPDFView(CanViewMixin, DetailView):
|
|||||||
from reportlab.pdfbase.ttfonts import TTFont
|
from reportlab.pdfbase.ttfonts import TTFont
|
||||||
from reportlab.pdfbase import pdfmetrics
|
from reportlab.pdfbase import pdfmetrics
|
||||||
|
|
||||||
pdfmetrics.registerFont(TTFont('DejaVu', 'DejaVuSerif.ttf'))
|
pdfmetrics.registerFont(TTFont("DejaVu", "DejaVuSerif.ttf"))
|
||||||
|
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
amount = self.object.amount
|
amount = self.object.amount
|
||||||
@ -450,11 +558,15 @@ class OperationPDFView(CanViewMixin, DetailView):
|
|||||||
else:
|
else:
|
||||||
target = self.object.target.get_display_name()
|
target = self.object.target.get_display_name()
|
||||||
|
|
||||||
response = HttpResponse(content_type='application/pdf')
|
response = HttpResponse(content_type="application/pdf")
|
||||||
response['Content-Disposition'] = 'filename="op-%d(%s_on_%s).pdf"' % (num, ti, club_name)
|
response["Content-Disposition"] = 'filename="op-%d(%s_on_%s).pdf"' % (
|
||||||
|
num,
|
||||||
|
ti,
|
||||||
|
club_name,
|
||||||
|
)
|
||||||
p = canvas.Canvas(response)
|
p = canvas.Canvas(response)
|
||||||
|
|
||||||
p.setFont('DejaVu', 12)
|
p.setFont("DejaVu", 12)
|
||||||
|
|
||||||
p.setTitle("%s %d" % (_("Operation"), num))
|
p.setTitle("%s %d" % (_("Operation"), num))
|
||||||
width, height = letter
|
width, height = letter
|
||||||
@ -466,20 +578,29 @@ class OperationPDFView(CanViewMixin, DetailView):
|
|||||||
|
|
||||||
label = Table(labelStr, colWidths=[150], rowHeights=[20])
|
label = Table(labelStr, colWidths=[150], rowHeights=[20])
|
||||||
|
|
||||||
label.setStyle(TableStyle([
|
label.setStyle(TableStyle([("ALIGN", (0, 0), (-1, -1), "RIGHT")]))
|
||||||
('ALIGN', (0, 0), (-1, -1), 'RIGHT'),
|
|
||||||
]))
|
|
||||||
w, h = label.wrapOn(label, 0, 0)
|
w, h = label.wrapOn(label, 0, 0)
|
||||||
label.drawOn(p, width - 180, height)
|
label.drawOn(p, width - 180, height)
|
||||||
|
|
||||||
p.drawString(90, height - 100, _("Financial proof: ") + "OP%010d" % (id_op)) # Justificatif du libellé
|
p.drawString(
|
||||||
p.drawString(90, height - 130, _("Club: %(club_name)s") % ({"club_name": club_name}))
|
90, height - 100, _("Financial proof: ") + "OP%010d" % (id_op)
|
||||||
p.drawString(90, height - 160, _("Label: %(op_label)s") % {"op_label": op_label if op_label is not None else ""})
|
) # Justificatif du libellé
|
||||||
|
p.drawString(
|
||||||
|
90, height - 130, _("Club: %(club_name)s") % ({"club_name": club_name})
|
||||||
|
)
|
||||||
|
p.drawString(
|
||||||
|
90,
|
||||||
|
height - 160,
|
||||||
|
_("Label: %(op_label)s")
|
||||||
|
% {"op_label": op_label if op_label is not None else ""},
|
||||||
|
)
|
||||||
p.drawString(90, height - 190, _("Date: %(date)s") % {"date": date})
|
p.drawString(90, height - 190, _("Date: %(date)s") % {"date": date})
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
data += [["%s" % (_("Credit").upper() if nature == 'CREDIT' else _("Debit").upper())]]
|
data += [
|
||||||
|
["%s" % (_("Credit").upper() if nature == "CREDIT" else _("Debit").upper())]
|
||||||
|
]
|
||||||
|
|
||||||
data += [[_("Amount: %(amount).2f €") % {"amount": amount}]]
|
data += [[_("Amount: %(amount).2f €") % {"amount": amount}]]
|
||||||
|
|
||||||
@ -493,33 +614,50 @@ class OperationPDFView(CanViewMixin, DetailView):
|
|||||||
|
|
||||||
data += [[payment_mode]]
|
data += [[payment_mode]]
|
||||||
|
|
||||||
data += [["%s : %s" % (_("Debtor") if nature == 'CREDIT' else _("Creditor"), target), ""]]
|
data += [
|
||||||
|
[
|
||||||
|
"%s : %s"
|
||||||
|
% (_("Debtor") if nature == "CREDIT" else _("Creditor"), target),
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
data += [["%s \n%s" % (_("Comment:"), remark)]]
|
data += [["%s \n%s" % (_("Comment:"), remark)]]
|
||||||
|
|
||||||
t = Table(data, colWidths=[(width - 90 * 2) / 2] * 2, rowHeights=[20, 20, 70, 20, 80])
|
t = Table(
|
||||||
t.setStyle(TableStyle([
|
data, colWidths=[(width - 90 * 2) / 2] * 2, rowHeights=[20, 20, 70, 20, 80]
|
||||||
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
)
|
||||||
('VALIGN', (-2, -1), (-1, -1), 'TOP'),
|
t.setStyle(
|
||||||
('VALIGN', (0, 0), (-1, -2), 'MIDDLE'),
|
TableStyle(
|
||||||
('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
|
[
|
||||||
('SPAN', (0, 0), (1, 0)), # line DEBIT/CREDIT
|
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
||||||
('SPAN', (0, 1), (1, 1)), # line amount
|
("VALIGN", (-2, -1), (-1, -1), "TOP"),
|
||||||
('SPAN', (-2, -1), (-1, -1)), # line comment
|
("VALIGN", (0, 0), (-1, -2), "MIDDLE"),
|
||||||
('SPAN', (0, -2), (-1, -2)), # line creditor/debtor
|
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black),
|
||||||
('SPAN', (0, 2), (1, 2)), # line payment_mode
|
("SPAN", (0, 0), (1, 0)), # line DEBIT/CREDIT
|
||||||
('ALIGN', (0, 2), (1, 2), 'LEFT'), # line payment_mode
|
("SPAN", (0, 1), (1, 1)), # line amount
|
||||||
('ALIGN', (-2, -1), (-1, -1), 'LEFT'),
|
("SPAN", (-2, -1), (-1, -1)), # line comment
|
||||||
('BOX', (0, 0), (-1, -1), 0.25, colors.black),
|
("SPAN", (0, -2), (-1, -2)), # line creditor/debtor
|
||||||
]))
|
("SPAN", (0, 2), (1, 2)), # line payment_mode
|
||||||
|
("ALIGN", (0, 2), (1, 2), "LEFT"), # line payment_mode
|
||||||
|
("ALIGN", (-2, -1), (-1, -1), "LEFT"),
|
||||||
|
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
signature = []
|
signature = []
|
||||||
signature += [[_("Signature:")]]
|
signature += [[_("Signature:")]]
|
||||||
|
|
||||||
tSig = Table(signature, colWidths=[(width - 90 * 2)], rowHeights=[80])
|
tSig = Table(signature, colWidths=[(width - 90 * 2)], rowHeights=[80])
|
||||||
tSig.setStyle(TableStyle([
|
tSig.setStyle(
|
||||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
TableStyle(
|
||||||
('BOX', (0, 0), (-1, -1), 0.25, colors.black)]))
|
[
|
||||||
|
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||||
|
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
w, h = tSig.wrapOn(p, 0, 0)
|
w, h = tSig.wrapOn(p, 0, 0)
|
||||||
tSig.drawOn(p, 90, 200)
|
tSig.drawOn(p, 90, 200)
|
||||||
@ -540,18 +678,22 @@ class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
|
|||||||
"""
|
"""
|
||||||
Display a statement sorted by labels
|
Display a statement sorted by labels
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = GeneralJournal
|
model = GeneralJournal
|
||||||
pk_url_kwarg = "j_id"
|
pk_url_kwarg = "j_id"
|
||||||
template_name = 'accounting/journal_statement_nature.jinja'
|
template_name = "accounting/journal_statement_nature.jinja"
|
||||||
current_tab = 'nature_statement'
|
current_tab = "nature_statement"
|
||||||
|
|
||||||
def statement(self, queryset, movement_type):
|
def statement(self, queryset, movement_type):
|
||||||
ret = collections.OrderedDict()
|
ret = collections.OrderedDict()
|
||||||
statement = collections.OrderedDict()
|
statement = collections.OrderedDict()
|
||||||
total_sum = 0
|
total_sum = 0
|
||||||
for sat in [None] + list(SimplifiedAccountingType.objects.order_by('label').all()):
|
for sat in [None] + list(
|
||||||
sum = queryset.filter(accounting_type__movement_type=movement_type,
|
SimplifiedAccountingType.objects.order_by("label").all()
|
||||||
simpleaccounting_type=sat).aggregate(amount_sum=Sum('amount'))['amount_sum']
|
):
|
||||||
|
sum = queryset.filter(
|
||||||
|
accounting_type__movement_type=movement_type, simpleaccounting_type=sat
|
||||||
|
).aggregate(amount_sum=Sum("amount"))["amount_sum"]
|
||||||
if sat:
|
if sat:
|
||||||
sat = sat.label
|
sat = sat.label
|
||||||
else:
|
else:
|
||||||
@ -564,7 +706,9 @@ class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
def big_statement(self):
|
def big_statement(self):
|
||||||
label_list = self.object.operations.order_by('label').values_list('label').distinct()
|
label_list = (
|
||||||
|
self.object.operations.order_by("label").values_list("label").distinct()
|
||||||
|
)
|
||||||
labels = Label.objects.filter(id__in=label_list).all()
|
labels = Label.objects.filter(id__in=label_list).all()
|
||||||
statement = collections.OrderedDict()
|
statement = collections.OrderedDict()
|
||||||
gen_statement = collections.OrderedDict()
|
gen_statement = collections.OrderedDict()
|
||||||
@ -572,20 +716,28 @@ class JournalNatureStatementView(JournalTabsMixin, CanViewMixin, DetailView):
|
|||||||
gen_statement.update(self.statement(self.object.operations.all(), "CREDIT"))
|
gen_statement.update(self.statement(self.object.operations.all(), "CREDIT"))
|
||||||
gen_statement.update(self.statement(self.object.operations.all(), "DEBIT"))
|
gen_statement.update(self.statement(self.object.operations.all(), "DEBIT"))
|
||||||
statement[_("General statement")] = gen_statement
|
statement[_("General statement")] = gen_statement
|
||||||
no_label_statement.update(self.statement(self.object.operations.filter(label=None).all(), "CREDIT"))
|
no_label_statement.update(
|
||||||
no_label_statement.update(self.statement(self.object.operations.filter(label=None).all(), "DEBIT"))
|
self.statement(self.object.operations.filter(label=None).all(), "CREDIT")
|
||||||
|
)
|
||||||
|
no_label_statement.update(
|
||||||
|
self.statement(self.object.operations.filter(label=None).all(), "DEBIT")
|
||||||
|
)
|
||||||
statement[_("No label operations")] = no_label_statement
|
statement[_("No label operations")] = no_label_statement
|
||||||
for l in labels:
|
for l in labels:
|
||||||
l_stmt = collections.OrderedDict()
|
l_stmt = collections.OrderedDict()
|
||||||
l_stmt.update(self.statement(self.object.operations.filter(label=l).all(), "CREDIT"))
|
l_stmt.update(
|
||||||
l_stmt.update(self.statement(self.object.operations.filter(label=l).all(), "DEBIT"))
|
self.statement(self.object.operations.filter(label=l).all(), "CREDIT")
|
||||||
|
)
|
||||||
|
l_stmt.update(
|
||||||
|
self.statement(self.object.operations.filter(label=l).all(), "DEBIT")
|
||||||
|
)
|
||||||
statement[l] = l_stmt
|
statement[l] = l_stmt
|
||||||
return statement
|
return statement
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
""" Add infos to the context """
|
""" Add infos to the context """
|
||||||
kwargs = super(JournalNatureStatementView, self).get_context_data(**kwargs)
|
kwargs = super(JournalNatureStatementView, self).get_context_data(**kwargs)
|
||||||
kwargs['statement'] = self.big_statement()
|
kwargs["statement"] = self.big_statement()
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -593,20 +745,29 @@ class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView):
|
|||||||
"""
|
"""
|
||||||
Calculate a dictionary with operation target and sum of operations
|
Calculate a dictionary with operation target and sum of operations
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = GeneralJournal
|
model = GeneralJournal
|
||||||
pk_url_kwarg = "j_id"
|
pk_url_kwarg = "j_id"
|
||||||
template_name = 'accounting/journal_statement_person.jinja'
|
template_name = "accounting/journal_statement_person.jinja"
|
||||||
current_tab = 'person_statement'
|
current_tab = "person_statement"
|
||||||
|
|
||||||
def sum_by_target(self, target_id, target_type, movement_type):
|
def sum_by_target(self, target_id, target_type, movement_type):
|
||||||
return self.object.operations.filter(accounting_type__movement_type=movement_type,
|
return self.object.operations.filter(
|
||||||
target_id=target_id, target_type=target_type).aggregate(amount_sum=Sum('amount'))['amount_sum']
|
accounting_type__movement_type=movement_type,
|
||||||
|
target_id=target_id,
|
||||||
|
target_type=target_type,
|
||||||
|
).aggregate(amount_sum=Sum("amount"))["amount_sum"]
|
||||||
|
|
||||||
def statement(self, movement_type):
|
def statement(self, movement_type):
|
||||||
statement = collections.OrderedDict()
|
statement = collections.OrderedDict()
|
||||||
for op in self.object.operations.filter(accounting_type__movement_type=movement_type).order_by('target_type',
|
for op in (
|
||||||
'target_id').distinct():
|
self.object.operations.filter(accounting_type__movement_type=movement_type)
|
||||||
statement[op.target] = self.sum_by_target(op.target_id, op.target_type, movement_type)
|
.order_by("target_type", "target_id")
|
||||||
|
.distinct()
|
||||||
|
):
|
||||||
|
statement[op.target] = self.sum_by_target(
|
||||||
|
op.target_id, op.target_type, movement_type
|
||||||
|
)
|
||||||
return statement
|
return statement
|
||||||
|
|
||||||
def total(self, movement_type):
|
def total(self, movement_type):
|
||||||
@ -615,10 +776,10 @@ class JournalPersonStatementView(JournalTabsMixin, CanViewMixin, DetailView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
""" Add journal to the context """
|
""" Add journal to the context """
|
||||||
kwargs = super(JournalPersonStatementView, self).get_context_data(**kwargs)
|
kwargs = super(JournalPersonStatementView, self).get_context_data(**kwargs)
|
||||||
kwargs['credit_statement'] = self.statement("CREDIT")
|
kwargs["credit_statement"] = self.statement("CREDIT")
|
||||||
kwargs['debit_statement'] = self.statement("DEBIT")
|
kwargs["debit_statement"] = self.statement("DEBIT")
|
||||||
kwargs['total_credit'] = self.total("CREDIT")
|
kwargs["total_credit"] = self.total("CREDIT")
|
||||||
kwargs['total_debit'] = self.total("DEBIT")
|
kwargs["total_debit"] = self.total("DEBIT")
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -626,16 +787,18 @@ class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView)
|
|||||||
"""
|
"""
|
||||||
Calculate a dictionary with operation type and sum of operations
|
Calculate a dictionary with operation type and sum of operations
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = GeneralJournal
|
model = GeneralJournal
|
||||||
pk_url_kwarg = "j_id"
|
pk_url_kwarg = "j_id"
|
||||||
template_name = 'accounting/journal_statement_accounting.jinja'
|
template_name = "accounting/journal_statement_accounting.jinja"
|
||||||
current_tab = "accounting_statement"
|
current_tab = "accounting_statement"
|
||||||
|
|
||||||
def statement(self):
|
def statement(self):
|
||||||
statement = collections.OrderedDict()
|
statement = collections.OrderedDict()
|
||||||
for at in AccountingType.objects.order_by('code').all():
|
for at in AccountingType.objects.order_by("code").all():
|
||||||
sum_by_type = self.object.operations.filter(
|
sum_by_type = self.object.operations.filter(
|
||||||
accounting_type__code__startswith=at.code).aggregate(amount_sum=Sum('amount'))['amount_sum']
|
accounting_type__code__startswith=at.code
|
||||||
|
).aggregate(amount_sum=Sum("amount"))["amount_sum"]
|
||||||
if sum_by_type:
|
if sum_by_type:
|
||||||
statement[at] = sum_by_type
|
statement[at] = sum_by_type
|
||||||
return statement
|
return statement
|
||||||
@ -643,86 +806,95 @@ class JournalAccountingStatementView(JournalTabsMixin, CanViewMixin, DetailView)
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
""" Add journal to the context """
|
""" Add journal to the context """
|
||||||
kwargs = super(JournalAccountingStatementView, self).get_context_data(**kwargs)
|
kwargs = super(JournalAccountingStatementView, self).get_context_data(**kwargs)
|
||||||
kwargs['statement'] = self.statement()
|
kwargs["statement"] = self.statement()
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
# Company views
|
# Company views
|
||||||
|
|
||||||
|
|
||||||
class CompanyListView(CanViewMixin, ListView):
|
class CompanyListView(CanViewMixin, ListView):
|
||||||
model = Company
|
model = Company
|
||||||
template_name = 'accounting/co_list.jinja'
|
template_name = "accounting/co_list.jinja"
|
||||||
|
|
||||||
|
|
||||||
class CompanyCreateView(CanCreateMixin, CreateView):
|
class CompanyCreateView(CanCreateMixin, CreateView):
|
||||||
"""
|
"""
|
||||||
Create a company
|
Create a company
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Company
|
model = Company
|
||||||
fields = ['name']
|
fields = ["name"]
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
success_url = reverse_lazy('accounting:co_list')
|
success_url = reverse_lazy("accounting:co_list")
|
||||||
|
|
||||||
|
|
||||||
class CompanyEditView(CanCreateMixin, UpdateView):
|
class CompanyEditView(CanCreateMixin, UpdateView):
|
||||||
"""
|
"""
|
||||||
Edit a company
|
Edit a company
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Company
|
model = Company
|
||||||
pk_url_kwarg = "co_id"
|
pk_url_kwarg = "co_id"
|
||||||
fields = ['name']
|
fields = ["name"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
success_url = reverse_lazy('accounting:co_list')
|
success_url = reverse_lazy("accounting:co_list")
|
||||||
|
|
||||||
|
|
||||||
# Label views
|
# Label views
|
||||||
|
|
||||||
|
|
||||||
class LabelListView(CanViewMixin, DetailView):
|
class LabelListView(CanViewMixin, DetailView):
|
||||||
model = ClubAccount
|
model = ClubAccount
|
||||||
pk_url_kwarg = "clubaccount_id"
|
pk_url_kwarg = "clubaccount_id"
|
||||||
template_name = 'accounting/label_list.jinja'
|
template_name = "accounting/label_list.jinja"
|
||||||
|
|
||||||
|
|
||||||
class LabelCreateView(CanCreateMixin, CreateView): # FIXME we need to check the rights before creating the object
|
class LabelCreateView(
|
||||||
|
CanCreateMixin, CreateView
|
||||||
|
): # FIXME we need to check the rights before creating the object
|
||||||
model = Label
|
model = Label
|
||||||
form_class = modelform_factory(Label, fields=['name', 'club_account'], widgets={
|
form_class = modelform_factory(
|
||||||
'club_account': HiddenInput,
|
Label, fields=["name", "club_account"], widgets={"club_account": HiddenInput}
|
||||||
})
|
)
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
ret = super(LabelCreateView, self).get_initial()
|
ret = super(LabelCreateView, self).get_initial()
|
||||||
if 'parent' in self.request.GET.keys():
|
if "parent" in self.request.GET.keys():
|
||||||
obj = ClubAccount.objects.filter(id=int(self.request.GET['parent'])).first()
|
obj = ClubAccount.objects.filter(id=int(self.request.GET["parent"])).first()
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
ret['club_account'] = obj.id
|
ret["club_account"] = obj.id
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class LabelEditView(CanEditMixin, UpdateView):
|
class LabelEditView(CanEditMixin, UpdateView):
|
||||||
model = Label
|
model = Label
|
||||||
pk_url_kwarg = "label_id"
|
pk_url_kwarg = "label_id"
|
||||||
fields = ['name']
|
fields = ["name"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
|
|
||||||
class LabelDeleteView(CanEditMixin, DeleteView):
|
class LabelDeleteView(CanEditMixin, DeleteView):
|
||||||
model = Label
|
model = Label
|
||||||
pk_url_kwarg = "label_id"
|
pk_url_kwarg = "label_id"
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return self.object.get_absolute_url()
|
return self.object.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
class CloseCustomerAccountForm(forms.Form):
|
class CloseCustomerAccountForm(forms.Form):
|
||||||
user = AutoCompleteSelectField('users', label=_('Refound this account'), help_text=None, required=True)
|
user = AutoCompleteSelectField(
|
||||||
|
"users", label=_("Refound this account"), help_text=None, required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RefoundAccountView(FormView):
|
class RefoundAccountView(FormView):
|
||||||
"""
|
"""
|
||||||
Create a selling with the same amount than the current user money
|
Create a selling with the same amount than the current user money
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template_name = "accounting/refound_account.jinja"
|
template_name = "accounting/refound_account.jinja"
|
||||||
form_class = CloseCustomerAccountForm
|
form_class = CloseCustomerAccountForm
|
||||||
|
|
||||||
@ -743,21 +915,28 @@ class RefoundAccountView(FormView):
|
|||||||
return super(RefoundAccountView, self).post(self, request, *arg, **kwargs)
|
return super(RefoundAccountView, self).post(self, request, *arg, **kwargs)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
self.customer = form.cleaned_data['user']
|
self.customer = form.cleaned_data["user"]
|
||||||
self.create_selling()
|
self.create_selling()
|
||||||
return super(RefoundAccountView, self).form_valid(form)
|
return super(RefoundAccountView, self).form_valid(form)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse('accounting:refound_account')
|
return reverse("accounting:refound_account")
|
||||||
|
|
||||||
def create_selling(self):
|
def create_selling(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
uprice = self.customer.customer.amount
|
uprice = self.customer.customer.amount
|
||||||
refound_club_counter = Counter.objects.get(id=settings.SITH_COUNTER_REFOUND_ID)
|
refound_club_counter = Counter.objects.get(
|
||||||
|
id=settings.SITH_COUNTER_REFOUND_ID
|
||||||
|
)
|
||||||
refound_club = refound_club_counter.club
|
refound_club = refound_club_counter.club
|
||||||
s = Selling(label=_('Refound account'), unit_price=uprice,
|
s = Selling(
|
||||||
quantity=1, seller=self.operator,
|
label=_("Refound account"),
|
||||||
|
unit_price=uprice,
|
||||||
|
quantity=1,
|
||||||
|
seller=self.operator,
|
||||||
customer=self.customer.customer,
|
customer=self.customer.customer,
|
||||||
club=refound_club, counter=refound_club_counter,
|
club=refound_club,
|
||||||
product=Product.objects.get(id=settings.SITH_PRODUCT_REFOUND_ID))
|
counter=refound_club_counter,
|
||||||
|
product=Product.objects.get(id=settings.SITH_PRODUCT_REFOUND_ID),
|
||||||
|
)
|
||||||
s.save()
|
s.save()
|
||||||
|
@ -21,4 +21,3 @@
|
|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
35
api/urls.py
35
api/urls.py
@ -29,25 +29,28 @@ from rest_framework import routers
|
|||||||
|
|
||||||
# Router config
|
# Router config
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register(r'counter', CounterViewSet, base_name='api_counter')
|
router.register(r"counter", CounterViewSet, base_name="api_counter")
|
||||||
router.register(r'user', UserViewSet, base_name='api_user')
|
router.register(r"user", UserViewSet, base_name="api_user")
|
||||||
router.register(r'club', ClubViewSet, base_name='api_club')
|
router.register(r"club", ClubViewSet, base_name="api_club")
|
||||||
router.register(r'group', GroupViewSet, base_name='api_group')
|
router.register(r"group", GroupViewSet, base_name="api_group")
|
||||||
|
|
||||||
# Launderette
|
# Launderette
|
||||||
router.register(r'launderette/place', LaunderettePlaceViewSet,
|
router.register(
|
||||||
base_name='api_launderette_place')
|
r"launderette/place", LaunderettePlaceViewSet, base_name="api_launderette_place"
|
||||||
router.register(r'launderette/machine', LaunderetteMachineViewSet,
|
)
|
||||||
base_name='api_launderette_machine')
|
router.register(
|
||||||
router.register(r'launderette/token', LaunderetteTokenViewSet,
|
r"launderette/machine",
|
||||||
base_name='api_launderette_token')
|
LaunderetteMachineViewSet,
|
||||||
|
base_name="api_launderette_machine",
|
||||||
|
)
|
||||||
|
router.register(
|
||||||
|
r"launderette/token", LaunderetteTokenViewSet, base_name="api_launderette_token"
|
||||||
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
||||||
# API
|
# API
|
||||||
url(r'^', include(router.urls)),
|
url(r"^", include(router.urls)),
|
||||||
url(r'^login/', include('rest_framework.urls', namespace='rest_framework')),
|
url(r"^login/", include("rest_framework.urls", namespace="rest_framework")),
|
||||||
url(r'^markdown$', RenderMarkdown, name='api_markdown'),
|
url(r"^markdown$", RenderMarkdown, name="api_markdown"),
|
||||||
url(r'^mailings$', FetchMailingLists, name='mailings_fetch')
|
url(r"^mailings$", FetchMailingLists, name="mailings_fetch"),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -30,19 +30,21 @@ from django.db.models.query import QuerySet
|
|||||||
|
|
||||||
from core.views import can_view, can_edit
|
from core.views import can_view, can_edit
|
||||||
|
|
||||||
|
|
||||||
def check_if(obj, user, test):
|
def check_if(obj, user, test):
|
||||||
"""
|
"""
|
||||||
Detect if it's a single object or a queryset
|
Detect if it's a single object or a queryset
|
||||||
aply a given test on individual object and return global permission
|
aply a given test on individual object and return global permission
|
||||||
"""
|
"""
|
||||||
if (isinstance(obj, QuerySet)):
|
if isinstance(obj, QuerySet):
|
||||||
for o in obj:
|
for o in obj:
|
||||||
if (test(o, user) is False):
|
if test(o, user) is False:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return test(obj, user)
|
return test(obj, user)
|
||||||
|
|
||||||
|
|
||||||
class ManageModelMixin:
|
class ManageModelMixin:
|
||||||
@detail_route()
|
@detail_route()
|
||||||
def id(self, request, pk=None):
|
def id(self, request, pk=None):
|
||||||
@ -53,19 +55,19 @@ class ManageModelMixin:
|
|||||||
serializer = self.get_serializer(self.queryset)
|
serializer = self.get_serializer(self.queryset)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
class RightModelViewSet(ManageModelMixin, viewsets.ModelViewSet):
|
|
||||||
|
|
||||||
|
class RightModelViewSet(ManageModelMixin, viewsets.ModelViewSet):
|
||||||
def dispatch(self, request, *arg, **kwargs):
|
def dispatch(self, request, *arg, **kwargs):
|
||||||
res = super(RightModelViewSet,
|
res = super(RightModelViewSet, self).dispatch(request, *arg, **kwargs)
|
||||||
self).dispatch(request, *arg, **kwargs)
|
|
||||||
obj = self.queryset
|
obj = self.queryset
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
try:
|
try:
|
||||||
if (request.method == 'GET' and check_if(obj, user, can_view)):
|
if request.method == "GET" and check_if(obj, user, can_view):
|
||||||
return res
|
return res
|
||||||
if (request.method != 'GET' and check_if(obj, user, can_edit)):
|
if request.method != "GET" and check_if(obj, user, can_edit):
|
||||||
return res
|
return res
|
||||||
except: pass # To prevent bug with Anonymous user
|
except:
|
||||||
|
pass # To prevent bug with Anonymous user
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,15 +30,14 @@ from rest_framework.views import APIView
|
|||||||
from core.templatetags.renderer import markdown
|
from core.templatetags.renderer import markdown
|
||||||
|
|
||||||
|
|
||||||
@api_view(['POST'])
|
@api_view(["POST"])
|
||||||
@renderer_classes((StaticHTMLRenderer,))
|
@renderer_classes((StaticHTMLRenderer,))
|
||||||
def RenderMarkdown(request):
|
def RenderMarkdown(request):
|
||||||
"""
|
"""
|
||||||
Render Markdown
|
Render Markdown
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
data = markdown(request.POST['text'])
|
data = markdown(request.POST["text"])
|
||||||
except:
|
except:
|
||||||
data = 'Error'
|
data = "Error"
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
@ -36,10 +36,9 @@ from api.views import RightModelViewSet
|
|||||||
|
|
||||||
|
|
||||||
class ClubSerializer(serializers.ModelSerializer):
|
class ClubSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Club
|
model = Club
|
||||||
fields = ('id', 'name', 'unix_name', 'address', 'members')
|
fields = ("id", "name", "unix_name", "address", "members")
|
||||||
|
|
||||||
|
|
||||||
class ClubViewSet(RightModelViewSet):
|
class ClubViewSet(RightModelViewSet):
|
||||||
@ -51,13 +50,15 @@ class ClubViewSet(RightModelViewSet):
|
|||||||
queryset = Club.objects.all()
|
queryset = Club.objects.all()
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(["GET"])
|
||||||
@renderer_classes((StaticHTMLRenderer,))
|
@renderer_classes((StaticHTMLRenderer,))
|
||||||
def FetchMailingLists(request):
|
def FetchMailingLists(request):
|
||||||
key = request.GET.get('key', '')
|
key = request.GET.get("key", "")
|
||||||
if key != settings.SITH_MAILING_FETCH_KEY:
|
if key != settings.SITH_MAILING_FETCH_KEY:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
data = ''
|
data = ""
|
||||||
for mailing in Mailing.objects.filter(is_moderated=True, club__is_active=True).all():
|
for mailing in Mailing.objects.filter(
|
||||||
|
is_moderated=True, club__is_active=True
|
||||||
|
).all():
|
||||||
data += mailing.fetch_format() + "\n"
|
data += mailing.fetch_format() + "\n"
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
@ -35,14 +35,12 @@ class CounterSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
is_open = serializers.BooleanField(read_only=True)
|
is_open = serializers.BooleanField(read_only=True)
|
||||||
barman_list = serializers.ListField(
|
barman_list = serializers.ListField(
|
||||||
child=serializers.IntegerField(),
|
child=serializers.IntegerField(), read_only=True
|
||||||
read_only=True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Counter
|
model = Counter
|
||||||
fields = ('id', 'name', 'type', 'club',
|
fields = ("id", "name", "type", "club", "products", "is_open", "barman_list")
|
||||||
'products', 'is_open', 'barman_list')
|
|
||||||
|
|
||||||
|
|
||||||
class CounterViewSet(RightModelViewSet):
|
class CounterViewSet(RightModelViewSet):
|
||||||
|
@ -30,7 +30,6 @@ from api.views import RightModelViewSet
|
|||||||
|
|
||||||
|
|
||||||
class GroupSerializer(serializers.ModelSerializer):
|
class GroupSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RealGroup
|
model = RealGroup
|
||||||
|
|
||||||
|
@ -30,34 +30,45 @@ from launderette.models import Launderette, Machine, Token
|
|||||||
|
|
||||||
from api.views import RightModelViewSet
|
from api.views import RightModelViewSet
|
||||||
|
|
||||||
|
|
||||||
class LaunderettePlaceSerializer(serializers.ModelSerializer):
|
class LaunderettePlaceSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
machine_list = serializers.ListField(
|
machine_list = serializers.ListField(
|
||||||
child=serializers.IntegerField(),
|
child=serializers.IntegerField(), read_only=True
|
||||||
read_only=True
|
|
||||||
)
|
|
||||||
token_list = serializers.ListField(
|
|
||||||
child=serializers.IntegerField(),
|
|
||||||
read_only=True
|
|
||||||
)
|
)
|
||||||
|
token_list = serializers.ListField(child=serializers.IntegerField(), read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Launderette
|
model = Launderette
|
||||||
fields = ('id', 'name', 'counter', 'machine_list',
|
fields = (
|
||||||
'token_list', 'get_absolute_url')
|
"id",
|
||||||
|
"name",
|
||||||
|
"counter",
|
||||||
|
"machine_list",
|
||||||
|
"token_list",
|
||||||
|
"get_absolute_url",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LaunderetteMachineSerializer(serializers.ModelSerializer):
|
class LaunderetteMachineSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Machine
|
model = Machine
|
||||||
fields = ('id', 'name', 'type', 'is_working', 'launderette')
|
fields = ("id", "name", "type", "is_working", "launderette")
|
||||||
|
|
||||||
|
|
||||||
class LaunderetteTokenSerializer(serializers.ModelSerializer):
|
class LaunderetteTokenSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Token
|
model = Token
|
||||||
fields = ('id', 'name', 'type', 'launderette', 'borrow_date',
|
fields = (
|
||||||
'user', 'is_avaliable')
|
"id",
|
||||||
|
"name",
|
||||||
|
"type",
|
||||||
|
"launderette",
|
||||||
|
"borrow_date",
|
||||||
|
"user",
|
||||||
|
"is_avaliable",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LaunderettePlaceViewSet(RightModelViewSet):
|
class LaunderettePlaceViewSet(RightModelViewSet):
|
||||||
"""
|
"""
|
||||||
@ -67,6 +78,7 @@ class LaunderettePlaceViewSet(RightModelViewSet):
|
|||||||
serializer_class = LaunderettePlaceSerializer
|
serializer_class = LaunderettePlaceSerializer
|
||||||
queryset = Launderette.objects.all()
|
queryset = Launderette.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class LaunderetteMachineViewSet(RightModelViewSet):
|
class LaunderetteMachineViewSet(RightModelViewSet):
|
||||||
"""
|
"""
|
||||||
Manage Washing Machines (api/v1/launderette/machine/)
|
Manage Washing Machines (api/v1/launderette/machine/)
|
||||||
@ -89,7 +101,7 @@ class LaunderetteTokenViewSet(RightModelViewSet):
|
|||||||
"""
|
"""
|
||||||
Return all washing tokens (api/v1/launderette/token/washing)
|
Return all washing tokens (api/v1/launderette/token/washing)
|
||||||
"""
|
"""
|
||||||
self.queryset = self.queryset.filter(type='WASHING')
|
self.queryset = self.queryset.filter(type="WASHING")
|
||||||
serializer = self.get_serializer(self.queryset, many=True)
|
serializer = self.get_serializer(self.queryset, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@ -98,7 +110,7 @@ class LaunderetteTokenViewSet(RightModelViewSet):
|
|||||||
"""
|
"""
|
||||||
Return all drying tokens (api/v1/launderette/token/drying)
|
Return all drying tokens (api/v1/launderette/token/drying)
|
||||||
"""
|
"""
|
||||||
self.queryset = self.queryset.filter(type='DRYING')
|
self.queryset = self.queryset.filter(type="DRYING")
|
||||||
serializer = self.get_serializer(self.queryset, many=True)
|
serializer = self.get_serializer(self.queryset, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@ -107,7 +119,9 @@ class LaunderetteTokenViewSet(RightModelViewSet):
|
|||||||
"""
|
"""
|
||||||
Return all avaliable tokens (api/v1/launderette/token/avaliable)
|
Return all avaliable tokens (api/v1/launderette/token/avaliable)
|
||||||
"""
|
"""
|
||||||
self.queryset = self.queryset.filter(borrow_date__isnull=True, user__isnull=True)
|
self.queryset = self.queryset.filter(
|
||||||
|
borrow_date__isnull=True, user__isnull=True
|
||||||
|
)
|
||||||
serializer = self.get_serializer(self.queryset, many=True)
|
serializer = self.get_serializer(self.queryset, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
@ -116,6 +130,8 @@ class LaunderetteTokenViewSet(RightModelViewSet):
|
|||||||
"""
|
"""
|
||||||
Return all unavaliable tokens (api/v1/launderette/token/unavaliable)
|
Return all unavaliable tokens (api/v1/launderette/token/unavaliable)
|
||||||
"""
|
"""
|
||||||
self.queryset = self.queryset.filter(borrow_date__isnull=False, user__isnull=False)
|
self.queryset = self.queryset.filter(
|
||||||
|
borrow_date__isnull=False, user__isnull=False
|
||||||
|
)
|
||||||
serializer = self.get_serializer(self.queryset, many=True)
|
serializer = self.get_serializer(self.queryset, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
@ -34,11 +34,18 @@ from api.views import RightModelViewSet
|
|||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ('id', 'first_name', 'last_name', 'email',
|
fields = (
|
||||||
'date_of_birth', 'nick_name', 'is_active', 'date_joined')
|
"id",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"email",
|
||||||
|
"date_of_birth",
|
||||||
|
"nick_name",
|
||||||
|
"is_active",
|
||||||
|
"date_joined",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(RightModelViewSet):
|
class UserViewSet(RightModelViewSet):
|
||||||
|
@ -21,4 +21,3 @@
|
|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -7,28 +7,92 @@ import django.core.validators
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = []
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Club',
|
name="Club",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('name', models.CharField(max_length=64, verbose_name='name')),
|
"id",
|
||||||
('unix_name', models.CharField(unique=True, max_length=30, error_messages={'unique': 'A club with that unix name already exists.'}, verbose_name='unix name', validators=[django.core.validators.RegexValidator('^[a-z0-9][a-z0-9._-]*[a-z0-9]$', 'Enter a valid unix name. This value may contain only letters, numbers ./-/_ characters.')])),
|
models.AutoField(
|
||||||
('address', models.CharField(max_length=254, verbose_name='address')),
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=64, verbose_name="name")),
|
||||||
|
(
|
||||||
|
"unix_name",
|
||||||
|
models.CharField(
|
||||||
|
unique=True,
|
||||||
|
max_length=30,
|
||||||
|
error_messages={
|
||||||
|
"unique": "A club with that unix name already exists."
|
||||||
|
},
|
||||||
|
verbose_name="unix name",
|
||||||
|
validators=[
|
||||||
|
django.core.validators.RegexValidator(
|
||||||
|
"^[a-z0-9][a-z0-9._-]*[a-z0-9]$",
|
||||||
|
"Enter a valid unix name. This value may contain only letters, numbers ./-/_ characters.",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("address", models.CharField(max_length=254, verbose_name="address")),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Membership',
|
name="Membership",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('start_date', models.DateField(verbose_name='start date', auto_now=True)),
|
"id",
|
||||||
('end_date', models.DateField(null=True, verbose_name='end date', blank=True)),
|
models.AutoField(
|
||||||
('role', models.IntegerField(choices=[(0, 'Curious'), (1, 'Active member'), (2, 'Board member'), (3, 'IT supervisor'), (4, 'Secretary'), (5, 'Communication supervisor'), (7, 'Treasurer'), (9, 'Vice-President'), (10, 'President')], default=0, verbose_name='role')),
|
primary_key=True,
|
||||||
('description', models.CharField(max_length=128, blank=True, verbose_name='description')),
|
serialize=False,
|
||||||
('club', models.ForeignKey(verbose_name='club', to='club.Club', related_name='members')),
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"start_date",
|
||||||
|
models.DateField(verbose_name="start date", auto_now=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"end_date",
|
||||||
|
models.DateField(null=True, verbose_name="end date", blank=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"role",
|
||||||
|
models.IntegerField(
|
||||||
|
choices=[
|
||||||
|
(0, "Curious"),
|
||||||
|
(1, "Active member"),
|
||||||
|
(2, "Board member"),
|
||||||
|
(3, "IT supervisor"),
|
||||||
|
(4, "Secretary"),
|
||||||
|
(5, "Communication supervisor"),
|
||||||
|
(7, "Treasurer"),
|
||||||
|
(9, "Vice-President"),
|
||||||
|
(10, "President"),
|
||||||
|
],
|
||||||
|
default=0,
|
||||||
|
verbose_name="role",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"description",
|
||||||
|
models.CharField(
|
||||||
|
max_length=128, blank=True, verbose_name="description"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"club",
|
||||||
|
models.ForeignKey(
|
||||||
|
verbose_name="club", to="club.Club", related_name="members"
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -9,39 +9,57 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
('club', '0001_initial'),
|
("club", "0001_initial"),
|
||||||
('core', '0001_initial'),
|
("core", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='membership',
|
model_name="membership",
|
||||||
name='user',
|
name="user",
|
||||||
field=models.ForeignKey(verbose_name='user', to=settings.AUTH_USER_MODEL, related_name='membership'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="user",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
related_name="membership",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='edit_groups',
|
name="edit_groups",
|
||||||
field=models.ManyToManyField(to='core.Group', blank=True, related_name='editable_club'),
|
field=models.ManyToManyField(
|
||||||
|
to="core.Group", blank=True, related_name="editable_club"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='home',
|
name="home",
|
||||||
field=models.OneToOneField(blank=True, null=True, related_name='home_of_club', verbose_name='home', to='core.SithFile'),
|
field=models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name="home_of_club",
|
||||||
|
verbose_name="home",
|
||||||
|
to="core.SithFile",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='owner_group',
|
name="owner_group",
|
||||||
field=models.ForeignKey(default=1, to='core.Group', related_name='owned_club'),
|
field=models.ForeignKey(
|
||||||
|
default=1, to="core.Group", related_name="owned_club"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='parent',
|
name="parent",
|
||||||
field=models.ForeignKey(null=True, to='club.Club', related_name='children', blank=True),
|
field=models.ForeignKey(
|
||||||
|
null=True, to="club.Club", related_name="children", blank=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='view_groups',
|
name="view_groups",
|
||||||
field=models.ManyToManyField(to='core.Group', blank=True, related_name='viewable_club'),
|
field=models.ManyToManyField(
|
||||||
|
to="core.Group", blank=True, related_name="viewable_club"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0002_auto_20160824_2152")]
|
||||||
('club', '0002_auto_20160824_2152'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='membership',
|
model_name="membership",
|
||||||
name='start_date',
|
name="start_date",
|
||||||
field=models.DateField(verbose_name='start date'),
|
field=models.DateField(verbose_name="start date"),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,16 @@ from django.conf import settings
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0003_auto_20160902_2042")]
|
||||||
('club', '0003_auto_20160902_2042'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='membership',
|
model_name="membership",
|
||||||
name='user',
|
name="user",
|
||||||
field=models.ForeignKey(verbose_name='user', related_name='memberships', to=settings.AUTH_USER_MODEL),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="user",
|
||||||
|
related_name="memberships",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,19 @@ import django.db.models.deletion
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0004_auto_20160915_1057")]
|
||||||
('club', '0004_auto_20160915_1057'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='home',
|
name="home",
|
||||||
field=models.OneToOneField(related_name='home_of_club', blank=True, on_delete=django.db.models.deletion.SET_NULL, verbose_name='home', null=True, to='core.SithFile'),
|
field=models.OneToOneField(
|
||||||
|
related_name="home_of_club",
|
||||||
|
blank=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
verbose_name="home",
|
||||||
|
null=True,
|
||||||
|
to="core.SithFile",
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,14 @@ import django.utils.timezone
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0005_auto_20161120_1149")]
|
||||||
('club', '0005_auto_20161120_1149'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='membership',
|
model_name="membership",
|
||||||
name='start_date',
|
name="start_date",
|
||||||
field=models.DateField(verbose_name='start date', default=django.utils.timezone.now),
|
field=models.DateField(
|
||||||
|
verbose_name="start date", default=django.utils.timezone.now
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,13 +6,10 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0006_auto_20161229_0040")]
|
||||||
('club', '0006_auto_20161229_0040'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterModelOptions(
|
migrations.AlterModelOptions(
|
||||||
name='club',
|
name="club", options={"ordering": ["name", "unix_name"]}
|
||||||
options={'ordering': ['name', 'unix_name']},
|
)
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0007_auto_20170324_0917")]
|
||||||
('club', '0007_auto_20170324_0917'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='id',
|
name="id",
|
||||||
field=models.AutoField(primary_key=True, serialize=False, db_index=True),
|
field=models.AutoField(primary_key=True, serialize=False, db_index=True),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
@ -11,31 +11,98 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
('club', '0008_auto_20170515_2214'),
|
("club", "0008_auto_20170515_2214"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Mailing',
|
name="Mailing",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
|
(
|
||||||
('email', models.CharField(max_length=256, unique=True, validators=[django.core.validators.RegexValidator(re.compile('(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+)*\\Z|^"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*"\\Z)', 34), 'Enter a valid address. Only the root of the address is needed.')], verbose_name='Email address')),
|
"id",
|
||||||
('is_moderated', models.BooleanField(default=False, verbose_name='is moderated')),
|
models.AutoField(
|
||||||
('club', models.ForeignKey(verbose_name='Club', related_name='mailings', to='club.Club')),
|
auto_created=True,
|
||||||
('moderator', models.ForeignKey(null=True, verbose_name='moderator', related_name='moderated_mailings', to=settings.AUTH_USER_MODEL)),
|
verbose_name="ID",
|
||||||
|
serialize=False,
|
||||||
|
primary_key=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"email",
|
||||||
|
models.CharField(
|
||||||
|
max_length=256,
|
||||||
|
unique=True,
|
||||||
|
validators=[
|
||||||
|
django.core.validators.RegexValidator(
|
||||||
|
re.compile(
|
||||||
|
"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\\Z|^\"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*\"\\Z)",
|
||||||
|
34,
|
||||||
|
),
|
||||||
|
"Enter a valid address. Only the root of the address is needed.",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
verbose_name="Email address",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_moderated",
|
||||||
|
models.BooleanField(default=False, verbose_name="is moderated"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"club",
|
||||||
|
models.ForeignKey(
|
||||||
|
verbose_name="Club", related_name="mailings", to="club.Club"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"moderator",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
verbose_name="moderator",
|
||||||
|
related_name="moderated_mailings",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='MailingSubscription',
|
name="MailingSubscription",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
|
(
|
||||||
('email', models.EmailField(max_length=254, verbose_name='Email address')),
|
"id",
|
||||||
('mailing', models.ForeignKey(verbose_name='Mailing', related_name='subscriptions', to='club.Mailing')),
|
models.AutoField(
|
||||||
('user', models.ForeignKey(null=True, verbose_name='User', related_name='mailing_subscriptions', blank=True, to=settings.AUTH_USER_MODEL)),
|
auto_created=True,
|
||||||
|
verbose_name="ID",
|
||||||
|
serialize=False,
|
||||||
|
primary_key=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"email",
|
||||||
|
models.EmailField(max_length=254, verbose_name="Email address"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"mailing",
|
||||||
|
models.ForeignKey(
|
||||||
|
verbose_name="Mailing",
|
||||||
|
related_name="subscriptions",
|
||||||
|
to="club.Mailing",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
verbose_name="User",
|
||||||
|
related_name="mailing_subscriptions",
|
||||||
|
blank=True,
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
migrations.AlterUniqueTogether(
|
||||||
name='mailingsubscription',
|
name="mailingsubscription",
|
||||||
unique_together=set([('user', 'email', 'mailing')]),
|
unique_together=set([("user", "email", "mailing")]),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -12,34 +12,44 @@ def generate_club_pages(apps, schema_editor):
|
|||||||
club.make_page()
|
club.make_page()
|
||||||
for child in Club.objects.filter(parent=club).all():
|
for child in Club.objects.filter(parent=club).all():
|
||||||
recursive_generate_club_page(child)
|
recursive_generate_club_page(child)
|
||||||
|
|
||||||
for club in Club.objects.filter(parent=None).all():
|
for club in Club.objects.filter(parent=None).all():
|
||||||
recursive_generate_club_page(club)
|
recursive_generate_club_page(club)
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0024_auto_20170906_1317"), ("club", "0010_club_logo")]
|
||||||
('core', '0024_auto_20170906_1317'),
|
|
||||||
('club', '0010_club_logo'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='is_active',
|
name="is_active",
|
||||||
field=models.BooleanField(default=True, verbose_name='is active'),
|
field=models.BooleanField(default=True, verbose_name="is active"),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='page',
|
name="page",
|
||||||
field=models.OneToOneField(related_name='club', blank=True, null=True, to='core.Page'),
|
field=models.OneToOneField(
|
||||||
|
related_name="club", blank=True, null=True, to="core.Page"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='short_description',
|
name="short_description",
|
||||||
field=models.CharField(verbose_name='short description', max_length=1000, default='', blank=True, null=True),
|
field=models.CharField(
|
||||||
|
verbose_name="short description",
|
||||||
|
max_length=1000,
|
||||||
|
default="",
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PsqlRunOnly(
|
||||||
|
"SET CONSTRAINTS ALL IMMEDIATE", reverse_sql=migrations.RunSQL.noop
|
||||||
),
|
),
|
||||||
PsqlRunOnly('SET CONSTRAINTS ALL IMMEDIATE', reverse_sql=migrations.RunSQL.noop),
|
|
||||||
migrations.RunPython(generate_club_pages),
|
migrations.RunPython(generate_club_pages),
|
||||||
PsqlRunOnly(migrations.RunSQL.noop, reverse_sql='SET CONSTRAINTS ALL IMMEDIATE'),
|
PsqlRunOnly(
|
||||||
|
migrations.RunSQL.noop, reverse_sql="SET CONSTRAINTS ALL IMMEDIATE"
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,14 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0009_auto_20170822_2232")]
|
||||||
('club', '0009_auto_20170822_2232'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='logo',
|
name="logo",
|
||||||
field=models.ImageField(null=True, upload_to='club_logos', blank=True, verbose_name='logo'),
|
field=models.ImageField(
|
||||||
|
null=True, upload_to="club_logos", blank=True, verbose_name="logo"
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,16 @@ import club.models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("club", "0010_auto_20170912_2028")]
|
||||||
('club', '0010_auto_20170912_2028'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='club',
|
model_name="club",
|
||||||
name='owner_group',
|
name="owner_group",
|
||||||
field=models.ForeignKey(default=club.models.Club.get_default_owner_group, related_name='owned_club', to='core.Group'),
|
field=models.ForeignKey(
|
||||||
|
default=club.models.Club.get_default_owner_group,
|
||||||
|
related_name="owned_club",
|
||||||
|
to="core.Group",
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
229
club/models.py
229
club/models.py
@ -43,40 +43,64 @@ class Club(models.Model):
|
|||||||
"""
|
"""
|
||||||
The Club class, made as a tree to allow nice tidy organization
|
The Club class, made as a tree to allow nice tidy organization
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id = models.AutoField(primary_key=True, db_index=True)
|
id = models.AutoField(primary_key=True, db_index=True)
|
||||||
name = models.CharField(_('name'), max_length=64)
|
name = models.CharField(_("name"), max_length=64)
|
||||||
parent = models.ForeignKey('Club', related_name='children', null=True, blank=True)
|
parent = models.ForeignKey("Club", related_name="children", null=True, blank=True)
|
||||||
unix_name = models.CharField(_('unix name'), max_length=30, unique=True,
|
unix_name = models.CharField(
|
||||||
|
_("unix name"),
|
||||||
|
max_length=30,
|
||||||
|
unique=True,
|
||||||
validators=[
|
validators=[
|
||||||
validators.RegexValidator(
|
validators.RegexValidator(
|
||||||
r'^[a-z0-9][a-z0-9._-]*[a-z0-9]$',
|
r"^[a-z0-9][a-z0-9._-]*[a-z0-9]$",
|
||||||
_('Enter a valid unix name. This value may contain only '
|
_(
|
||||||
'letters, numbers ./-/_ characters.')
|
"Enter a valid unix name. This value may contain only "
|
||||||
|
"letters, numbers ./-/_ characters."
|
||||||
),
|
),
|
||||||
],
|
|
||||||
error_messages={
|
|
||||||
'unique': _("A club with that unix name already exists."),
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
logo = models.ImageField(upload_to='club_logos', verbose_name=_('logo'), null=True, blank=True)
|
],
|
||||||
is_active = models.BooleanField(_('is active'), default=True)
|
error_messages={"unique": _("A club with that unix name already exists.")},
|
||||||
short_description = models.CharField(_('short description'), max_length=1000, default='', blank=True, null=True)
|
)
|
||||||
address = models.CharField(_('address'), max_length=254)
|
logo = models.ImageField(
|
||||||
|
upload_to="club_logos", verbose_name=_("logo"), null=True, blank=True
|
||||||
|
)
|
||||||
|
is_active = models.BooleanField(_("is active"), default=True)
|
||||||
|
short_description = models.CharField(
|
||||||
|
_("short description"), max_length=1000, default="", blank=True, null=True
|
||||||
|
)
|
||||||
|
address = models.CharField(_("address"), max_length=254)
|
||||||
# This function prevents generating migration upon settings change
|
# This function prevents generating migration upon settings change
|
||||||
def get_default_owner_group(): return settings.SITH_GROUP_ROOT_ID
|
def get_default_owner_group():
|
||||||
owner_group = models.ForeignKey(Group, related_name="owned_club", default=get_default_owner_group)
|
return settings.SITH_GROUP_ROOT_ID
|
||||||
edit_groups = models.ManyToManyField(Group, related_name="editable_club", blank=True)
|
|
||||||
view_groups = models.ManyToManyField(Group, related_name="viewable_club", blank=True)
|
owner_group = models.ForeignKey(
|
||||||
home = models.OneToOneField(SithFile, related_name='home_of_club', verbose_name=_("home"), null=True, blank=True,
|
Group, related_name="owned_club", default=get_default_owner_group
|
||||||
on_delete=models.SET_NULL)
|
)
|
||||||
|
edit_groups = models.ManyToManyField(
|
||||||
|
Group, related_name="editable_club", blank=True
|
||||||
|
)
|
||||||
|
view_groups = models.ManyToManyField(
|
||||||
|
Group, related_name="viewable_club", blank=True
|
||||||
|
)
|
||||||
|
home = models.OneToOneField(
|
||||||
|
SithFile,
|
||||||
|
related_name="home_of_club",
|
||||||
|
verbose_name=_("home"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
)
|
||||||
page = models.OneToOneField(Page, related_name="club", blank=True, null=True)
|
page = models.OneToOneField(Page, related_name="club", blank=True, null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name', 'unix_name']
|
ordering = ["name", "unix_name"]
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def president(self):
|
def president(self):
|
||||||
return self.members.filter(role=settings.SITH_CLUB_ROLES_ID['President'], end_date=None).first()
|
return self.members.filter(
|
||||||
|
role=settings.SITH_CLUB_ROLES_ID["President"], end_date=None
|
||||||
|
).first()
|
||||||
|
|
||||||
def check_loop(self):
|
def check_loop(self):
|
||||||
"""Raise a validation error when a loop is found within the parent list"""
|
"""Raise a validation error when a loop is found within the parent list"""
|
||||||
@ -84,7 +108,7 @@ class Club(models.Model):
|
|||||||
cur = self
|
cur = self
|
||||||
while cur.parent is not None:
|
while cur.parent is not None:
|
||||||
if cur in objs:
|
if cur in objs:
|
||||||
raise ValidationError(_('You can not make loops in clubs'))
|
raise ValidationError(_("You can not make loops in clubs"))
|
||||||
objs.append(cur)
|
objs.append(cur)
|
||||||
cur = cur.parent
|
cur = cur.parent
|
||||||
|
|
||||||
@ -130,7 +154,12 @@ class Club(models.Model):
|
|||||||
self.page.unset_lock()
|
self.page.unset_lock()
|
||||||
self.page.name = self.unix_name
|
self.page.name = self.unix_name
|
||||||
self.page.save(force_lock=True)
|
self.page.save(force_lock=True)
|
||||||
elif self.page and self.parent and self.parent.page and self.page.parent != self.parent.page:
|
elif (
|
||||||
|
self.page
|
||||||
|
and self.parent
|
||||||
|
and self.parent.page
|
||||||
|
and self.page.parent != self.parent.page
|
||||||
|
):
|
||||||
self.page.unset_lock()
|
self.page.unset_lock()
|
||||||
self.page.parent = self.parent.page
|
self.page.parent = self.parent.page
|
||||||
self.page.save(force_lock=True)
|
self.page.save(force_lock=True)
|
||||||
@ -150,7 +179,9 @@ class Club(models.Model):
|
|||||||
board.save()
|
board.save()
|
||||||
member = MetaGroup(name=self.unix_name + settings.SITH_MEMBER_SUFFIX)
|
member = MetaGroup(name=self.unix_name + settings.SITH_MEMBER_SUFFIX)
|
||||||
member.save()
|
member.save()
|
||||||
subscribers = Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first()
|
subscribers = Group.objects.filter(
|
||||||
|
name=settings.SITH_MAIN_MEMBERS_GROUP
|
||||||
|
).first()
|
||||||
self.make_home()
|
self.make_home()
|
||||||
self.home.edit_groups = [board]
|
self.home.edit_groups = [board]
|
||||||
self.home.view_groups = [member, subscribers]
|
self.home.view_groups = [member, subscribers]
|
||||||
@ -161,7 +192,7 @@ class Club(models.Model):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('club:club_view', kwargs={'club_id': self.id})
|
return reverse("club:club_view", kwargs={"club_id": self.id})
|
||||||
|
|
||||||
def get_display_name(self):
|
def get_display_name(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -223,24 +254,48 @@ class Membership(models.Model):
|
|||||||
A User is currently member of all the Clubs where its Membership has an end_date set to null/None.
|
A User is currently member of all the Clubs where its Membership has an end_date set to null/None.
|
||||||
Otherwise, it's a past membership kept because it can be very useful to see who was in which Club in the past.
|
Otherwise, it's a past membership kept because it can be very useful to see who was in which Club in the past.
|
||||||
"""
|
"""
|
||||||
user = models.ForeignKey(User, verbose_name=_('user'), related_name="memberships", null=False, blank=False)
|
|
||||||
club = models.ForeignKey(Club, verbose_name=_('club'), related_name="members", null=False, blank=False)
|
user = models.ForeignKey(
|
||||||
start_date = models.DateField(_('start date'), default=timezone.now)
|
User,
|
||||||
end_date = models.DateField(_('end date'), null=True, blank=True)
|
verbose_name=_("user"),
|
||||||
role = models.IntegerField(_('role'), choices=sorted(settings.SITH_CLUB_ROLES.items()),
|
related_name="memberships",
|
||||||
default=sorted(settings.SITH_CLUB_ROLES.items())[0][0])
|
null=False,
|
||||||
description = models.CharField(_('description'), max_length=128, null=False, blank=True)
|
blank=False,
|
||||||
|
)
|
||||||
|
club = models.ForeignKey(
|
||||||
|
Club, verbose_name=_("club"), related_name="members", null=False, blank=False
|
||||||
|
)
|
||||||
|
start_date = models.DateField(_("start date"), default=timezone.now)
|
||||||
|
end_date = models.DateField(_("end date"), null=True, blank=True)
|
||||||
|
role = models.IntegerField(
|
||||||
|
_("role"),
|
||||||
|
choices=sorted(settings.SITH_CLUB_ROLES.items()),
|
||||||
|
default=sorted(settings.SITH_CLUB_ROLES.items())[0][0],
|
||||||
|
)
|
||||||
|
description = models.CharField(
|
||||||
|
_("description"), max_length=128, null=False, blank=True
|
||||||
|
)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
sub = User.objects.filter(pk=self.user.pk).first()
|
sub = User.objects.filter(pk=self.user.pk).first()
|
||||||
if sub is None or not sub.is_subscribed:
|
if sub is None or not sub.is_subscribed:
|
||||||
raise ValidationError(_('User must be subscriber to take part to a club'))
|
raise ValidationError(_("User must be subscriber to take part to a club"))
|
||||||
if Membership.objects.filter(user=self.user).filter(club=self.club).filter(end_date=None).exists():
|
if (
|
||||||
raise ValidationError(_('User is already member of that club'))
|
Membership.objects.filter(user=self.user)
|
||||||
|
.filter(club=self.club)
|
||||||
|
.filter(end_date=None)
|
||||||
|
.exists()
|
||||||
|
):
|
||||||
|
raise ValidationError(_("User is already member of that club"))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.club.name + ' - ' + self.user.username + ' - ' + str(settings.SITH_CLUB_ROLES[self.role]) + str(
|
return (
|
||||||
" - " + str(_('past member')) if self.end_date is not None else ""
|
self.club.name
|
||||||
|
+ " - "
|
||||||
|
+ self.user.username
|
||||||
|
+ " - "
|
||||||
|
+ str(settings.SITH_CLUB_ROLES[self.role])
|
||||||
|
+ str(" - " + str(_("past member")) if self.end_date is not None else "")
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
@ -255,11 +310,13 @@ class Membership(models.Model):
|
|||||||
"""
|
"""
|
||||||
if user.memberships:
|
if user.memberships:
|
||||||
ms = user.memberships.filter(club=self.club, end_date=None).first()
|
ms = user.memberships.filter(club=self.club, end_date=None).first()
|
||||||
return (ms and ms.role >= self.role) or user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
|
return (ms and ms.role >= self.role) or user.is_in_group(
|
||||||
|
settings.SITH_MAIN_BOARD_GROUP
|
||||||
|
)
|
||||||
return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
|
return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('club:club_members', kwargs={'club_id': self.club.id})
|
return reverse("club:club_members", kwargs={"club_id": self.club.id})
|
||||||
|
|
||||||
|
|
||||||
class Mailing(models.Model):
|
class Mailing(models.Model):
|
||||||
@ -267,14 +324,27 @@ class Mailing(models.Model):
|
|||||||
This class correspond to a mailing list
|
This class correspond to a mailing list
|
||||||
Remember that mailing lists should be validated by UTBM
|
Remember that mailing lists should be validated by UTBM
|
||||||
"""
|
"""
|
||||||
club = models.ForeignKey(Club, verbose_name=_('Club'), related_name="mailings", null=False, blank=False)
|
|
||||||
email = models.CharField(_('Email address'), unique=True, null=False, blank=False, max_length=256,
|
club = models.ForeignKey(
|
||||||
|
Club, verbose_name=_("Club"), related_name="mailings", null=False, blank=False
|
||||||
|
)
|
||||||
|
email = models.CharField(
|
||||||
|
_("Email address"),
|
||||||
|
unique=True,
|
||||||
|
null=False,
|
||||||
|
blank=False,
|
||||||
|
max_length=256,
|
||||||
validators=[
|
validators=[
|
||||||
RegexValidator(validate_email.user_regex,
|
RegexValidator(
|
||||||
_('Enter a valid address. Only the root of the address is needed.'))
|
validate_email.user_regex,
|
||||||
])
|
_("Enter a valid address. Only the root of the address is needed."),
|
||||||
is_moderated = models.BooleanField(_('is moderated'), default=False)
|
)
|
||||||
moderator = models.ForeignKey(User, related_name="moderated_mailings", verbose_name=_("moderator"), null=True)
|
],
|
||||||
|
)
|
||||||
|
is_moderated = models.BooleanField(_("is moderated"), default=False)
|
||||||
|
moderator = models.ForeignKey(
|
||||||
|
User, related_name="moderated_mailings", verbose_name=_("moderator"), null=True
|
||||||
|
)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if self.can_moderate(self.moderator):
|
if self.can_moderate(self.moderator):
|
||||||
@ -285,13 +355,17 @@ class Mailing(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def email_full(self):
|
def email_full(self):
|
||||||
return self.email + '@' + settings.SITH_MAILING_DOMAIN
|
return self.email + "@" + settings.SITH_MAILING_DOMAIN
|
||||||
|
|
||||||
def can_moderate(self, user):
|
def can_moderate(self, user):
|
||||||
return user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(self) or user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return (
|
||||||
|
user.is_in_group(self)
|
||||||
|
or user.is_root
|
||||||
|
or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
)
|
||||||
|
|
||||||
def can_view(self, user):
|
def can_view(self, user):
|
||||||
return self.club.has_rights_in_club(user)
|
return self.club.has_rights_in_club(user)
|
||||||
@ -305,16 +379,26 @@ class Mailing(models.Model):
|
|||||||
super(Mailing, self).delete()
|
super(Mailing, self).delete()
|
||||||
|
|
||||||
def fetch_format(self):
|
def fetch_format(self):
|
||||||
resp = self.email + ': '
|
resp = self.email + ": "
|
||||||
for sub in self.subscriptions.all():
|
for sub in self.subscriptions.all():
|
||||||
resp += sub.fetch_format()
|
resp += sub.fetch_format()
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
if not self.is_moderated:
|
if not self.is_moderated:
|
||||||
for user in RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first().users.all():
|
for user in (
|
||||||
if not user.notifications.filter(type="MAILING_MODERATION", viewed=False).exists():
|
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
Notification(user=user, url=reverse('com:mailing_admin'), type="MAILING_MODERATION").save()
|
.first()
|
||||||
|
.users.all()
|
||||||
|
):
|
||||||
|
if not user.notifications.filter(
|
||||||
|
type="MAILING_MODERATION", viewed=False
|
||||||
|
).exists():
|
||||||
|
Notification(
|
||||||
|
user=user,
|
||||||
|
url=reverse("com:mailing_admin"),
|
||||||
|
type="MAILING_MODERATION",
|
||||||
|
).save()
|
||||||
super(Mailing, self).save()
|
super(Mailing, self).save()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -325,12 +409,25 @@ class MailingSubscription(models.Model):
|
|||||||
"""
|
"""
|
||||||
This class makes the link between user and mailing list
|
This class makes the link between user and mailing list
|
||||||
"""
|
"""
|
||||||
mailing = models.ForeignKey(Mailing, verbose_name=_('Mailing'), related_name="subscriptions", null=False, blank=False)
|
|
||||||
user = models.ForeignKey(User, verbose_name=_('User'), related_name="mailing_subscriptions", null=True, blank=True)
|
mailing = models.ForeignKey(
|
||||||
email = models.EmailField(_('Email address'), blank=False, null=False)
|
Mailing,
|
||||||
|
verbose_name=_("Mailing"),
|
||||||
|
related_name="subscriptions",
|
||||||
|
null=False,
|
||||||
|
blank=False,
|
||||||
|
)
|
||||||
|
user = models.ForeignKey(
|
||||||
|
User,
|
||||||
|
verbose_name=_("User"),
|
||||||
|
related_name="mailing_subscriptions",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
email = models.EmailField(_("Email address"), blank=False, null=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (('user', 'email', 'mailing'),)
|
unique_together = (("user", "email", "mailing"),)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if not self.user and not self.email:
|
if not self.user and not self.email:
|
||||||
@ -338,17 +435,25 @@ class MailingSubscription(models.Model):
|
|||||||
try:
|
try:
|
||||||
if self.user and not self.email:
|
if self.user and not self.email:
|
||||||
self.email = self.user.email
|
self.email = self.user.email
|
||||||
if MailingSubscription.objects.filter(mailing=self.mailing, email=self.email).exists():
|
if MailingSubscription.objects.filter(
|
||||||
raise ValidationError(_("This email is already suscribed in this mailing"))
|
mailing=self.mailing, email=self.email
|
||||||
|
).exists():
|
||||||
|
raise ValidationError(
|
||||||
|
_("This email is already suscribed in this mailing")
|
||||||
|
)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
pass
|
pass
|
||||||
super(MailingSubscription, self).clean()
|
super(MailingSubscription, self).clean()
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return self.mailing.club.has_rights_in_club(user) or user.is_root or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return (
|
||||||
|
self.mailing.club.has_rights_in_club(user)
|
||||||
|
or user.is_root
|
||||||
|
or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
)
|
||||||
|
|
||||||
def can_be_edited_by(self, user):
|
def can_be_edited_by(self, user):
|
||||||
return (self.user is not None and user.id == self.user.id)
|
return self.user is not None and user.id == self.user.id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_email(self):
|
def get_email(self):
|
||||||
@ -357,7 +462,7 @@ class MailingSubscription(models.Model):
|
|||||||
return self.email
|
return self.email
|
||||||
|
|
||||||
def fetch_format(self):
|
def fetch_format(self):
|
||||||
return self.get_email + ' '
|
return self.get_email + " "
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.user:
|
if self.user:
|
||||||
|
124
club/tests.py
124
club/tests.py
@ -41,66 +41,92 @@ class ClubTest(TestCase):
|
|||||||
self.bdf = Club.objects.filter(unix_name="bdf").first()
|
self.bdf = Club.objects.filter(unix_name="bdf").first()
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_root_ok(self):
|
def test_create_add_user_to_club_from_root_ok(self):
|
||||||
self.client.login(username='root', password='plop')
|
self.client.login(username="root", password="plop")
|
||||||
self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
self.client.post(
|
||||||
"user": self.skia.id,
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
"start_date": "12/06/2016",
|
{"user": self.skia.id, "start_date": "12/06/2016", "role": 3},
|
||||||
"role": 3})
|
)
|
||||||
response = self.client.get(reverse("club:club_members", kwargs={"club_id": self.bdf.id}))
|
response = self.client.get(
|
||||||
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue("S' Kia</a></td>\\n <td>Responsable info</td>" in str(response.content))
|
self.assertTrue(
|
||||||
|
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_root_fail_not_subscriber(self):
|
def test_create_add_user_to_club_from_root_fail_not_subscriber(self):
|
||||||
self.client.login(username='root', password='plop')
|
self.client.login(username="root", password="plop")
|
||||||
response = self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
response = self.client.post(
|
||||||
"user": self.guy.id,
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
"start_date": "12/06/2016",
|
{"user": self.guy.id, "start_date": "12/06/2016", "role": 3},
|
||||||
"role": 3})
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('<ul class="errorlist nonfield"><li>' in str(response.content))
|
self.assertTrue('<ul class="errorlist nonfield"><li>' in str(response.content))
|
||||||
response = self.client.get(reverse("club:club_members", kwargs={"club_id": self.bdf.id}))
|
response = self.client.get(
|
||||||
self.assertFalse("Guy Carlier</a></td>\\n <td>Responsable info</td>" in str(response.content))
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
||||||
|
)
|
||||||
|
self.assertFalse(
|
||||||
|
"Guy Carlier</a></td>\\n <td>Responsable info</td>"
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_root_fail_already_in_club(self):
|
def test_create_add_user_to_club_from_root_fail_already_in_club(self):
|
||||||
self.client.login(username='root', password='plop')
|
self.client.login(username="root", password="plop")
|
||||||
self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
self.client.post(
|
||||||
"user": self.skia.id,
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
"start_date": "12/06/2016",
|
{"user": self.skia.id, "start_date": "12/06/2016", "role": 3},
|
||||||
"role": 3})
|
)
|
||||||
response = self.client.get(reverse("club:club_members", kwargs={"club_id": self.bdf.id}))
|
response = self.client.get(
|
||||||
self.assertTrue("S' Kia</a></td>\\n <td>Responsable info</td>" in str(response.content))
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
||||||
response = self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
)
|
||||||
"user": self.skia.id,
|
self.assertTrue(
|
||||||
"start_date": "12/06/2016",
|
"S' Kia</a></td>\\n <td>Responsable info</td>"
|
||||||
"role": 4})
|
in str(response.content)
|
||||||
|
)
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
|
{"user": self.skia.id, "start_date": "12/06/2016", "role": 4},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertFalse("S' Kia</a></td>\\n <td>Secrétaire</td>" in str(response.content))
|
self.assertFalse(
|
||||||
|
"S' Kia</a></td>\\n <td>Secrétaire</td>"
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_skia_ok(self):
|
def test_create_add_user_to_club_from_skia_ok(self):
|
||||||
self.client.login(username='root', password='plop')
|
self.client.login(username="root", password="plop")
|
||||||
self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
self.client.post(
|
||||||
"user": self.skia.id,
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
"start_date": "12/06/2016",
|
{"user": self.skia.id, "start_date": "12/06/2016", "role": 10},
|
||||||
"role": 10})
|
)
|
||||||
self.client.login(username='skia', password='plop')
|
self.client.login(username="skia", password="plop")
|
||||||
self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
self.client.post(
|
||||||
"user": self.rbatsbak.id,
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
"start_date": "12/06/2016",
|
{"user": self.rbatsbak.id, "start_date": "12/06/2016", "role": 9},
|
||||||
"role": 9})
|
)
|
||||||
response = self.client.get(reverse("club:club_members", kwargs={"club_id": self.bdf.id}))
|
response = self.client.get(
|
||||||
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id})
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue("""Richard Batsbak</a></td>\\n <td>Vice-Pr\\xc3\\xa9sident</td>""" in str(response.content))
|
self.assertTrue(
|
||||||
|
"""Richard Batsbak</a></td>\\n <td>Vice-Pr\\xc3\\xa9sident</td>"""
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_create_add_user_to_club_from_richard_fail(self):
|
def test_create_add_user_to_club_from_richard_fail(self):
|
||||||
self.client.login(username='root', password='plop')
|
self.client.login(username="root", password="plop")
|
||||||
self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
self.client.post(
|
||||||
"user": self.rbatsbak.id,
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
"start_date": "12/06/2016",
|
{"user": self.rbatsbak.id, "start_date": "12/06/2016", "role": 3},
|
||||||
"role": 3})
|
)
|
||||||
self.client.login(username='rbatsbak', password='plop')
|
self.client.login(username="rbatsbak", password="plop")
|
||||||
response = self.client.post(reverse("club:club_members", kwargs={"club_id": self.bdf.id}), {
|
response = self.client.post(
|
||||||
"user": self.skia.id,
|
reverse("club:club_members", kwargs={"club_id": self.bdf.id}),
|
||||||
"start_date": "12/06/2016",
|
{"user": self.skia.id, "start_date": "12/06/2016", "role": 10},
|
||||||
"role": 10})
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue("<li>Vous n'avez pas la permission de faire cela</li>" in str(response.content))
|
self.assertTrue(
|
||||||
|
"<li>Vous n'avez pas la permission de faire cela</li>"
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
118
club/urls.py
118
club/urls.py
@ -28,30 +28,96 @@ from django.conf.urls import url
|
|||||||
from club.views import *
|
from club.views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', ClubListView.as_view(), name='club_list'),
|
url(r"^$", ClubListView.as_view(), name="club_list"),
|
||||||
url(r'^new$', ClubCreateView.as_view(), name='club_new'),
|
url(r"^new$", ClubCreateView.as_view(), name="club_new"),
|
||||||
url(r'^stats$', ClubStatView.as_view(), name='club_stats'),
|
url(r"^stats$", ClubStatView.as_view(), name="club_stats"),
|
||||||
url(r'^(?P<club_id>[0-9]+)/$', ClubView.as_view(), name='club_view'),
|
url(r"^(?P<club_id>[0-9]+)/$", ClubView.as_view(), name="club_view"),
|
||||||
url(r'^(?P<club_id>[0-9]+)/rev/(?P<rev_id>[0-9]+)/$', ClubRevView.as_view(), name='club_view_rev'),
|
url(
|
||||||
url(r'^(?P<club_id>[0-9]+)/hist$', ClubPageHistView.as_view(), name='club_hist'),
|
r"^(?P<club_id>[0-9]+)/rev/(?P<rev_id>[0-9]+)/$",
|
||||||
url(r'^(?P<club_id>[0-9]+)/edit$', ClubEditView.as_view(), name='club_edit'),
|
ClubRevView.as_view(),
|
||||||
url(r'^(?P<club_id>[0-9]+)/edit/page$', ClubPageEditView.as_view(), name='club_edit_page'),
|
name="club_view_rev",
|
||||||
url(r'^(?P<club_id>[0-9]+)/members$', ClubMembersView.as_view(), name='club_members'),
|
),
|
||||||
url(r'^(?P<club_id>[0-9]+)/elderlies$', ClubOldMembersView.as_view(), name='club_old_members'),
|
url(r"^(?P<club_id>[0-9]+)/hist$", ClubPageHistView.as_view(), name="club_hist"),
|
||||||
url(r'^(?P<club_id>[0-9]+)/sellings$', ClubSellingView.as_view(), name='club_sellings'),
|
url(r"^(?P<club_id>[0-9]+)/edit$", ClubEditView.as_view(), name="club_edit"),
|
||||||
url(r'^(?P<club_id>[0-9]+)/sellings/csv$', ClubSellingCSVView.as_view(), name='sellings_csv'),
|
url(
|
||||||
url(r'^(?P<club_id>[0-9]+)/prop$', ClubEditPropView.as_view(), name='club_prop'),
|
r"^(?P<club_id>[0-9]+)/edit/page$",
|
||||||
url(r'^(?P<club_id>[0-9]+)/tools$', ClubToolsView.as_view(), name='tools'),
|
ClubPageEditView.as_view(),
|
||||||
url(r'^(?P<club_id>[0-9]+)/mailing$', ClubMailingView.as_view(action="display"), name='mailing'),
|
name="club_edit_page",
|
||||||
url(r'^(?P<club_id>[0-9]+)/mailing/new/mailing$', ClubMailingView.as_view(action="add_mailing"), name='mailing_create'),
|
),
|
||||||
url(r'^(?P<club_id>[0-9]+)/mailing/new/subscription$', ClubMailingView.as_view(action="add_member"), name='mailing_subscription_create'),
|
url(
|
||||||
url(r'^(?P<mailing_id>[0-9]+)/mailing/generate$', MailingAutoGenerationView.as_view(), name='mailing_generate'),
|
r"^(?P<club_id>[0-9]+)/members$", ClubMembersView.as_view(), name="club_members"
|
||||||
url(r'^(?P<mailing_id>[0-9]+)/mailing/clean$', MailingAutoCleanView.as_view(), name='mailing_clean'),
|
),
|
||||||
url(r'^(?P<mailing_id>[0-9]+)/mailing/delete$', MailingDeleteView.as_view(), name='mailing_delete'),
|
url(
|
||||||
url(r'^(?P<mailing_subscription_id>[0-9]+)/mailing/delete/subscription$', MailingSubscriptionDeleteView.as_view(), name='mailing_subscription_delete'),
|
r"^(?P<club_id>[0-9]+)/elderlies$",
|
||||||
url(r'^membership/(?P<membership_id>[0-9]+)/set_old$', MembershipSetOldView.as_view(), name='membership_set_old'),
|
ClubOldMembersView.as_view(),
|
||||||
url(r'^(?P<club_id>[0-9]+)/poster$', PosterListView.as_view(), name='poster_list'),
|
name="club_old_members",
|
||||||
url(r'^(?P<club_id>[0-9]+)/poster/create$', PosterCreateView.as_view(), name='poster_create'),
|
),
|
||||||
url(r'^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/edit$', PosterEditView.as_view(), name='poster_edit'),
|
url(
|
||||||
url(r'^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/delete$', PosterDeleteView.as_view(), name='poster_delete'),
|
r"^(?P<club_id>[0-9]+)/sellings$",
|
||||||
|
ClubSellingView.as_view(),
|
||||||
|
name="club_sellings",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<club_id>[0-9]+)/sellings/csv$",
|
||||||
|
ClubSellingCSVView.as_view(),
|
||||||
|
name="sellings_csv",
|
||||||
|
),
|
||||||
|
url(r"^(?P<club_id>[0-9]+)/prop$", ClubEditPropView.as_view(), name="club_prop"),
|
||||||
|
url(r"^(?P<club_id>[0-9]+)/tools$", ClubToolsView.as_view(), name="tools"),
|
||||||
|
url(
|
||||||
|
r"^(?P<club_id>[0-9]+)/mailing$",
|
||||||
|
ClubMailingView.as_view(action="display"),
|
||||||
|
name="mailing",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<club_id>[0-9]+)/mailing/new/mailing$",
|
||||||
|
ClubMailingView.as_view(action="add_mailing"),
|
||||||
|
name="mailing_create",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<club_id>[0-9]+)/mailing/new/subscription$",
|
||||||
|
ClubMailingView.as_view(action="add_member"),
|
||||||
|
name="mailing_subscription_create",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<mailing_id>[0-9]+)/mailing/generate$",
|
||||||
|
MailingAutoGenerationView.as_view(),
|
||||||
|
name="mailing_generate",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<mailing_id>[0-9]+)/mailing/clean$",
|
||||||
|
MailingAutoCleanView.as_view(),
|
||||||
|
name="mailing_clean",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<mailing_id>[0-9]+)/mailing/delete$",
|
||||||
|
MailingDeleteView.as_view(),
|
||||||
|
name="mailing_delete",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<mailing_subscription_id>[0-9]+)/mailing/delete/subscription$",
|
||||||
|
MailingSubscriptionDeleteView.as_view(),
|
||||||
|
name="mailing_subscription_delete",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^membership/(?P<membership_id>[0-9]+)/set_old$",
|
||||||
|
MembershipSetOldView.as_view(),
|
||||||
|
name="membership_set_old",
|
||||||
|
),
|
||||||
|
url(r"^(?P<club_id>[0-9]+)/poster$", PosterListView.as_view(), name="poster_list"),
|
||||||
|
url(
|
||||||
|
r"^(?P<club_id>[0-9]+)/poster/create$",
|
||||||
|
PosterCreateView.as_view(),
|
||||||
|
name="poster_create",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/edit$",
|
||||||
|
PosterEditView.as_view(),
|
||||||
|
name="poster_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^(?P<club_id>[0-9]+)/poster/(?P<poster_id>[0-9]+)/delete$",
|
||||||
|
PosterDeleteView.as_view(),
|
||||||
|
name="poster_delete",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
488
club/views.py
488
club/views.py
@ -37,13 +37,25 @@ from ajax_select.fields import AutoCompleteSelectField
|
|||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
|
|
||||||
from core.views import CanCreateMixin, CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, PageEditViewBase
|
from core.views import (
|
||||||
|
CanCreateMixin,
|
||||||
|
CanViewMixin,
|
||||||
|
CanEditMixin,
|
||||||
|
CanEditPropMixin,
|
||||||
|
TabedViewMixin,
|
||||||
|
PageEditViewBase,
|
||||||
|
)
|
||||||
from core.views.forms import SelectDate, SelectDateTime
|
from core.views.forms import SelectDate, SelectDateTime
|
||||||
from club.models import Club, Membership, Mailing, MailingSubscription
|
from club.models import Club, Membership, Mailing, MailingSubscription
|
||||||
from sith.settings import SITH_MAXIMUM_FREE_ROLE
|
from sith.settings import SITH_MAXIMUM_FREE_ROLE
|
||||||
from counter.models import Selling, Counter
|
from counter.models import Selling, Counter
|
||||||
from core.models import User, PageRev
|
from core.models import User, PageRev
|
||||||
from com.views import PosterListBaseView, PosterCreateBaseView, PosterEditBaseView, PosterDeleteBaseView
|
from com.views import (
|
||||||
|
PosterListBaseView,
|
||||||
|
PosterCreateBaseView,
|
||||||
|
PosterEditBaseView,
|
||||||
|
PosterDeleteBaseView,
|
||||||
|
)
|
||||||
from com.models import Poster
|
from com.models import Poster
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -54,7 +66,7 @@ from django.conf import settings
|
|||||||
class ClubEditForm(forms.ModelForm):
|
class ClubEditForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Club
|
model = Club
|
||||||
fields = ['address', 'logo', 'short_description']
|
fields = ["address", "logo", "short_description"]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ClubEditForm, self).__init__(*args, **kwargs)
|
super(ClubEditForm, self).__init__(*args, **kwargs)
|
||||||
@ -64,36 +76,40 @@ class ClubEditForm(forms.ModelForm):
|
|||||||
class MailingForm(forms.ModelForm):
|
class MailingForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Mailing
|
model = Mailing
|
||||||
fields = ('email', 'club', 'moderator')
|
fields = ("email", "club", "moderator")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
club_id = kwargs.pop('club_id', None)
|
club_id = kwargs.pop("club_id", None)
|
||||||
user_id = kwargs.pop('user_id', -1) # Remember 0 is treated as None
|
user_id = kwargs.pop("user_id", -1) # Remember 0 is treated as None
|
||||||
super(MailingForm, self).__init__(*args, **kwargs)
|
super(MailingForm, self).__init__(*args, **kwargs)
|
||||||
if club_id:
|
if club_id:
|
||||||
self.fields['club'].queryset = Club.objects.filter(id=club_id)
|
self.fields["club"].queryset = Club.objects.filter(id=club_id)
|
||||||
self.fields['club'].initial = club_id
|
self.fields["club"].initial = club_id
|
||||||
self.fields['club'].widget = forms.HiddenInput()
|
self.fields["club"].widget = forms.HiddenInput()
|
||||||
if user_id >= 0:
|
if user_id >= 0:
|
||||||
self.fields['moderator'].queryset = User.objects.filter(id=user_id)
|
self.fields["moderator"].queryset = User.objects.filter(id=user_id)
|
||||||
self.fields['moderator'].initial = user_id
|
self.fields["moderator"].initial = user_id
|
||||||
self.fields['moderator'].widget = forms.HiddenInput()
|
self.fields["moderator"].widget = forms.HiddenInput()
|
||||||
|
|
||||||
|
|
||||||
class MailingSubscriptionForm(forms.ModelForm):
|
class MailingSubscriptionForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = MailingSubscription
|
model = MailingSubscription
|
||||||
fields = ('mailing', 'user', 'email')
|
fields = ("mailing", "user", "email")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs.pop('user_id', None) # For standart interface
|
kwargs.pop("user_id", None) # For standart interface
|
||||||
club_id = kwargs.pop('club_id', None)
|
club_id = kwargs.pop("club_id", None)
|
||||||
super(MailingSubscriptionForm, self).__init__(*args, **kwargs)
|
super(MailingSubscriptionForm, self).__init__(*args, **kwargs)
|
||||||
self.fields['email'].required = False
|
self.fields["email"].required = False
|
||||||
if club_id:
|
if club_id:
|
||||||
self.fields['mailing'].queryset = Mailing.objects.filter(club__id=club_id, is_moderated=True)
|
self.fields["mailing"].queryset = Mailing.objects.filter(
|
||||||
|
club__id=club_id, is_moderated=True
|
||||||
|
)
|
||||||
|
|
||||||
user = AutoCompleteSelectField('users', label=_('User'), help_text=None, required=False)
|
user = AutoCompleteSelectField(
|
||||||
|
"users", label=_("User"), help_text=None, required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ClubTabsMixin(TabedViewMixin):
|
class ClubTabsMixin(TabedViewMixin):
|
||||||
@ -105,66 +121,105 @@ class ClubTabsMixin(TabedViewMixin):
|
|||||||
|
|
||||||
def get_list_of_tabs(self):
|
def get_list_of_tabs(self):
|
||||||
tab_list = []
|
tab_list = []
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('club:club_view', kwargs={'club_id': self.object.id}),
|
{
|
||||||
'slug': 'infos',
|
"url": reverse("club:club_view", kwargs={"club_id": self.object.id}),
|
||||||
'name': _("Infos"),
|
"slug": "infos",
|
||||||
})
|
"name": _("Infos"),
|
||||||
|
}
|
||||||
|
)
|
||||||
if self.request.user.can_view(self.object):
|
if self.request.user.can_view(self.object):
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('club:club_members', kwargs={'club_id': self.object.id}),
|
{
|
||||||
'slug': 'members',
|
"url": reverse(
|
||||||
'name': _("Members"),
|
"club:club_members", kwargs={"club_id": self.object.id}
|
||||||
})
|
),
|
||||||
tab_list.append({
|
"slug": "members",
|
||||||
'url': reverse('club:club_old_members', kwargs={'club_id': self.object.id}),
|
"name": _("Members"),
|
||||||
'slug': 'elderlies',
|
}
|
||||||
'name': _("Old members"),
|
)
|
||||||
})
|
tab_list.append(
|
||||||
|
{
|
||||||
|
"url": reverse(
|
||||||
|
"club:club_old_members", kwargs={"club_id": self.object.id}
|
||||||
|
),
|
||||||
|
"slug": "elderlies",
|
||||||
|
"name": _("Old members"),
|
||||||
|
}
|
||||||
|
)
|
||||||
if self.object.page:
|
if self.object.page:
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('club:club_hist', kwargs={'club_id': self.object.id}),
|
{
|
||||||
'slug': 'history',
|
"url": reverse(
|
||||||
'name': _("History"),
|
"club:club_hist", kwargs={"club_id": self.object.id}
|
||||||
})
|
),
|
||||||
|
"slug": "history",
|
||||||
|
"name": _("History"),
|
||||||
|
}
|
||||||
|
)
|
||||||
if self.request.user.can_edit(self.object):
|
if self.request.user.can_edit(self.object):
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('club:tools', kwargs={'club_id': self.object.id}),
|
{
|
||||||
'slug': 'tools',
|
"url": reverse("club:tools", kwargs={"club_id": self.object.id}),
|
||||||
'name': _("Tools"),
|
"slug": "tools",
|
||||||
})
|
"name": _("Tools"),
|
||||||
tab_list.append({
|
}
|
||||||
'url': reverse('club:club_edit', kwargs={'club_id': self.object.id}),
|
)
|
||||||
'slug': 'edit',
|
tab_list.append(
|
||||||
'name': _("Edit"),
|
{
|
||||||
})
|
"url": reverse(
|
||||||
|
"club:club_edit", kwargs={"club_id": self.object.id}
|
||||||
|
),
|
||||||
|
"slug": "edit",
|
||||||
|
"name": _("Edit"),
|
||||||
|
}
|
||||||
|
)
|
||||||
if self.object.page and self.request.user.can_edit(self.object.page):
|
if self.object.page and self.request.user.can_edit(self.object.page):
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('core:page_edit', kwargs={'page_name': self.object.page.get_full_name()}),
|
{
|
||||||
'slug': 'page_edit',
|
"url": reverse(
|
||||||
'name': _('Edit club page')
|
"core:page_edit",
|
||||||
})
|
kwargs={"page_name": self.object.page.get_full_name()},
|
||||||
tab_list.append({
|
),
|
||||||
'url': reverse('club:club_sellings', kwargs={'club_id': self.object.id}),
|
"slug": "page_edit",
|
||||||
'slug': 'sellings',
|
"name": _("Edit club page"),
|
||||||
'name': _("Sellings"),
|
}
|
||||||
})
|
)
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('club:mailing', kwargs={'club_id': self.object.id}),
|
{
|
||||||
'slug': 'mailing',
|
"url": reverse(
|
||||||
'name': _("Mailing list"),
|
"club:club_sellings", kwargs={"club_id": self.object.id}
|
||||||
})
|
),
|
||||||
tab_list.append({
|
"slug": "sellings",
|
||||||
'url': reverse('club:poster_list', kwargs={'club_id': self.object.id}),
|
"name": _("Sellings"),
|
||||||
'slug': 'posters',
|
}
|
||||||
'name': _("Posters list"),
|
)
|
||||||
})
|
tab_list.append(
|
||||||
|
{
|
||||||
|
"url": reverse("club:mailing", kwargs={"club_id": self.object.id}),
|
||||||
|
"slug": "mailing",
|
||||||
|
"name": _("Mailing list"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
tab_list.append(
|
||||||
|
{
|
||||||
|
"url": reverse(
|
||||||
|
"club:poster_list", kwargs={"club_id": self.object.id}
|
||||||
|
),
|
||||||
|
"slug": "posters",
|
||||||
|
"name": _("Posters list"),
|
||||||
|
}
|
||||||
|
)
|
||||||
if self.request.user.is_owner(self.object):
|
if self.request.user.is_owner(self.object):
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('club:club_prop', kwargs={'club_id': self.object.id}),
|
{
|
||||||
'slug': 'props',
|
"url": reverse(
|
||||||
'name': _("Props"),
|
"club:club_prop", kwargs={"club_id": self.object.id}
|
||||||
})
|
),
|
||||||
|
"slug": "props",
|
||||||
|
"name": _("Props"),
|
||||||
|
}
|
||||||
|
)
|
||||||
return tab_list
|
return tab_list
|
||||||
|
|
||||||
|
|
||||||
@ -172,23 +227,25 @@ class ClubListView(ListView):
|
|||||||
"""
|
"""
|
||||||
List the Clubs
|
List the Clubs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
template_name = 'club/club_list.jinja'
|
template_name = "club/club_list.jinja"
|
||||||
|
|
||||||
|
|
||||||
class ClubView(ClubTabsMixin, DetailView):
|
class ClubView(ClubTabsMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
Front page of a Club
|
Front page of a Club
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
template_name = 'club/club_detail.jinja'
|
template_name = "club/club_detail.jinja"
|
||||||
current_tab = "infos"
|
current_tab = "infos"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(ClubView, self).get_context_data(**kwargs)
|
kwargs = super(ClubView, self).get_context_data(**kwargs)
|
||||||
if self.object.page and self.object.page.revisions.exists():
|
if self.object.page and self.object.page.revisions.exists():
|
||||||
kwargs['page_revision'] = self.object.page.revisions.last().content
|
kwargs["page_revision"] = self.object.page.revisions.last().content
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -196,23 +253,24 @@ class ClubRevView(ClubView):
|
|||||||
"""
|
"""
|
||||||
Display a specific page revision
|
Display a specific page revision
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
self.revision = get_object_or_404(PageRev, pk=kwargs['rev_id'], page__club=obj)
|
self.revision = get_object_or_404(PageRev, pk=kwargs["rev_id"], page__club=obj)
|
||||||
return super(ClubRevView, self).dispatch(request, *args, **kwargs)
|
return super(ClubRevView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(ClubRevView, self).get_context_data(**kwargs)
|
kwargs = super(ClubRevView, self).get_context_data(**kwargs)
|
||||||
kwargs['page_revision'] = self.revision.content
|
kwargs["page_revision"] = self.revision.content
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class ClubPageEditView(ClubTabsMixin, PageEditViewBase):
|
class ClubPageEditView(ClubTabsMixin, PageEditViewBase):
|
||||||
template_name = 'club/pagerev_edit.jinja'
|
template_name = "club/pagerev_edit.jinja"
|
||||||
current_tab = "page_edit"
|
current_tab = "page_edit"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.club = get_object_or_404(Club, pk=kwargs['club_id'])
|
self.club = get_object_or_404(Club, pk=kwargs["club_id"])
|
||||||
if not self.club.page:
|
if not self.club.page:
|
||||||
raise Http404
|
raise Http404
|
||||||
return super(ClubPageEditView, self).dispatch(request, *args, **kwargs)
|
return super(ClubPageEditView, self).dispatch(request, *args, **kwargs)
|
||||||
@ -222,16 +280,17 @@ class ClubPageEditView(ClubTabsMixin, PageEditViewBase):
|
|||||||
return self._get_revision()
|
return self._get_revision()
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse_lazy('club:club_view', kwargs={'club_id': self.club.id})
|
return reverse_lazy("club:club_view", kwargs={"club_id": self.club.id})
|
||||||
|
|
||||||
|
|
||||||
class ClubPageHistView(ClubTabsMixin, CanViewMixin, DetailView):
|
class ClubPageHistView(ClubTabsMixin, CanViewMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
Modification hostory of the page
|
Modification hostory of the page
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
template_name = 'club/page_history.jinja'
|
template_name = "club/page_history.jinja"
|
||||||
current_tab = "history"
|
current_tab = "history"
|
||||||
|
|
||||||
|
|
||||||
@ -239,9 +298,10 @@ class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView):
|
|||||||
"""
|
"""
|
||||||
Tools page of a Club
|
Tools page of a Club
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
template_name = 'club/club_tools.jinja'
|
template_name = "club/club_tools.jinja"
|
||||||
current_tab = "tools"
|
current_tab = "tools"
|
||||||
|
|
||||||
|
|
||||||
@ -249,16 +309,18 @@ class ClubMemberForm(forms.ModelForm):
|
|||||||
"""
|
"""
|
||||||
Form handling the members of a club
|
Form handling the members of a club
|
||||||
"""
|
"""
|
||||||
error_css_class = 'error'
|
|
||||||
required_css_class = 'required'
|
error_css_class = "error"
|
||||||
|
required_css_class = "required"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Membership
|
model = Membership
|
||||||
fields = ['user', 'role', 'start_date', 'description']
|
fields = ["user", "role", "start_date", "description"]
|
||||||
widgets = {
|
widgets = {"start_date": SelectDate}
|
||||||
'start_date': SelectDate
|
|
||||||
}
|
user = AutoCompleteSelectField(
|
||||||
user = AutoCompleteSelectField('users', required=True, label=_("Select user"), help_text=None)
|
"users", required=True, label=_("Select user"), help_text=None
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -272,10 +334,11 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView):
|
|||||||
"""
|
"""
|
||||||
View of a club's members
|
View of a club's members
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
form_class = ClubMemberForm
|
form_class = ClubMemberForm
|
||||||
template_name = 'club/club_members.jinja'
|
template_name = "club/club_members.jinja"
|
||||||
current_tab = "members"
|
current_tab = "members"
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
@ -284,12 +347,19 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView):
|
|||||||
That's why the save method of ClubMemberForm is overridden.
|
That's why the save method of ClubMemberForm is overridden.
|
||||||
"""
|
"""
|
||||||
form = super(ClubMembersView, self).get_form()
|
form = super(ClubMembersView, self).get_form()
|
||||||
if 'user' in form.data and form.data.get('user') != '': # Load an existing membership if possible
|
if (
|
||||||
form.instance = Membership.objects.filter(club=self.object).filter(user=form.data.get('user')).filter(end_date=None).first()
|
"user" in form.data and form.data.get("user") != ""
|
||||||
|
): # Load an existing membership if possible
|
||||||
|
form.instance = (
|
||||||
|
Membership.objects.filter(club=self.object)
|
||||||
|
.filter(user=form.data.get("user"))
|
||||||
|
.filter(end_date=None)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
if form.instance is None: # Instanciate a new membership
|
if form.instance is None: # Instanciate a new membership
|
||||||
form.instance = Membership(club=self.object, user=self.request.user)
|
form.instance = Membership(club=self.object, user=self.request.user)
|
||||||
if not self.request.user.is_root:
|
if not self.request.user.is_root:
|
||||||
form.fields.pop('start_date', None)
|
form.fields.pop("start_date", None)
|
||||||
return form
|
return form
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
@ -298,9 +368,12 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView):
|
|||||||
"""
|
"""
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
ms = self.object.get_membership_for(user)
|
ms = self.object.get_membership_for(user)
|
||||||
if (form.cleaned_data['role'] <= SITH_MAXIMUM_FREE_ROLE or
|
if (
|
||||||
(ms is not None and ms.role >= form.cleaned_data['role']) or
|
form.cleaned_data["role"] <= SITH_MAXIMUM_FREE_ROLE
|
||||||
user.is_board_member or user.is_root):
|
or (ms is not None and ms.role >= form.cleaned_data["role"])
|
||||||
|
or user.is_board_member
|
||||||
|
or user.is_root
|
||||||
|
):
|
||||||
form.save()
|
form.save()
|
||||||
form = self.form_class()
|
form = self.form_class()
|
||||||
return super(ModelFormMixin, self).form_valid(form)
|
return super(ModelFormMixin, self).form_valid(form)
|
||||||
@ -313,39 +386,57 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView):
|
|||||||
return super(ClubMembersView, self).dispatch(request, *args, **kwargs)
|
return super(ClubMembersView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse_lazy('club:club_members', kwargs={'club_id': self.club.id})
|
return reverse_lazy("club:club_members", kwargs={"club_id": self.club.id})
|
||||||
|
|
||||||
|
|
||||||
class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView):
|
class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
Old members of a club
|
Old members of a club
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
template_name = 'club/club_old_members.jinja'
|
template_name = "club/club_old_members.jinja"
|
||||||
current_tab = "elderlies"
|
current_tab = "elderlies"
|
||||||
|
|
||||||
|
|
||||||
class SellingsFormBase(forms.Form):
|
class SellingsFormBase(forms.Form):
|
||||||
begin_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Begin date"), required=False, widget=SelectDateTime)
|
begin_date = forms.DateTimeField(
|
||||||
end_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End date"), required=False, widget=SelectDateTime)
|
["%Y-%m-%d %H:%M:%S"],
|
||||||
counter = forms.ModelChoiceField(Counter.objects.order_by('name').all(), label=_("Counter"), required=False)
|
label=_("Begin date"),
|
||||||
|
required=False,
|
||||||
|
widget=SelectDateTime,
|
||||||
|
)
|
||||||
|
end_date = forms.DateTimeField(
|
||||||
|
["%Y-%m-%d %H:%M:%S"],
|
||||||
|
label=_("End date"),
|
||||||
|
required=False,
|
||||||
|
widget=SelectDateTime,
|
||||||
|
)
|
||||||
|
counter = forms.ModelChoiceField(
|
||||||
|
Counter.objects.order_by("name").all(), label=_("Counter"), required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailView):
|
class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
Sellings of a club
|
Sellings of a club
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
template_name = 'club/club_sellings.jinja'
|
template_name = "club/club_sellings.jinja"
|
||||||
current_tab = "sellings"
|
current_tab = "sellings"
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'product': forms.ModelChoiceField(self.object.products.order_by('name').all(), label=_("Product"), required=False)
|
"product": forms.ModelChoiceField(
|
||||||
|
self.object.products.order_by("name").all(),
|
||||||
|
label=_("Product"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return type('SellingsForm', (SellingsFormBase,), kwargs)
|
return type("SellingsForm", (SellingsFormBase,), kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(ClubSellingView, self).get_context_data(**kwargs)
|
kwargs = super(ClubSellingView, self).get_context_data(**kwargs)
|
||||||
@ -354,21 +445,23 @@ class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailView):
|
|||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
if not len([v for v in form.cleaned_data.values() if v is not None]):
|
if not len([v for v in form.cleaned_data.values() if v is not None]):
|
||||||
qs = Selling.objects.filter(id=-1)
|
qs = Selling.objects.filter(id=-1)
|
||||||
if form.cleaned_data['begin_date']:
|
if form.cleaned_data["begin_date"]:
|
||||||
qs = qs.filter(date__gte=form.cleaned_data['begin_date'])
|
qs = qs.filter(date__gte=form.cleaned_data["begin_date"])
|
||||||
if form.cleaned_data['end_date']:
|
if form.cleaned_data["end_date"]:
|
||||||
qs = qs.filter(date__lte=form.cleaned_data['end_date'])
|
qs = qs.filter(date__lte=form.cleaned_data["end_date"])
|
||||||
if form.cleaned_data['counter']:
|
if form.cleaned_data["counter"]:
|
||||||
qs = qs.filter(counter=form.cleaned_data['counter'])
|
qs = qs.filter(counter=form.cleaned_data["counter"])
|
||||||
if form.cleaned_data['product']:
|
if form.cleaned_data["product"]:
|
||||||
qs = qs.filter(product__id=form.cleaned_data['product'].id)
|
qs = qs.filter(product__id=form.cleaned_data["product"].id)
|
||||||
kwargs['result'] = qs.all().order_by('-id')
|
kwargs["result"] = qs.all().order_by("-id")
|
||||||
kwargs['total'] = sum([s.quantity * s.unit_price for s in qs.all()])
|
kwargs["total"] = sum([s.quantity * s.unit_price for s in qs.all()])
|
||||||
kwargs['total_quantity'] = sum([s.quantity for s in qs.all()])
|
kwargs["total_quantity"] = sum([s.quantity for s in qs.all()])
|
||||||
kwargs['benefit'] = kwargs['total'] - sum([s.product.purchase_price for s in qs.exclude(product=None)])
|
kwargs["benefit"] = kwargs["total"] - sum(
|
||||||
|
[s.product.purchase_price for s in qs.exclude(product=None)]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
kwargs['result'] = qs[:0]
|
kwargs["result"] = qs[:0]
|
||||||
kwargs['form'] = form
|
kwargs["form"] = form
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -379,36 +472,56 @@ class ClubSellingCSVView(ClubSellingView):
|
|||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
import csv
|
import csv
|
||||||
response = HttpResponse(content_type='text/csv')
|
|
||||||
|
response = HttpResponse(content_type="text/csv")
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
name = _("Sellings") + "_" + self.object.name + ".csv"
|
name = _("Sellings") + "_" + self.object.name + ".csv"
|
||||||
response['Content-Disposition'] = 'filename=' + name
|
response["Content-Disposition"] = "filename=" + name
|
||||||
kwargs = self.get_context_data(**kwargs)
|
kwargs = self.get_context_data(**kwargs)
|
||||||
writer = csv.writer(response, delimiter=";", lineterminator='\n', quoting=csv.QUOTE_ALL)
|
writer = csv.writer(
|
||||||
|
response, delimiter=";", lineterminator="\n", quoting=csv.QUOTE_ALL
|
||||||
|
)
|
||||||
|
|
||||||
writer.writerow([_t('Quantity'), kwargs['total_quantity']])
|
writer.writerow([_t("Quantity"), kwargs["total_quantity"]])
|
||||||
writer.writerow([_t('Total'), kwargs['total']])
|
writer.writerow([_t("Total"), kwargs["total"]])
|
||||||
writer.writerow([_t('Benefit'), kwargs['benefit']])
|
writer.writerow([_t("Benefit"), kwargs["benefit"]])
|
||||||
writer.writerow([_t('Date'), _t('Counter'), _t('Barman'), _t('Customer'), _t('Label'),
|
writer.writerow(
|
||||||
_t('Quantity'), _t('Total'), _t('Payment method'), _t('Selling price'), _t('Purchase price'), _t('Benefit')])
|
[
|
||||||
for o in kwargs['result']:
|
_t("Date"),
|
||||||
|
_t("Counter"),
|
||||||
|
_t("Barman"),
|
||||||
|
_t("Customer"),
|
||||||
|
_t("Label"),
|
||||||
|
_t("Quantity"),
|
||||||
|
_t("Total"),
|
||||||
|
_t("Payment method"),
|
||||||
|
_t("Selling price"),
|
||||||
|
_t("Purchase price"),
|
||||||
|
_t("Benefit"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
for o in kwargs["result"]:
|
||||||
row = [o.date, o.counter]
|
row = [o.date, o.counter]
|
||||||
if o.seller:
|
if o.seller:
|
||||||
row.append(o.seller.get_display_name())
|
row.append(o.seller.get_display_name())
|
||||||
else:
|
else:
|
||||||
row.append('')
|
row.append("")
|
||||||
if o.customer:
|
if o.customer:
|
||||||
row.append(o.customer.user.get_display_name())
|
row.append(o.customer.user.get_display_name())
|
||||||
else:
|
else:
|
||||||
row.append('')
|
row.append("")
|
||||||
row = row + [o.label, o.quantity, o.quantity * o.unit_price,
|
row = row + [
|
||||||
o.get_payment_method_display()]
|
o.label,
|
||||||
|
o.quantity,
|
||||||
|
o.quantity * o.unit_price,
|
||||||
|
o.get_payment_method_display(),
|
||||||
|
]
|
||||||
if o.product:
|
if o.product:
|
||||||
row.append(o.product.selling_price)
|
row.append(o.product.selling_price)
|
||||||
row.append(o.product.purchase_price)
|
row.append(o.product.purchase_price)
|
||||||
row.append(o.product.selling_price - o.product.purchase_price)
|
row.append(o.product.selling_price - o.product.purchase_price)
|
||||||
else:
|
else:
|
||||||
row = row + ['', '', '']
|
row = row + ["", "", ""]
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
@ -418,10 +531,11 @@ class ClubEditView(ClubTabsMixin, CanEditMixin, UpdateView):
|
|||||||
"""
|
"""
|
||||||
Edit a Club's main informations (for the club's members)
|
Edit a Club's main informations (for the club's members)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
form_class = ClubEditForm
|
form_class = ClubEditForm
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
current_tab = "edit"
|
current_tab = "edit"
|
||||||
|
|
||||||
|
|
||||||
@ -429,10 +543,11 @@ class ClubEditPropView(ClubTabsMixin, CanEditPropMixin, UpdateView):
|
|||||||
"""
|
"""
|
||||||
Edit the properties of a Club object (for the Sith admins)
|
Edit the properties of a Club object (for the Sith admins)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
fields = ['name', 'unix_name', 'parent', 'is_active']
|
fields = ["name", "unix_name", "parent", "is_active"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
current_tab = "props"
|
current_tab = "props"
|
||||||
|
|
||||||
|
|
||||||
@ -440,16 +555,18 @@ class ClubCreateView(CanEditPropMixin, CreateView):
|
|||||||
"""
|
"""
|
||||||
Create a club (for the Sith admin)
|
Create a club (for the Sith admin)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Club
|
model = Club
|
||||||
pk_url_kwarg = "club_id"
|
pk_url_kwarg = "club_id"
|
||||||
fields = ['name', 'unix_name', 'parent']
|
fields = ["name", "unix_name", "parent"]
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
|
|
||||||
class MembershipSetOldView(CanEditMixin, DetailView):
|
class MembershipSetOldView(CanEditMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
Set a membership as beeing old
|
Set a membership as beeing old
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = Membership
|
model = Membership
|
||||||
pk_url_kwarg = "membership_id"
|
pk_url_kwarg = "membership_id"
|
||||||
|
|
||||||
@ -457,11 +574,23 @@ class MembershipSetOldView(CanEditMixin, DetailView):
|
|||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
self.object.end_date = timezone.now()
|
self.object.end_date = timezone.now()
|
||||||
self.object.save()
|
self.object.save()
|
||||||
return HttpResponseRedirect(reverse('club:club_members', args=self.args, kwargs={'club_id': self.object.club.id}))
|
return HttpResponseRedirect(
|
||||||
|
reverse(
|
||||||
|
"club:club_members",
|
||||||
|
args=self.args,
|
||||||
|
kwargs={"club_id": self.object.club.id},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
return HttpResponseRedirect(reverse('club:club_members', args=self.args, kwargs={'club_id': self.object.club.id}))
|
return HttpResponseRedirect(
|
||||||
|
reverse(
|
||||||
|
"club:club_members",
|
||||||
|
args=self.args,
|
||||||
|
kwargs={"club_id": self.object.club.id},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ClubStatView(TemplateView):
|
class ClubStatView(TemplateView):
|
||||||
@ -469,7 +598,7 @@ class ClubStatView(TemplateView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(ClubStatView, self).get_context_data(**kwargs)
|
kwargs = super(ClubStatView, self).get_context_data(**kwargs)
|
||||||
kwargs['club_list'] = Club.objects.all()
|
kwargs["club_list"] = Club.objects.all()
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -477,16 +606,21 @@ class ClubMailingView(ClubTabsMixin, ListView):
|
|||||||
"""
|
"""
|
||||||
A list of mailing for a given club
|
A list of mailing for a given club
|
||||||
"""
|
"""
|
||||||
|
|
||||||
action = None
|
action = None
|
||||||
model = Mailing
|
model = Mailing
|
||||||
template_name = "club/mailing.jinja"
|
template_name = "club/mailing.jinja"
|
||||||
current_tab = 'mailing'
|
current_tab = "mailing"
|
||||||
|
|
||||||
def authorized(self):
|
def authorized(self):
|
||||||
return self.club.has_rights_in_club(self.user) or self.user.is_root or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return (
|
||||||
|
self.club.has_rights_in_club(self.user)
|
||||||
|
or self.user.is_root
|
||||||
|
or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
)
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.club = get_object_or_404(Club, pk=kwargs['club_id'])
|
self.club = get_object_or_404(Club, pk=kwargs["club_id"])
|
||||||
self.user = request.user
|
self.user = request.user
|
||||||
self.object = self.club
|
self.object = self.club
|
||||||
if not self.authorized():
|
if not self.authorized():
|
||||||
@ -504,7 +638,9 @@ class ClubMailingView(ClubTabsMixin, ListView):
|
|||||||
elif self.action == "add_member":
|
elif self.action == "add_member":
|
||||||
form = MailingSubscriptionForm
|
form = MailingSubscriptionForm
|
||||||
model = MailingSubscription
|
model = MailingSubscription
|
||||||
return MailingGenericCreateView.as_view(model=model, list_view=self, form_class=form)(request, *args, **kwargs)
|
return MailingGenericCreateView.as_view(
|
||||||
|
model=model, list_view=self, form_class=form
|
||||||
|
)(request, *args, **kwargs)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
@ -512,11 +648,11 @@ class ClubMailingView(ClubTabsMixin, ListView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(ClubMailingView, self).get_context_data(**kwargs)
|
kwargs = super(ClubMailingView, self).get_context_data(**kwargs)
|
||||||
kwargs['add_member'] = self.member_form
|
kwargs["add_member"] = self.member_form
|
||||||
kwargs['add_mailing'] = self.mailing_form
|
kwargs["add_mailing"] = self.mailing_form
|
||||||
kwargs['club'] = self.club
|
kwargs["club"] = self.club
|
||||||
kwargs['user'] = self.user
|
kwargs["user"] = self.user
|
||||||
kwargs['has_objects'] = len(kwargs['object_list']) > 0
|
kwargs["has_objects"] = len(kwargs["object_list"]) > 0
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
@ -527,20 +663,23 @@ class MailingGenericCreateView(CreateView, SingleObjectMixin):
|
|||||||
"""
|
"""
|
||||||
Create a new mailing list
|
Create a new mailing list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
list_view = None
|
list_view = None
|
||||||
form_class = None
|
form_class = None
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
view_kwargs = self.list_view.get_context_data(**kwargs)
|
view_kwargs = self.list_view.get_context_data(**kwargs)
|
||||||
for key, data in super(MailingGenericCreateView, self).get_context_data(**kwargs).items():
|
for key, data in (
|
||||||
|
super(MailingGenericCreateView, self).get_context_data(**kwargs).items()
|
||||||
|
):
|
||||||
view_kwargs[key] = data
|
view_kwargs[key] = data
|
||||||
view_kwargs[self.list_view.action] = view_kwargs['form']
|
view_kwargs[self.list_view.action] = view_kwargs["form"]
|
||||||
return view_kwargs
|
return view_kwargs
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super(MailingGenericCreateView, self).get_form_kwargs()
|
kwargs = super(MailingGenericCreateView, self).get_form_kwargs()
|
||||||
kwargs['club_id'] = self.list_view.club.id
|
kwargs["club_id"] = self.list_view.club.id
|
||||||
kwargs['user_id'] = self.list_view.user.id
|
kwargs["user_id"] = self.list_view.user.id
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
@ -550,13 +689,13 @@ class MailingGenericCreateView(CreateView, SingleObjectMixin):
|
|||||||
return super(MailingGenericCreateView, self).dispatch(request, *args, **kwargs)
|
return super(MailingGenericCreateView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse_lazy('club:mailing', kwargs={'club_id': self.list_view.club.id})
|
return reverse_lazy("club:mailing", kwargs={"club_id": self.list_view.club.id})
|
||||||
|
|
||||||
|
|
||||||
class MailingDeleteView(CanEditMixin, DeleteView):
|
class MailingDeleteView(CanEditMixin, DeleteView):
|
||||||
|
|
||||||
model = Mailing
|
model = Mailing
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
pk_url_kwarg = "mailing_id"
|
pk_url_kwarg = "mailing_id"
|
||||||
redirect_page = None
|
redirect_page = None
|
||||||
|
|
||||||
@ -568,27 +707,28 @@ class MailingDeleteView(CanEditMixin, DeleteView):
|
|||||||
if self.redirect_page:
|
if self.redirect_page:
|
||||||
return reverse_lazy(self.redirect_page)
|
return reverse_lazy(self.redirect_page)
|
||||||
else:
|
else:
|
||||||
return reverse_lazy('club:mailing', kwargs={'club_id': self.club_id})
|
return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})
|
||||||
|
|
||||||
|
|
||||||
class MailingSubscriptionDeleteView(CanEditMixin, DeleteView):
|
class MailingSubscriptionDeleteView(CanEditMixin, DeleteView):
|
||||||
|
|
||||||
model = MailingSubscription
|
model = MailingSubscription
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
pk_url_kwarg = "mailing_subscription_id"
|
pk_url_kwarg = "mailing_subscription_id"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.club_id = self.get_object().mailing.club.id
|
self.club_id = self.get_object().mailing.club.id
|
||||||
return super(MailingSubscriptionDeleteView, self).dispatch(request, *args, **kwargs)
|
return super(MailingSubscriptionDeleteView, self).dispatch(
|
||||||
|
request, *args, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse_lazy('club:mailing', kwargs={'club_id': self.club_id})
|
return reverse_lazy("club:mailing", kwargs={"club_id": self.club_id})
|
||||||
|
|
||||||
|
|
||||||
class MailingAutoGenerationView(View):
|
class MailingAutoGenerationView(View):
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.mailing = get_object_or_404(Mailing, pk=kwargs['mailing_id'])
|
self.mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"])
|
||||||
if not request.user.can_edit(self.mailing):
|
if not request.user.can_edit(self.mailing):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
return super(MailingAutoGenerationView, self).dispatch(request, *args, **kwargs)
|
return super(MailingAutoGenerationView, self).dispatch(request, *args, **kwargs)
|
||||||
@ -596,23 +736,24 @@ class MailingAutoGenerationView(View):
|
|||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
club = self.mailing.club
|
club = self.mailing.club
|
||||||
self.mailing.subscriptions.all().delete()
|
self.mailing.subscriptions.all().delete()
|
||||||
members = club.members.filter(role__gte=settings.SITH_CLUB_ROLES_ID['Board member']).exclude(end_date__lte=timezone.now())
|
members = club.members.filter(
|
||||||
|
role__gte=settings.SITH_CLUB_ROLES_ID["Board member"]
|
||||||
|
).exclude(end_date__lte=timezone.now())
|
||||||
for member in members.all():
|
for member in members.all():
|
||||||
MailingSubscription(user=member.user, mailing=self.mailing).save()
|
MailingSubscription(user=member.user, mailing=self.mailing).save()
|
||||||
return redirect('club:mailing', club_id=club.id)
|
return redirect("club:mailing", club_id=club.id)
|
||||||
|
|
||||||
|
|
||||||
class MailingAutoCleanView(View):
|
class MailingAutoCleanView(View):
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.mailing = get_object_or_404(Mailing, pk=kwargs['mailing_id'])
|
self.mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"])
|
||||||
if not request.user.can_edit(self.mailing):
|
if not request.user.can_edit(self.mailing):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
return super(MailingAutoCleanView, self).dispatch(request, *args, **kwargs)
|
return super(MailingAutoCleanView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.mailing.subscriptions.all().delete()
|
self.mailing.subscriptions.all().delete()
|
||||||
return redirect('club:mailing', club_id=self.mailing.club.id)
|
return redirect("club:mailing", club_id=self.mailing.club.id)
|
||||||
|
|
||||||
|
|
||||||
class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin):
|
class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin):
|
||||||
@ -623,8 +764,8 @@ class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterListView, self).get_context_data(**kwargs)
|
kwargs = super(PosterListView, self).get_context_data(**kwargs)
|
||||||
kwargs['app'] = "club"
|
kwargs["app"] = "club"
|
||||||
kwargs['club'] = self.club
|
kwargs["club"] = self.club
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -640,18 +781,18 @@ class PosterCreateView(PosterCreateBaseView, CanCreateMixin):
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse_lazy('club:poster_list', kwargs={'club_id': self.club.id})
|
return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})
|
||||||
|
|
||||||
|
|
||||||
class PosterEditView(ClubTabsMixin, PosterEditBaseView, CanEditMixin):
|
class PosterEditView(ClubTabsMixin, PosterEditBaseView, CanEditMixin):
|
||||||
"""Edit communication poster"""
|
"""Edit communication poster"""
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('club:poster_list', kwargs={'club_id': self.club.id})
|
return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterEditView, self).get_context_data(**kwargs)
|
kwargs = super(PosterEditView, self).get_context_data(**kwargs)
|
||||||
kwargs['app'] = "club"
|
kwargs["app"] = "club"
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@ -659,5 +800,4 @@ class PosterDeleteView(PosterDeleteBaseView, ClubTabsMixin, CanEditMixin):
|
|||||||
"""Delete communication poster"""
|
"""Delete communication poster"""
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('club:poster_list', kwargs={'club_id': self.club.id})
|
return reverse_lazy("club:poster_list", kwargs={"club_id": self.club.id})
|
||||||
|
|
||||||
|
@ -21,4 +21,3 @@
|
|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -41,4 +41,3 @@ admin.site.register(News, NewsAdmin)
|
|||||||
admin.site.register(Weekmail, WeekmailAdmin)
|
admin.site.register(Weekmail, WeekmailAdmin)
|
||||||
admin.site.register(Screen)
|
admin.site.register(Screen)
|
||||||
admin.site.register(Poster)
|
admin.site.register(Poster)
|
||||||
|
|
||||||
|
@ -6,17 +6,37 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = []
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Sith',
|
name="Sith",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)),
|
(
|
||||||
('alert_msg', models.TextField(default='', verbose_name='alert message', blank=True)),
|
"id",
|
||||||
('info_msg', models.TextField(default='', verbose_name='info message', blank=True)),
|
models.AutoField(
|
||||||
('index_page', models.TextField(default='', verbose_name='index page', blank=True)),
|
verbose_name="ID",
|
||||||
],
|
auto_created=True,
|
||||||
|
serialize=False,
|
||||||
|
primary_key=True,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"alert_msg",
|
||||||
|
models.TextField(
|
||||||
|
default="", verbose_name="alert message", blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_msg",
|
||||||
|
models.TextField(
|
||||||
|
default="", verbose_name="info message", blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"index_page",
|
||||||
|
models.TextField(default="", verbose_name="index page", blank=True),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -8,33 +8,100 @@ from django.conf import settings
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('club', '0005_auto_20161120_1149'),
|
("club", "0005_auto_20161120_1149"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
('com', '0001_initial'),
|
("com", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='News',
|
name="News",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')),
|
(
|
||||||
('title', models.CharField(max_length=64, verbose_name='title')),
|
"id",
|
||||||
('summary', models.TextField(verbose_name='summary')),
|
models.AutoField(
|
||||||
('content', models.TextField(verbose_name='content')),
|
primary_key=True,
|
||||||
('type', models.CharField(choices=[('NOTICE', 'Notice'), ('EVENT', 'Event'), ('WEEKLY', 'Weekly'), ('CALL', 'Call')], default='EVENT', max_length=16, verbose_name='type')),
|
serialize=False,
|
||||||
('is_moderated', models.BooleanField(default=False, verbose_name='is moderated')),
|
auto_created=True,
|
||||||
('author', models.ForeignKey(related_name='owned_news', to=settings.AUTH_USER_MODEL, verbose_name='author')),
|
verbose_name="ID",
|
||||||
('club', models.ForeignKey(related_name='news', to='club.Club', verbose_name='club')),
|
),
|
||||||
('moderator', models.ForeignKey(related_name='moderated_news', null=True, to=settings.AUTH_USER_MODEL, verbose_name='moderator')),
|
),
|
||||||
|
("title", models.CharField(max_length=64, verbose_name="title")),
|
||||||
|
("summary", models.TextField(verbose_name="summary")),
|
||||||
|
("content", models.TextField(verbose_name="content")),
|
||||||
|
(
|
||||||
|
"type",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("NOTICE", "Notice"),
|
||||||
|
("EVENT", "Event"),
|
||||||
|
("WEEKLY", "Weekly"),
|
||||||
|
("CALL", "Call"),
|
||||||
|
],
|
||||||
|
default="EVENT",
|
||||||
|
max_length=16,
|
||||||
|
verbose_name="type",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_moderated",
|
||||||
|
models.BooleanField(default=False, verbose_name="is moderated"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"author",
|
||||||
|
models.ForeignKey(
|
||||||
|
related_name="owned_news",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="author",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"club",
|
||||||
|
models.ForeignKey(
|
||||||
|
related_name="news", to="club.Club", verbose_name="club"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"moderator",
|
||||||
|
models.ForeignKey(
|
||||||
|
related_name="moderated_news",
|
||||||
|
null=True,
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="moderator",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='NewsDate',
|
name="NewsDate",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')),
|
(
|
||||||
('start_date', models.DateTimeField(null=True, blank=True, verbose_name='start_date')),
|
"id",
|
||||||
('end_date', models.DateTimeField(null=True, blank=True, verbose_name='end_date')),
|
models.AutoField(
|
||||||
('news', models.ForeignKey(related_name='dates', to='com.News', verbose_name='news_date')),
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
auto_created=True,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"start_date",
|
||||||
|
models.DateTimeField(
|
||||||
|
null=True, blank=True, verbose_name="start_date"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"end_date",
|
||||||
|
models.DateTimeField(
|
||||||
|
null=True, blank=True, verbose_name="end_date"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"news",
|
||||||
|
models.ForeignKey(
|
||||||
|
related_name="dates", to="com.News", verbose_name="news_date"
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -8,42 +8,81 @@ from django.conf import settings
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('club', '0006_auto_20161229_0040'),
|
("club", "0006_auto_20161229_0040"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
('com', '0002_news_newsdate'),
|
("com", "0002_news_newsdate"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Weekmail',
|
name="Weekmail",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('title', models.CharField(max_length=64, verbose_name='title', blank=True)),
|
"id",
|
||||||
('intro', models.TextField(verbose_name='intro', blank=True)),
|
models.AutoField(
|
||||||
('joke', models.TextField(verbose_name='joke', blank=True)),
|
serialize=False,
|
||||||
('protip', models.TextField(verbose_name='protip', blank=True)),
|
primary_key=True,
|
||||||
('conclusion', models.TextField(verbose_name='conclusion', blank=True)),
|
verbose_name="ID",
|
||||||
('sent', models.BooleanField(verbose_name='sent', default=False)),
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"title",
|
||||||
|
models.CharField(max_length=64, verbose_name="title", blank=True),
|
||||||
|
),
|
||||||
|
("intro", models.TextField(verbose_name="intro", blank=True)),
|
||||||
|
("joke", models.TextField(verbose_name="joke", blank=True)),
|
||||||
|
("protip", models.TextField(verbose_name="protip", blank=True)),
|
||||||
|
("conclusion", models.TextField(verbose_name="conclusion", blank=True)),
|
||||||
|
("sent", models.BooleanField(verbose_name="sent", default=False)),
|
||||||
],
|
],
|
||||||
options={
|
options={"ordering": ["-id"]},
|
||||||
'ordering': ['-id'],
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='WeekmailArticle',
|
name="WeekmailArticle",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('title', models.CharField(max_length=64, verbose_name='title')),
|
"id",
|
||||||
('content', models.TextField(verbose_name='content')),
|
models.AutoField(
|
||||||
('rank', models.IntegerField(verbose_name='rank', default=-1)),
|
serialize=False,
|
||||||
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='author', related_name='owned_weekmail_articles')),
|
primary_key=True,
|
||||||
('club', models.ForeignKey(to='club.Club', verbose_name='club', related_name='weekmail_articles')),
|
verbose_name="ID",
|
||||||
('weekmail', models.ForeignKey(to='com.Weekmail', verbose_name='weekmail', related_name='articles', null=True)),
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("title", models.CharField(max_length=64, verbose_name="title")),
|
||||||
|
("content", models.TextField(verbose_name="content")),
|
||||||
|
("rank", models.IntegerField(verbose_name="rank", default=-1)),
|
||||||
|
(
|
||||||
|
"author",
|
||||||
|
models.ForeignKey(
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="author",
|
||||||
|
related_name="owned_weekmail_articles",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"club",
|
||||||
|
models.ForeignKey(
|
||||||
|
to="club.Club",
|
||||||
|
verbose_name="club",
|
||||||
|
related_name="weekmail_articles",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"weekmail",
|
||||||
|
models.ForeignKey(
|
||||||
|
to="com.Weekmail",
|
||||||
|
verbose_name="weekmail",
|
||||||
|
related_name="articles",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='sith',
|
model_name="sith",
|
||||||
name='weekmail_destinations',
|
name="weekmail_destinations",
|
||||||
field=models.TextField(verbose_name='weekmail destinations', default=''),
|
field=models.TextField(verbose_name="weekmail destinations", default=""),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -9,36 +9,78 @@ from django.conf import settings
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('club', '0010_auto_20170912_2028'),
|
("club", "0010_auto_20170912_2028"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
('com', '0003_auto_20170115_2300'),
|
("com", "0003_auto_20170115_2300"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Poster',
|
name="Poster",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
(
|
||||||
('name', models.CharField(verbose_name='name', max_length=128, default='')),
|
"id",
|
||||||
('file', models.ImageField(verbose_name='file', upload_to='com/posters')),
|
models.AutoField(
|
||||||
('date_begin', models.DateTimeField(default=django.utils.timezone.now)),
|
verbose_name="ID",
|
||||||
('date_end', models.DateTimeField(blank=True, null=True)),
|
primary_key=True,
|
||||||
('display_time', models.IntegerField(verbose_name='display time', default=30)),
|
serialize=False,
|
||||||
('is_moderated', models.BooleanField(verbose_name='is moderated', default=False)),
|
auto_created=True,
|
||||||
('club', models.ForeignKey(verbose_name='club', related_name='posters', to='club.Club')),
|
),
|
||||||
('moderator', models.ForeignKey(verbose_name='moderator', blank=True, null=True, related_name='moderated_posters', to=settings.AUTH_USER_MODEL)),
|
),
|
||||||
|
(
|
||||||
|
"name",
|
||||||
|
models.CharField(verbose_name="name", max_length=128, default=""),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"file",
|
||||||
|
models.ImageField(verbose_name="file", upload_to="com/posters"),
|
||||||
|
),
|
||||||
|
("date_begin", models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
("date_end", models.DateTimeField(blank=True, null=True)),
|
||||||
|
(
|
||||||
|
"display_time",
|
||||||
|
models.IntegerField(verbose_name="display time", default=30),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_moderated",
|
||||||
|
models.BooleanField(verbose_name="is moderated", default=False),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"club",
|
||||||
|
models.ForeignKey(
|
||||||
|
verbose_name="club", related_name="posters", to="club.Club"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"moderator",
|
||||||
|
models.ForeignKey(
|
||||||
|
verbose_name="moderator",
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name="moderated_posters",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Screen',
|
name="Screen",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
(
|
||||||
('name', models.CharField(verbose_name='name', max_length=128)),
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
verbose_name="ID",
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(verbose_name="name", max_length=128)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='poster',
|
model_name="poster",
|
||||||
name='screens',
|
name="screens",
|
||||||
field=models.ManyToManyField(related_name='posters', to='com.Screen'),
|
field=models.ManyToManyField(related_name="posters", to="com.Screen"),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("com", "0004_auto_20171221_1614")]
|
||||||
('com', '0004_auto_20171221_1614'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='poster',
|
model_name="poster",
|
||||||
name='display_time',
|
name="display_time",
|
||||||
field=models.IntegerField(verbose_name='display time', default=15),
|
field=models.IntegerField(verbose_name="display time", default=15),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
138
com/models.py
138
com/models.py
@ -40,10 +40,9 @@ from core.models import User, Preferences, RealGroup, Notification, SithFile
|
|||||||
from club.models import Club
|
from club.models import Club
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Sith(models.Model):
|
class Sith(models.Model):
|
||||||
"""A one instance class storing all the modifiable infos"""
|
"""A one instance class storing all the modifiable infos"""
|
||||||
|
|
||||||
alert_msg = models.TextField(_("alert message"), default="", blank=True)
|
alert_msg = models.TextField(_("alert message"), default="", blank=True)
|
||||||
info_msg = models.TextField(_("info message"), default="", blank=True)
|
info_msg = models.TextField(_("info message"), default="", blank=True)
|
||||||
index_page = models.TextField(_("index page"), default="", blank=True)
|
index_page = models.TextField(_("index page"), default="", blank=True)
|
||||||
@ -57,23 +56,30 @@ class Sith(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
NEWS_TYPES = [
|
NEWS_TYPES = [
|
||||||
('NOTICE', _('Notice')),
|
("NOTICE", _("Notice")),
|
||||||
('EVENT', _('Event')),
|
("EVENT", _("Event")),
|
||||||
('WEEKLY', _('Weekly')),
|
("WEEKLY", _("Weekly")),
|
||||||
('CALL', _('Call')),
|
("CALL", _("Call")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class News(models.Model):
|
class News(models.Model):
|
||||||
"""The news class"""
|
"""The news class"""
|
||||||
|
|
||||||
title = models.CharField(_("title"), max_length=64)
|
title = models.CharField(_("title"), max_length=64)
|
||||||
summary = models.TextField(_("summary"))
|
summary = models.TextField(_("summary"))
|
||||||
content = models.TextField(_("content"))
|
content = models.TextField(_("content"))
|
||||||
type = models.CharField(_("type"), max_length=16, choices=NEWS_TYPES, default="EVENT")
|
type = models.CharField(
|
||||||
|
_("type"), max_length=16, choices=NEWS_TYPES, default="EVENT"
|
||||||
|
)
|
||||||
club = models.ForeignKey(Club, related_name="news", verbose_name=_("club"))
|
club = models.ForeignKey(Club, related_name="news", verbose_name=_("club"))
|
||||||
author = models.ForeignKey(User, related_name="owned_news", verbose_name=_("author"))
|
author = models.ForeignKey(
|
||||||
|
User, related_name="owned_news", verbose_name=_("author")
|
||||||
|
)
|
||||||
is_moderated = models.BooleanField(_("is moderated"), default=False)
|
is_moderated = models.BooleanField(_("is moderated"), default=False)
|
||||||
moderator = models.ForeignKey(User, related_name="moderated_news", verbose_name=_("moderator"), null=True)
|
moderator = models.ForeignKey(
|
||||||
|
User, related_name="moderated_news", verbose_name=_("moderator"), null=True
|
||||||
|
)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user == self.author
|
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user == self.author
|
||||||
@ -85,7 +91,7 @@ class News(models.Model):
|
|||||||
return self.is_moderated or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return self.is_moderated or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('com:news_detail', kwargs={'news_id': self.id})
|
return reverse("com:news_detail", kwargs={"news_id": self.id})
|
||||||
|
|
||||||
def get_full_url(self):
|
def get_full_url(self):
|
||||||
return "https://%s%s" % (settings.SITH_URL, self.get_absolute_url())
|
return "https://%s%s" % (settings.SITH_URL, self.get_absolute_url())
|
||||||
@ -95,15 +101,28 @@ class News(models.Model):
|
|||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
super(News, self).save(*args, **kwargs)
|
super(News, self).save(*args, **kwargs)
|
||||||
for u in RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first().users.all():
|
for u in (
|
||||||
Notification(user=u, url=reverse("com:news_admin_list"),
|
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
type="NEWS_MODERATION", param="1").save()
|
.first()
|
||||||
|
.users.all()
|
||||||
|
):
|
||||||
|
Notification(
|
||||||
|
user=u,
|
||||||
|
url=reverse("com:news_admin_list"),
|
||||||
|
type="NEWS_MODERATION",
|
||||||
|
param="1",
|
||||||
|
).save()
|
||||||
|
|
||||||
|
|
||||||
def news_notification_callback(notif):
|
def news_notification_callback(notif):
|
||||||
count = News.objects.filter(
|
count = (
|
||||||
Q(dates__start_date__gt=timezone.now(), is_moderated=False) |
|
News.objects.filter(
|
||||||
Q(type="NOTICE", is_moderated=False)
|
Q(dates__start_date__gt=timezone.now(), is_moderated=False)
|
||||||
).distinct().count()
|
| Q(type="NOTICE", is_moderated=False)
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
|
.count()
|
||||||
|
)
|
||||||
if count:
|
if count:
|
||||||
notif.viewed = False
|
notif.viewed = False
|
||||||
notif.param = "%s" % count
|
notif.param = "%s" % count
|
||||||
@ -111,6 +130,7 @@ def news_notification_callback(notif):
|
|||||||
else:
|
else:
|
||||||
notif.viewed = True
|
notif.viewed = True
|
||||||
|
|
||||||
|
|
||||||
class NewsDate(models.Model):
|
class NewsDate(models.Model):
|
||||||
"""
|
"""
|
||||||
A date class, useful for weekly events, or for events that just have no date
|
A date class, useful for weekly events, or for events that just have no date
|
||||||
@ -118,9 +138,10 @@ class NewsDate(models.Model):
|
|||||||
This class allows more flexibilty managing the dates related to a news, particularly when this news is weekly, since
|
This class allows more flexibilty managing the dates related to a news, particularly when this news is weekly, since
|
||||||
we don't have to make copies
|
we don't have to make copies
|
||||||
"""
|
"""
|
||||||
|
|
||||||
news = models.ForeignKey(News, related_name="dates", verbose_name=_("news_date"))
|
news = models.ForeignKey(News, related_name="dates", verbose_name=_("news_date"))
|
||||||
start_date = models.DateTimeField(_('start_date'), null=True, blank=True)
|
start_date = models.DateTimeField(_("start_date"), null=True, blank=True)
|
||||||
end_date = models.DateTimeField(_('end_date'), null=True, blank=True)
|
end_date = models.DateTimeField(_("end_date"), null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s: %s - %s" % (self.news.title, self.start_date, self.end_date)
|
return "%s: %s - %s" % (self.news.title, self.start_date, self.end_date)
|
||||||
@ -130,6 +151,7 @@ class Weekmail(models.Model):
|
|||||||
"""
|
"""
|
||||||
The weekmail class
|
The weekmail class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = models.CharField(_("title"), max_length=64, blank=True)
|
title = models.CharField(_("title"), max_length=64, blank=True)
|
||||||
intro = models.TextField(_("intro"), blank=True)
|
intro = models.TextField(_("intro"), blank=True)
|
||||||
joke = models.TextField(_("joke"), blank=True)
|
joke = models.TextField(_("joke"), blank=True)
|
||||||
@ -138,16 +160,21 @@ class Weekmail(models.Model):
|
|||||||
sent = models.BooleanField(_("sent"), default=False)
|
sent = models.BooleanField(_("sent"), default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-id']
|
ordering = ["-id"]
|
||||||
|
|
||||||
def send(self):
|
def send(self):
|
||||||
dest = [i[0] for i in Preferences.objects.filter(receive_weekmail=True).values_list('user__email')]
|
dest = [
|
||||||
|
i[0]
|
||||||
|
for i in Preferences.objects.filter(receive_weekmail=True).values_list(
|
||||||
|
"user__email"
|
||||||
|
)
|
||||||
|
]
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
email = EmailMultiAlternatives(
|
email = EmailMultiAlternatives(
|
||||||
subject=self.title,
|
subject=self.title,
|
||||||
body=self.render_text(),
|
body=self.render_text(),
|
||||||
from_email=settings.SITH_COM_EMAIL,
|
from_email=settings.SITH_COM_EMAIL,
|
||||||
to=Sith.objects.first().weekmail_destinations.split(' '),
|
to=Sith.objects.first().weekmail_destinations.split(" "),
|
||||||
bcc=dest,
|
bcc=dest,
|
||||||
)
|
)
|
||||||
email.attach_alternative(self.render_html(), "text/html")
|
email.attach_alternative(self.render_html(), "text/html")
|
||||||
@ -157,14 +184,14 @@ class Weekmail(models.Model):
|
|||||||
Weekmail().save()
|
Weekmail().save()
|
||||||
|
|
||||||
def render_text(self):
|
def render_text(self):
|
||||||
return render(None, "com/weekmail_renderer_text.jinja", context={
|
return render(
|
||||||
'weekmail': self,
|
None, "com/weekmail_renderer_text.jinja", context={"weekmail": self}
|
||||||
}).content.decode('utf-8')
|
).content.decode("utf-8")
|
||||||
|
|
||||||
def render_html(self):
|
def render_html(self):
|
||||||
return render(None, "com/weekmail_renderer_html.jinja", context={
|
return render(
|
||||||
'weekmail': self,
|
None, "com/weekmail_renderer_html.jinja", context={"weekmail": self}
|
||||||
}).content.decode('utf-8')
|
).content.decode("utf-8")
|
||||||
|
|
||||||
def get_banner(self):
|
def get_banner(self):
|
||||||
return "http://" + settings.SITH_URL + static("com/img/weekmail_bannerA18.jpg")
|
return "http://" + settings.SITH_URL + static("com/img/weekmail_bannerA18.jpg")
|
||||||
@ -180,12 +207,18 @@ class Weekmail(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class WeekmailArticle(models.Model):
|
class WeekmailArticle(models.Model):
|
||||||
weekmail = models.ForeignKey(Weekmail, related_name="articles", verbose_name=_("weekmail"), null=True)
|
weekmail = models.ForeignKey(
|
||||||
|
Weekmail, related_name="articles", verbose_name=_("weekmail"), null=True
|
||||||
|
)
|
||||||
title = models.CharField(_("title"), max_length=64)
|
title = models.CharField(_("title"), max_length=64)
|
||||||
content = models.TextField(_("content"))
|
content = models.TextField(_("content"))
|
||||||
author = models.ForeignKey(User, related_name="owned_weekmail_articles", verbose_name=_("author"))
|
author = models.ForeignKey(
|
||||||
club = models.ForeignKey(Club, related_name="weekmail_articles", verbose_name=_("club"))
|
User, related_name="owned_weekmail_articles", verbose_name=_("author")
|
||||||
rank = models.IntegerField(_('rank'), default=-1)
|
)
|
||||||
|
club = models.ForeignKey(
|
||||||
|
Club, related_name="weekmail_articles", verbose_name=_("club")
|
||||||
|
)
|
||||||
|
rank = models.IntegerField(_("rank"), default=-1)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
@ -199,7 +232,9 @@ class Screen(models.Model):
|
|||||||
|
|
||||||
def active_posters(self):
|
def active_posters(self):
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
return self.posters.filter(is_moderated=True, date_begin__lte=now).filter(Q(date_end__isnull=True) | Q(date_end__gte=now))
|
return self.posters.filter(is_moderated=True, date_begin__lte=now).filter(
|
||||||
|
Q(date_end__isnull=True) | Q(date_end__gte=now)
|
||||||
|
)
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
@ -209,21 +244,40 @@ class Screen(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class Poster(models.Model):
|
class Poster(models.Model):
|
||||||
name = models.CharField(_("name"), blank=False, null=False, max_length=128, default="")
|
name = models.CharField(
|
||||||
|
_("name"), blank=False, null=False, max_length=128, default=""
|
||||||
|
)
|
||||||
file = models.ImageField(_("file"), null=False, upload_to="com/posters")
|
file = models.ImageField(_("file"), null=False, upload_to="com/posters")
|
||||||
club = models.ForeignKey(Club, related_name="posters", verbose_name=_("club"), null=False)
|
club = models.ForeignKey(
|
||||||
|
Club, related_name="posters", verbose_name=_("club"), null=False
|
||||||
|
)
|
||||||
screens = models.ManyToManyField(Screen, related_name="posters")
|
screens = models.ManyToManyField(Screen, related_name="posters")
|
||||||
date_begin = models.DateTimeField(blank=False, null=False, default=timezone.now)
|
date_begin = models.DateTimeField(blank=False, null=False, default=timezone.now)
|
||||||
date_end = models.DateTimeField(blank=True, null=True)
|
date_end = models.DateTimeField(blank=True, null=True)
|
||||||
display_time = models.IntegerField(_("display time"), blank=False, null=False, default=15)
|
display_time = models.IntegerField(
|
||||||
|
_("display time"), blank=False, null=False, default=15
|
||||||
|
)
|
||||||
is_moderated = models.BooleanField(_("is moderated"), default=False)
|
is_moderated = models.BooleanField(_("is moderated"), default=False)
|
||||||
moderator = models.ForeignKey(User, related_name="moderated_posters", verbose_name=_("moderator"), null=True, blank=True)
|
moderator = models.ForeignKey(
|
||||||
|
User,
|
||||||
|
related_name="moderated_posters",
|
||||||
|
verbose_name=_("moderator"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.is_moderated:
|
if not self.is_moderated:
|
||||||
for u in RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first().users.all():
|
for u in (
|
||||||
Notification(user=u, url=reverse("com:poster_moderate_list"),
|
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
type="POSTER_MODERATION").save()
|
.first()
|
||||||
|
.users.all()
|
||||||
|
):
|
||||||
|
Notification(
|
||||||
|
user=u,
|
||||||
|
url=reverse("com:poster_moderate_list"),
|
||||||
|
type="POSTER_MODERATION",
|
||||||
|
).save()
|
||||||
return super(Poster, self).save(*args, **kwargs)
|
return super(Poster, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def clean(self, *args, **kwargs):
|
def clean(self, *args, **kwargs):
|
||||||
@ -231,7 +285,9 @@ class Poster(models.Model):
|
|||||||
raise ValidationError(_("Begin date should be before end date"))
|
raise ValidationError(_("Begin date should be before end date"))
|
||||||
|
|
||||||
def is_owned_by(self, user):
|
def is_owned_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or Club.objects.filter(id__in=user.clubs_with_rights)
|
return user.is_in_group(
|
||||||
|
settings.SITH_GROUP_COM_ADMIN_ID
|
||||||
|
) or Club.objects.filter(id__in=user.clubs_with_rights)
|
||||||
|
|
||||||
def can_be_moderated_by(self, user):
|
def can_be_moderated_by(self, user):
|
||||||
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
34
com/tests.py
34
com/tests.py
@ -34,25 +34,43 @@ class ComTest(TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
call_command("populate")
|
call_command("populate")
|
||||||
self.skia = User.objects.filter(username="skia").first()
|
self.skia = User.objects.filter(username="skia").first()
|
||||||
self.com_group = RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first()
|
self.com_group = RealGroup.objects.filter(
|
||||||
|
id=settings.SITH_GROUP_COM_ADMIN_ID
|
||||||
|
).first()
|
||||||
self.skia.groups = [self.com_group]
|
self.skia.groups = [self.com_group]
|
||||||
self.skia.save()
|
self.skia.save()
|
||||||
self.client.login(username=self.skia.username, password='plop')
|
self.client.login(username=self.skia.username, password="plop")
|
||||||
|
|
||||||
def test_alert_msg(self):
|
def test_alert_msg(self):
|
||||||
response = self.client.post(reverse("com:alert_edit"), {"alert_msg": """
|
response = self.client.post(
|
||||||
|
reverse("com:alert_edit"),
|
||||||
|
{
|
||||||
|
"alert_msg": """
|
||||||
### ALERTE!
|
### ALERTE!
|
||||||
|
|
||||||
**Caaaataaaapuuuulte!!!!**
|
**Caaaataaaapuuuulte!!!!**
|
||||||
"""})
|
"""
|
||||||
|
},
|
||||||
|
)
|
||||||
r = self.client.get(reverse("core:index"))
|
r = self.client.get(reverse("core:index"))
|
||||||
self.assertTrue(r.status_code == 200)
|
self.assertTrue(r.status_code == 200)
|
||||||
self.assertTrue("""<div id="alert_box">\\n <div class="markdown"><h3>ALERTE!</h3>\\n<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""" in str(r.content))
|
self.assertTrue(
|
||||||
|
"""<div id="alert_box">\\n <div class="markdown"><h3>ALERTE!</h3>\\n<p><strong>Caaaataaaapuuuulte!!!!</strong></p>"""
|
||||||
|
in str(r.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_info_msg(self):
|
def test_info_msg(self):
|
||||||
response = self.client.post(reverse("com:info_edit"), {"info_msg": """
|
response = self.client.post(
|
||||||
|
reverse("com:info_edit"),
|
||||||
|
{
|
||||||
|
"info_msg": """
|
||||||
### INFO: **Caaaataaaapuuuulte!!!!**
|
### INFO: **Caaaataaaapuuuulte!!!!**
|
||||||
"""})
|
"""
|
||||||
|
},
|
||||||
|
)
|
||||||
r = self.client.get(reverse("core:index"))
|
r = self.client.get(reverse("core:index"))
|
||||||
self.assertTrue(r.status_code == 200)
|
self.assertTrue(r.status_code == 200)
|
||||||
self.assertTrue("""<div id="info_box">\\n <div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""" in str(r.content))
|
self.assertTrue(
|
||||||
|
"""<div id="info_box">\\n <div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>"""
|
||||||
|
in str(r.content)
|
||||||
|
)
|
||||||
|
121
com/urls.py
121
com/urls.py
@ -28,35 +28,94 @@ from com.views import *
|
|||||||
from club.views import MailingDeleteView
|
from club.views import MailingDeleteView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^sith/edit/alert$', AlertMsgEditView.as_view(), name='alert_edit'),
|
url(r"^sith/edit/alert$", AlertMsgEditView.as_view(), name="alert_edit"),
|
||||||
url(r'^sith/edit/info$', InfoMsgEditView.as_view(), name='info_edit'),
|
url(r"^sith/edit/info$", InfoMsgEditView.as_view(), name="info_edit"),
|
||||||
url(r'^sith/edit/index$', IndexEditView.as_view(), name='index_edit'),
|
url(r"^sith/edit/index$", IndexEditView.as_view(), name="index_edit"),
|
||||||
url(r'^sith/edit/weekmail_destinations$', WeekmailDestinationEditView.as_view(), name='weekmail_destinations'),
|
url(
|
||||||
url(r'^weekmail$', WeekmailEditView.as_view(), name='weekmail'),
|
r"^sith/edit/weekmail_destinations$",
|
||||||
url(r'^weekmail/preview$', WeekmailPreviewView.as_view(), name='weekmail_preview'),
|
WeekmailDestinationEditView.as_view(),
|
||||||
url(r'^weekmail/new_article$', WeekmailArticleCreateView.as_view(), name='weekmail_article'),
|
name="weekmail_destinations",
|
||||||
url(r'^weekmail/article/(?P<article_id>[0-9]+)/delete$', WeekmailArticleDeleteView.as_view(), name='weekmail_article_delete'),
|
),
|
||||||
url(r'^weekmail/article/(?P<article_id>[0-9]+)/edit$', WeekmailArticleEditView.as_view(), name='weekmail_article_edit'),
|
url(r"^weekmail$", WeekmailEditView.as_view(), name="weekmail"),
|
||||||
url(r'^news$', NewsListView.as_view(), name='news_list'),
|
url(r"^weekmail/preview$", WeekmailPreviewView.as_view(), name="weekmail_preview"),
|
||||||
url(r'^news/admin$', NewsAdminListView.as_view(), name='news_admin_list'),
|
url(
|
||||||
url(r'^news/create$', NewsCreateView.as_view(), name='news_new'),
|
r"^weekmail/new_article$",
|
||||||
url(r'^news/(?P<news_id>[0-9]+)/delete$', NewsDeleteView.as_view(), name='news_delete'),
|
WeekmailArticleCreateView.as_view(),
|
||||||
url(r'^news/(?P<news_id>[0-9]+)/moderate$', NewsModerateView.as_view(), name='news_moderate'),
|
name="weekmail_article",
|
||||||
url(r'^news/(?P<news_id>[0-9]+)/edit$', NewsEditView.as_view(), name='news_edit'),
|
),
|
||||||
url(r'^news/(?P<news_id>[0-9]+)$', NewsDetailView.as_view(), name='news_detail'),
|
url(
|
||||||
url(r'^mailings$', MailingListAdminView.as_view(), name='mailing_admin'),
|
r"^weekmail/article/(?P<article_id>[0-9]+)/delete$",
|
||||||
url(r'^mailings/(?P<mailing_id>[0-9]+)/moderate$', MailingModerateView.as_view(), name='mailing_moderate'),
|
WeekmailArticleDeleteView.as_view(),
|
||||||
url(r'^mailings/(?P<mailing_id>[0-9]+)/delete$', MailingDeleteView.as_view(redirect_page='com:mailing_admin'), name='mailing_delete'),
|
name="weekmail_article_delete",
|
||||||
url(r'^poster$', PosterListView.as_view(), name='poster_list'),
|
),
|
||||||
url(r'^poster/create$', PosterCreateView.as_view(), name='poster_create'),
|
url(
|
||||||
url(r'^poster/(?P<poster_id>[0-9]+)/edit$', PosterEditView.as_view(), name='poster_edit'),
|
r"^weekmail/article/(?P<article_id>[0-9]+)/edit$",
|
||||||
url(r'^poster/(?P<poster_id>[0-9]+)/delete$', PosterDeleteView.as_view(), name='poster_delete'),
|
WeekmailArticleEditView.as_view(),
|
||||||
url(r'^poster/moderate$', PosterModerateListView.as_view(), name='poster_moderate_list'),
|
name="weekmail_article_edit",
|
||||||
url(r'^poster/(?P<object_id>[0-9]+)/moderate$', PosterModerateView.as_view(), name='poster_moderate'),
|
),
|
||||||
url(r'^screen$', ScreenListView.as_view(), name='screen_list'),
|
url(r"^news$", NewsListView.as_view(), name="news_list"),
|
||||||
url(r'^screen/create$', ScreenCreateView.as_view(), name='screen_create'),
|
url(r"^news/admin$", NewsAdminListView.as_view(), name="news_admin_list"),
|
||||||
url(r'^screen/(?P<screen_id>[0-9]+)/slideshow$', ScreenSlideshowView.as_view(), name='screen_slideshow'),
|
url(r"^news/create$", NewsCreateView.as_view(), name="news_new"),
|
||||||
url(r'^screen/(?P<screen_id>[0-9]+)/edit$', ScreenEditView.as_view(), name='screen_edit'),
|
url(
|
||||||
url(r'^screen/(?P<screen_id>[0-9]+)/delete$', ScreenDeleteView.as_view(), name='screen_delete'),
|
r"^news/(?P<news_id>[0-9]+)/delete$",
|
||||||
|
NewsDeleteView.as_view(),
|
||||||
|
name="news_delete",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^news/(?P<news_id>[0-9]+)/moderate$",
|
||||||
|
NewsModerateView.as_view(),
|
||||||
|
name="news_moderate",
|
||||||
|
),
|
||||||
|
url(r"^news/(?P<news_id>[0-9]+)/edit$", NewsEditView.as_view(), name="news_edit"),
|
||||||
|
url(r"^news/(?P<news_id>[0-9]+)$", NewsDetailView.as_view(), name="news_detail"),
|
||||||
|
url(r"^mailings$", MailingListAdminView.as_view(), name="mailing_admin"),
|
||||||
|
url(
|
||||||
|
r"^mailings/(?P<mailing_id>[0-9]+)/moderate$",
|
||||||
|
MailingModerateView.as_view(),
|
||||||
|
name="mailing_moderate",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^mailings/(?P<mailing_id>[0-9]+)/delete$",
|
||||||
|
MailingDeleteView.as_view(redirect_page="com:mailing_admin"),
|
||||||
|
name="mailing_delete",
|
||||||
|
),
|
||||||
|
url(r"^poster$", PosterListView.as_view(), name="poster_list"),
|
||||||
|
url(r"^poster/create$", PosterCreateView.as_view(), name="poster_create"),
|
||||||
|
url(
|
||||||
|
r"^poster/(?P<poster_id>[0-9]+)/edit$",
|
||||||
|
PosterEditView.as_view(),
|
||||||
|
name="poster_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^poster/(?P<poster_id>[0-9]+)/delete$",
|
||||||
|
PosterDeleteView.as_view(),
|
||||||
|
name="poster_delete",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^poster/moderate$",
|
||||||
|
PosterModerateListView.as_view(),
|
||||||
|
name="poster_moderate_list",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^poster/(?P<object_id>[0-9]+)/moderate$",
|
||||||
|
PosterModerateView.as_view(),
|
||||||
|
name="poster_moderate",
|
||||||
|
),
|
||||||
|
url(r"^screen$", ScreenListView.as_view(), name="screen_list"),
|
||||||
|
url(r"^screen/create$", ScreenCreateView.as_view(), name="screen_create"),
|
||||||
|
url(
|
||||||
|
r"^screen/(?P<screen_id>[0-9]+)/slideshow$",
|
||||||
|
ScreenSlideshowView.as_view(),
|
||||||
|
name="screen_slideshow",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^screen/(?P<screen_id>[0-9]+)/edit$",
|
||||||
|
ScreenEditView.as_view(),
|
||||||
|
name="screen_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^screen/(?P<screen_id>[0-9]+)/delete$",
|
||||||
|
ScreenDeleteView.as_view(),
|
||||||
|
name="screen_delete",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
559
com/views.py
559
com/views.py
@ -41,7 +41,14 @@ from django import forms
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle, Screen, Poster
|
from com.models import Sith, News, NewsDate, Weekmail, WeekmailArticle, Screen, Poster
|
||||||
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, CanCreateMixin, QuickNotifMixin
|
from core.views import (
|
||||||
|
CanViewMixin,
|
||||||
|
CanEditMixin,
|
||||||
|
CanEditPropMixin,
|
||||||
|
TabedViewMixin,
|
||||||
|
CanCreateMixin,
|
||||||
|
QuickNotifMixin,
|
||||||
|
)
|
||||||
from core.views.forms import SelectDateTime
|
from core.views.forms import SelectDateTime
|
||||||
from core.models import Notification, RealGroup, User
|
from core.models import Notification, RealGroup, User
|
||||||
from club.models import Club, Mailing
|
from club.models import Club, Mailing
|
||||||
@ -55,23 +62,40 @@ sith = Sith.objects.first
|
|||||||
class PosterForm(forms.ModelForm):
|
class PosterForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Poster
|
model = Poster
|
||||||
fields = ['name', 'file', 'club', 'screens', 'date_begin', 'date_end', 'display_time']
|
fields = [
|
||||||
widgets = {
|
"name",
|
||||||
'screens': forms.CheckboxSelectMultiple,
|
"file",
|
||||||
}
|
"club",
|
||||||
|
"screens",
|
||||||
|
"date_begin",
|
||||||
|
"date_end",
|
||||||
|
"display_time",
|
||||||
|
]
|
||||||
|
widgets = {"screens": forms.CheckboxSelectMultiple}
|
||||||
|
|
||||||
date_begin = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Start date"),
|
date_begin = forms.DateTimeField(
|
||||||
widget=SelectDateTime, required=True, initial=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
|
["%Y-%m-%d %H:%M:%S"],
|
||||||
date_end = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End date"),
|
label=_("Start date"),
|
||||||
widget=SelectDateTime, required=False)
|
widget=SelectDateTime,
|
||||||
|
required=True,
|
||||||
|
initial=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
)
|
||||||
|
date_end = forms.DateTimeField(
|
||||||
|
["%Y-%m-%d %H:%M:%S"],
|
||||||
|
label=_("End date"),
|
||||||
|
widget=SelectDateTime,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.user = kwargs.pop('user', None)
|
self.user = kwargs.pop("user", None)
|
||||||
super(PosterForm, self).__init__(*args, **kwargs)
|
super(PosterForm, self).__init__(*args, **kwargs)
|
||||||
if self.user:
|
if self.user:
|
||||||
if not self.user.is_com_admin:
|
if not self.user.is_com_admin:
|
||||||
self.fields['club'].queryset = Club.objects.filter(id__in=self.user.clubs_with_rights)
|
self.fields["club"].queryset = Club.objects.filter(
|
||||||
self.fields.pop('display_time')
|
id__in=self.user.clubs_with_rights
|
||||||
|
)
|
||||||
|
self.fields.pop("display_time")
|
||||||
|
|
||||||
|
|
||||||
class ComTabsMixin(TabedViewMixin):
|
class ComTabsMixin(TabedViewMixin):
|
||||||
@ -80,51 +104,54 @@ class ComTabsMixin(TabedViewMixin):
|
|||||||
|
|
||||||
def get_list_of_tabs(self):
|
def get_list_of_tabs(self):
|
||||||
tab_list = []
|
tab_list = []
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('com:weekmail'),
|
{"url": reverse("com:weekmail"), "slug": "weekmail", "name": _("Weekmail")}
|
||||||
'slug': 'weekmail',
|
)
|
||||||
'name': _("Weekmail"),
|
tab_list.append(
|
||||||
})
|
{
|
||||||
tab_list.append({
|
"url": reverse("com:weekmail_destinations"),
|
||||||
'url': reverse('com:weekmail_destinations'),
|
"slug": "weekmail_destinations",
|
||||||
'slug': 'weekmail_destinations',
|
"name": _("Weekmail destinations"),
|
||||||
'name': _("Weekmail destinations"),
|
}
|
||||||
})
|
)
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('com:index_edit'),
|
{"url": reverse("com:index_edit"), "slug": "index", "name": _("Index page")}
|
||||||
'slug': 'index',
|
)
|
||||||
'name': _("Index page"),
|
tab_list.append(
|
||||||
})
|
{"url": reverse("com:info_edit"), "slug": "info", "name": _("Info message")}
|
||||||
tab_list.append({
|
)
|
||||||
'url': reverse('com:info_edit'),
|
tab_list.append(
|
||||||
'slug': 'info',
|
{
|
||||||
'name': _("Info message"),
|
"url": reverse("com:alert_edit"),
|
||||||
})
|
"slug": "alert",
|
||||||
tab_list.append({
|
"name": _("Alert message"),
|
||||||
'url': reverse('com:alert_edit'),
|
}
|
||||||
'slug': 'alert',
|
)
|
||||||
'name': _("Alert message"),
|
tab_list.append(
|
||||||
})
|
{
|
||||||
tab_list.append({
|
"url": reverse("com:mailing_admin"),
|
||||||
'url': reverse('com:mailing_admin'),
|
"slug": "mailings",
|
||||||
'slug': 'mailings',
|
"name": _("Mailing lists administration"),
|
||||||
'name': _("Mailing lists administration"),
|
}
|
||||||
})
|
)
|
||||||
tab_list.append({
|
tab_list.append(
|
||||||
'url': reverse('com:poster_list'),
|
{
|
||||||
'slug': 'posters',
|
"url": reverse("com:poster_list"),
|
||||||
'name': _("Posters list"),
|
"slug": "posters",
|
||||||
})
|
"name": _("Posters list"),
|
||||||
tab_list.append({
|
}
|
||||||
'url': reverse('com:screen_list'),
|
)
|
||||||
'slug': 'screens',
|
tab_list.append(
|
||||||
'name': _("Screens list"),
|
{
|
||||||
})
|
"url": reverse("com:screen_list"),
|
||||||
|
"slug": "screens",
|
||||||
|
"name": _("Screens list"),
|
||||||
|
}
|
||||||
|
)
|
||||||
return tab_list
|
return tab_list
|
||||||
|
|
||||||
|
|
||||||
class IsComAdminMixin(View):
|
class IsComAdminMixin(View):
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)):
|
if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
@ -133,34 +160,35 @@ class IsComAdminMixin(View):
|
|||||||
|
|
||||||
class ComEditView(ComTabsMixin, CanEditPropMixin, UpdateView):
|
class ComEditView(ComTabsMixin, CanEditPropMixin, UpdateView):
|
||||||
model = Sith
|
model = Sith
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
return Sith.objects.first()
|
return Sith.objects.first()
|
||||||
|
|
||||||
|
|
||||||
class AlertMsgEditView(ComEditView):
|
class AlertMsgEditView(ComEditView):
|
||||||
fields = ['alert_msg']
|
fields = ["alert_msg"]
|
||||||
current_tab = "alert"
|
current_tab = "alert"
|
||||||
success_url = reverse_lazy('com:alert_edit')
|
success_url = reverse_lazy("com:alert_edit")
|
||||||
|
|
||||||
|
|
||||||
class InfoMsgEditView(ComEditView):
|
class InfoMsgEditView(ComEditView):
|
||||||
fields = ['info_msg']
|
fields = ["info_msg"]
|
||||||
current_tab = "info"
|
current_tab = "info"
|
||||||
success_url = reverse_lazy('com:info_edit')
|
success_url = reverse_lazy("com:info_edit")
|
||||||
|
|
||||||
|
|
||||||
class IndexEditView(ComEditView):
|
class IndexEditView(ComEditView):
|
||||||
fields = ['index_page']
|
fields = ["index_page"]
|
||||||
current_tab = "index"
|
current_tab = "index"
|
||||||
success_url = reverse_lazy('com:index_edit')
|
success_url = reverse_lazy("com:index_edit")
|
||||||
|
|
||||||
|
|
||||||
class WeekmailDestinationEditView(ComEditView):
|
class WeekmailDestinationEditView(ComEditView):
|
||||||
fields = ['weekmail_destinations']
|
fields = ["weekmail_destinations"]
|
||||||
current_tab = "weekmail_destinations"
|
current_tab = "weekmail_destinations"
|
||||||
success_url = reverse_lazy('com:weekmail_destinations')
|
success_url = reverse_lazy("com:weekmail_destinations")
|
||||||
|
|
||||||
|
|
||||||
# News
|
# News
|
||||||
|
|
||||||
@ -168,43 +196,64 @@ class WeekmailDestinationEditView(ComEditView):
|
|||||||
class NewsForm(forms.ModelForm):
|
class NewsForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = News
|
model = News
|
||||||
fields = ['type', 'title', 'club', 'summary', 'content', 'author']
|
fields = ["type", "title", "club", "summary", "content", "author"]
|
||||||
widgets = {
|
widgets = {"author": forms.HiddenInput, "type": forms.RadioSelect}
|
||||||
'author': forms.HiddenInput,
|
|
||||||
'type': forms.RadioSelect,
|
start_date = forms.DateTimeField(
|
||||||
}
|
["%Y-%m-%d %H:%M:%S"],
|
||||||
start_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Start date"), widget=SelectDateTime, required=False)
|
label=_("Start date"),
|
||||||
end_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End date"), widget=SelectDateTime, required=False)
|
widget=SelectDateTime,
|
||||||
until = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Until"), widget=SelectDateTime, required=False)
|
required=False,
|
||||||
|
)
|
||||||
|
end_date = forms.DateTimeField(
|
||||||
|
["%Y-%m-%d %H:%M:%S"],
|
||||||
|
label=_("End date"),
|
||||||
|
widget=SelectDateTime,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
until = forms.DateTimeField(
|
||||||
|
["%Y-%m-%d %H:%M:%S"], label=_("Until"), widget=SelectDateTime, required=False
|
||||||
|
)
|
||||||
automoderation = forms.BooleanField(label=_("Automoderation"), required=False)
|
automoderation = forms.BooleanField(label=_("Automoderation"), required=False)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
self.cleaned_data = super(NewsForm, self).clean()
|
self.cleaned_data = super(NewsForm, self).clean()
|
||||||
if self.cleaned_data['type'] != "NOTICE":
|
if self.cleaned_data["type"] != "NOTICE":
|
||||||
if not self.cleaned_data['start_date']:
|
if not self.cleaned_data["start_date"]:
|
||||||
self.add_error('start_date', ValidationError(_("This field is required.")))
|
self.add_error(
|
||||||
if not self.cleaned_data['end_date']:
|
"start_date", ValidationError(_("This field is required."))
|
||||||
self.add_error('end_date', ValidationError(_("This field is required.")))
|
)
|
||||||
if self.cleaned_data['start_date'] > self.cleaned_data['end_date']:
|
if not self.cleaned_data["end_date"]:
|
||||||
self.add_error('end_date', ValidationError(_("You crazy? You can not finish an event before starting it.")))
|
self.add_error(
|
||||||
if self.cleaned_data['type'] == "WEEKLY" and not self.cleaned_data['until']:
|
"end_date", ValidationError(_("This field is required."))
|
||||||
self.add_error('until', ValidationError(_("This field is required.")))
|
)
|
||||||
|
if self.cleaned_data["start_date"] > self.cleaned_data["end_date"]:
|
||||||
|
self.add_error(
|
||||||
|
"end_date",
|
||||||
|
ValidationError(
|
||||||
|
_("You crazy? You can not finish an event before starting it.")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if self.cleaned_data["type"] == "WEEKLY" and not self.cleaned_data["until"]:
|
||||||
|
self.add_error("until", ValidationError(_("This field is required.")))
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
ret = super(NewsForm, self).save()
|
ret = super(NewsForm, self).save()
|
||||||
self.instance.dates.all().delete()
|
self.instance.dates.all().delete()
|
||||||
if self.instance.type == "EVENT" or self.instance.type == "CALL":
|
if self.instance.type == "EVENT" or self.instance.type == "CALL":
|
||||||
NewsDate(start_date=self.cleaned_data['start_date'],
|
NewsDate(
|
||||||
end_date=self.cleaned_data['end_date'],
|
start_date=self.cleaned_data["start_date"],
|
||||||
news=self.instance).save()
|
end_date=self.cleaned_data["end_date"],
|
||||||
|
news=self.instance,
|
||||||
|
).save()
|
||||||
elif self.instance.type == "WEEKLY":
|
elif self.instance.type == "WEEKLY":
|
||||||
start_date = self.cleaned_data['start_date']
|
start_date = self.cleaned_data["start_date"]
|
||||||
end_date = self.cleaned_data['end_date']
|
end_date = self.cleaned_data["end_date"]
|
||||||
while start_date <= self.cleaned_data['until']:
|
while start_date <= self.cleaned_data["until"]:
|
||||||
NewsDate(start_date=start_date,
|
NewsDate(
|
||||||
end_date=end_date,
|
start_date=start_date, end_date=end_date, news=self.instance
|
||||||
news=self.instance).save()
|
).save()
|
||||||
start_date += timedelta(days=7)
|
start_date += timedelta(days=7)
|
||||||
end_date += timedelta(days=7)
|
end_date += timedelta(days=7)
|
||||||
return ret
|
return ret
|
||||||
@ -213,59 +262,81 @@ class NewsForm(forms.ModelForm):
|
|||||||
class NewsEditView(CanEditMixin, UpdateView):
|
class NewsEditView(CanEditMixin, UpdateView):
|
||||||
model = News
|
model = News
|
||||||
form_class = NewsForm
|
form_class = NewsForm
|
||||||
template_name = 'com/news_edit.jinja'
|
template_name = "com/news_edit.jinja"
|
||||||
pk_url_kwarg = 'news_id'
|
pk_url_kwarg = "news_id"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
init = {}
|
init = {}
|
||||||
try:
|
try:
|
||||||
init['start_date'] = self.object.dates.order_by('id').first().start_date.strftime('%Y-%m-%d %H:%M:%S')
|
init["start_date"] = (
|
||||||
|
self.object.dates.order_by("id")
|
||||||
|
.first()
|
||||||
|
.start_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
init['end_date'] = self.object.dates.order_by('id').first().end_date.strftime('%Y-%m-%d %H:%M:%S')
|
init["end_date"] = (
|
||||||
|
self.object.dates.order_by("id")
|
||||||
|
.first()
|
||||||
|
.end_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return init
|
return init
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
if form.is_valid() and 'preview' not in request.POST.keys():
|
if form.is_valid() and "preview" not in request.POST.keys():
|
||||||
return self.form_valid(form)
|
return self.form_valid(form)
|
||||||
else:
|
else:
|
||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
self.object = form.save()
|
self.object = form.save()
|
||||||
if form.cleaned_data['automoderation'] and self.request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID):
|
if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
|
||||||
|
settings.SITH_GROUP_COM_ADMIN_ID
|
||||||
|
):
|
||||||
self.object.moderator = self.request.user
|
self.object.moderator = self.request.user
|
||||||
self.object.is_moderated = True
|
self.object.is_moderated = True
|
||||||
self.object.save()
|
self.object.save()
|
||||||
else:
|
else:
|
||||||
self.object.is_moderated = False
|
self.object.is_moderated = False
|
||||||
self.object.save()
|
self.object.save()
|
||||||
for u in RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first().users.all():
|
for u in (
|
||||||
if not u.notifications.filter(type="NEWS_MODERATION", viewed=False).exists():
|
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
Notification(user=u, url=reverse("com:news_detail", kwargs={'news_id': self.object.id}), type="NEWS_MODERATION").save()
|
.first()
|
||||||
|
.users.all()
|
||||||
|
):
|
||||||
|
if not u.notifications.filter(
|
||||||
|
type="NEWS_MODERATION", viewed=False
|
||||||
|
).exists():
|
||||||
|
Notification(
|
||||||
|
user=u,
|
||||||
|
url=reverse(
|
||||||
|
"com:news_detail", kwargs={"news_id": self.object.id}
|
||||||
|
),
|
||||||
|
type="NEWS_MODERATION",
|
||||||
|
).save()
|
||||||
return super(NewsEditView, self).form_valid(form)
|
return super(NewsEditView, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class NewsCreateView(CanCreateMixin, CreateView):
|
class NewsCreateView(CanCreateMixin, CreateView):
|
||||||
model = News
|
model = News
|
||||||
form_class = NewsForm
|
form_class = NewsForm
|
||||||
template_name = 'com/news_edit.jinja'
|
template_name = "com/news_edit.jinja"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
init = {'author': self.request.user}
|
init = {"author": self.request.user}
|
||||||
try:
|
try:
|
||||||
init['club'] = Club.objects.filter(id=self.request.GET['club']).first()
|
init["club"] = Club.objects.filter(id=self.request.GET["club"]).first()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return init
|
return init
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
if form.is_valid() and 'preview' not in request.POST.keys():
|
if form.is_valid() and "preview" not in request.POST.keys():
|
||||||
return self.form_valid(form)
|
return self.form_valid(form)
|
||||||
else:
|
else:
|
||||||
self.object = form.instance
|
self.object = form.instance
|
||||||
@ -273,176 +344,216 @@ class NewsCreateView(CanCreateMixin, CreateView):
|
|||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
self.object = form.save()
|
self.object = form.save()
|
||||||
if form.cleaned_data['automoderation'] and self.request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID):
|
if form.cleaned_data["automoderation"] and self.request.user.is_in_group(
|
||||||
|
settings.SITH_GROUP_COM_ADMIN_ID
|
||||||
|
):
|
||||||
self.object.moderator = self.request.user
|
self.object.moderator = self.request.user
|
||||||
self.object.is_moderated = True
|
self.object.is_moderated = True
|
||||||
self.object.save()
|
self.object.save()
|
||||||
else:
|
else:
|
||||||
for u in RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID).first().users.all():
|
for u in (
|
||||||
if not u.notifications.filter(type="NEWS_MODERATION", viewed=False).exists():
|
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
Notification(user=u, url=reverse("com:news_admin_list"), type="NEWS_MODERATION").save()
|
.first()
|
||||||
|
.users.all()
|
||||||
|
):
|
||||||
|
if not u.notifications.filter(
|
||||||
|
type="NEWS_MODERATION", viewed=False
|
||||||
|
).exists():
|
||||||
|
Notification(
|
||||||
|
user=u,
|
||||||
|
url=reverse("com:news_admin_list"),
|
||||||
|
type="NEWS_MODERATION",
|
||||||
|
).save()
|
||||||
return super(NewsCreateView, self).form_valid(form)
|
return super(NewsCreateView, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class NewsDeleteView(CanEditMixin, DeleteView):
|
class NewsDeleteView(CanEditMixin, DeleteView):
|
||||||
model = News
|
model = News
|
||||||
pk_url_kwarg = 'news_id'
|
pk_url_kwarg = "news_id"
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
success_url = reverse_lazy('com:news_admin_list')
|
success_url = reverse_lazy("com:news_admin_list")
|
||||||
|
|
||||||
|
|
||||||
class NewsModerateView(CanEditMixin, SingleObjectMixin):
|
class NewsModerateView(CanEditMixin, SingleObjectMixin):
|
||||||
model = News
|
model = News
|
||||||
pk_url_kwarg = 'news_id'
|
pk_url_kwarg = "news_id"
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
if 'remove' in request.GET.keys():
|
if "remove" in request.GET.keys():
|
||||||
self.object.is_moderated = False
|
self.object.is_moderated = False
|
||||||
else:
|
else:
|
||||||
self.object.is_moderated = True
|
self.object.is_moderated = True
|
||||||
self.object.moderator = request.user
|
self.object.moderator = request.user
|
||||||
self.object.save()
|
self.object.save()
|
||||||
if 'next' in self.request.GET.keys():
|
if "next" in self.request.GET.keys():
|
||||||
return redirect(self.request.GET['next'])
|
return redirect(self.request.GET["next"])
|
||||||
return redirect('com:news_admin_list')
|
return redirect("com:news_admin_list")
|
||||||
|
|
||||||
|
|
||||||
class NewsAdminListView(CanEditMixin, ListView):
|
class NewsAdminListView(CanEditMixin, ListView):
|
||||||
model = News
|
model = News
|
||||||
template_name = 'com/news_admin_list.jinja'
|
template_name = "com/news_admin_list.jinja"
|
||||||
queryset = News.objects.all()
|
queryset = News.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class NewsListView(CanViewMixin, ListView):
|
class NewsListView(CanViewMixin, ListView):
|
||||||
model = News
|
model = News
|
||||||
template_name = 'com/news_list.jinja'
|
template_name = "com/news_list.jinja"
|
||||||
queryset = News.objects.filter(is_moderated=True)
|
queryset = News.objects.filter(is_moderated=True)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(NewsListView, self).get_context_data(**kwargs)
|
kwargs = super(NewsListView, self).get_context_data(**kwargs)
|
||||||
kwargs['NewsDate'] = NewsDate
|
kwargs["NewsDate"] = NewsDate
|
||||||
kwargs['timedelta'] = timedelta
|
kwargs["timedelta"] = timedelta
|
||||||
kwargs['birthdays'] = User.objects\
|
kwargs["birthdays"] = (
|
||||||
.filter(date_of_birth__month=timezone.now().month, date_of_birth__day=timezone.now().day)\
|
User.objects.filter(
|
||||||
.filter(role__in=['STUDENT', 'FORMER STUDENT'])\
|
date_of_birth__month=timezone.now().month,
|
||||||
.order_by('-date_of_birth')
|
date_of_birth__day=timezone.now().day,
|
||||||
|
)
|
||||||
|
.filter(role__in=["STUDENT", "FORMER STUDENT"])
|
||||||
|
.order_by("-date_of_birth")
|
||||||
|
)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class NewsDetailView(CanViewMixin, DetailView):
|
class NewsDetailView(CanViewMixin, DetailView):
|
||||||
model = News
|
model = News
|
||||||
template_name = 'com/news_detail.jinja'
|
template_name = "com/news_detail.jinja"
|
||||||
pk_url_kwarg = 'news_id'
|
pk_url_kwarg = "news_id"
|
||||||
|
|
||||||
|
|
||||||
# Weekmail
|
# Weekmail
|
||||||
|
|
||||||
|
|
||||||
class WeekmailPreviewView(ComTabsMixin, CanEditPropMixin, DetailView):
|
class WeekmailPreviewView(ComTabsMixin, CanEditPropMixin, DetailView):
|
||||||
model = Weekmail
|
model = Weekmail
|
||||||
template_name = 'com/weekmail_preview.jinja'
|
template_name = "com/weekmail_preview.jinja"
|
||||||
success_url = reverse_lazy('com:weekmail')
|
success_url = reverse_lazy("com:weekmail")
|
||||||
current_tab = "weekmail"
|
current_tab = "weekmail"
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
try:
|
try:
|
||||||
if request.POST['send'] == "validate":
|
if request.POST["send"] == "validate":
|
||||||
self.object.send()
|
self.object.send()
|
||||||
return HttpResponseRedirect(reverse('com:weekmail') + "?qn_weekmail_send_success")
|
return HttpResponseRedirect(
|
||||||
|
reverse("com:weekmail") + "?qn_weekmail_send_success"
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return super(WeekmailEditView, self).get(request, *args, **kwargs)
|
return super(WeekmailEditView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
return self.model.objects.filter(sent=False).order_by('-id').first()
|
return self.model.objects.filter(sent=False).order_by("-id").first()
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""Add rendered weekmail"""
|
"""Add rendered weekmail"""
|
||||||
kwargs = super(WeekmailPreviewView, self).get_context_data(**kwargs)
|
kwargs = super(WeekmailPreviewView, self).get_context_data(**kwargs)
|
||||||
kwargs['weekmail_rendered'] = self.object.render_html()
|
kwargs["weekmail_rendered"] = self.object.render_html()
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class WeekmailEditView(ComTabsMixin, QuickNotifMixin, CanEditPropMixin, UpdateView):
|
class WeekmailEditView(ComTabsMixin, QuickNotifMixin, CanEditPropMixin, UpdateView):
|
||||||
model = Weekmail
|
model = Weekmail
|
||||||
template_name = 'com/weekmail.jinja'
|
template_name = "com/weekmail.jinja"
|
||||||
form_class = modelform_factory(Weekmail, fields=['title', 'intro', 'joke', 'protip', 'conclusion'],
|
form_class = modelform_factory(
|
||||||
help_texts={'title': _("Delete and save to regenerate")})
|
Weekmail,
|
||||||
success_url = reverse_lazy('com:weekmail')
|
fields=["title", "intro", "joke", "protip", "conclusion"],
|
||||||
|
help_texts={"title": _("Delete and save to regenerate")},
|
||||||
|
)
|
||||||
|
success_url = reverse_lazy("com:weekmail")
|
||||||
current_tab = "weekmail"
|
current_tab = "weekmail"
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
weekmail = self.model.objects.filter(sent=False).order_by('-id').first()
|
weekmail = self.model.objects.filter(sent=False).order_by("-id").first()
|
||||||
if not weekmail.title:
|
if not weekmail.title:
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
weekmail.title = _("Weekmail of the ") + (now + timedelta(days=6 - now.weekday())).strftime('%d/%m/%Y')
|
weekmail.title = _("Weekmail of the ") + (
|
||||||
|
now + timedelta(days=6 - now.weekday())
|
||||||
|
).strftime("%d/%m/%Y")
|
||||||
weekmail.save()
|
weekmail.save()
|
||||||
return weekmail
|
return weekmail
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
if 'up_article' in request.GET.keys():
|
if "up_article" in request.GET.keys():
|
||||||
art = get_object_or_404(WeekmailArticle, id=request.GET['up_article'], weekmail=self.object)
|
art = get_object_or_404(
|
||||||
prev_art = self.object.articles.order_by('rank').filter(rank__lt=art.rank).last()
|
WeekmailArticle, id=request.GET["up_article"], weekmail=self.object
|
||||||
|
)
|
||||||
|
prev_art = (
|
||||||
|
self.object.articles.order_by("rank").filter(rank__lt=art.rank).last()
|
||||||
|
)
|
||||||
if prev_art:
|
if prev_art:
|
||||||
art.rank, prev_art.rank = prev_art.rank, art.rank
|
art.rank, prev_art.rank = prev_art.rank, art.rank
|
||||||
art.save()
|
art.save()
|
||||||
prev_art.save()
|
prev_art.save()
|
||||||
self.quick_notif_list += ['qn_success']
|
self.quick_notif_list += ["qn_success"]
|
||||||
if 'down_article' in request.GET.keys():
|
if "down_article" in request.GET.keys():
|
||||||
art = get_object_or_404(WeekmailArticle, id=request.GET['down_article'], weekmail=self.object)
|
art = get_object_or_404(
|
||||||
next_art = self.object.articles.order_by('rank').filter(rank__gt=art.rank).first()
|
WeekmailArticle, id=request.GET["down_article"], weekmail=self.object
|
||||||
|
)
|
||||||
|
next_art = (
|
||||||
|
self.object.articles.order_by("rank").filter(rank__gt=art.rank).first()
|
||||||
|
)
|
||||||
if next_art:
|
if next_art:
|
||||||
art.rank, next_art.rank = next_art.rank, art.rank
|
art.rank, next_art.rank = next_art.rank, art.rank
|
||||||
art.save()
|
art.save()
|
||||||
next_art.save()
|
next_art.save()
|
||||||
self.quick_notif_list += ['qn_success']
|
self.quick_notif_list += ["qn_success"]
|
||||||
if 'add_article' in request.GET.keys():
|
if "add_article" in request.GET.keys():
|
||||||
art = get_object_or_404(WeekmailArticle, id=request.GET['add_article'], weekmail=None)
|
art = get_object_or_404(
|
||||||
|
WeekmailArticle, id=request.GET["add_article"], weekmail=None
|
||||||
|
)
|
||||||
art.weekmail = self.object
|
art.weekmail = self.object
|
||||||
art.rank = self.object.articles.aggregate(Max('rank'))['rank__max'] or 0
|
art.rank = self.object.articles.aggregate(Max("rank"))["rank__max"] or 0
|
||||||
art.rank += 1
|
art.rank += 1
|
||||||
art.save()
|
art.save()
|
||||||
self.quick_notif_list += ['qn_success']
|
self.quick_notif_list += ["qn_success"]
|
||||||
if 'del_article' in request.GET.keys():
|
if "del_article" in request.GET.keys():
|
||||||
art = get_object_or_404(WeekmailArticle, id=request.GET['del_article'], weekmail=self.object)
|
art = get_object_or_404(
|
||||||
|
WeekmailArticle, id=request.GET["del_article"], weekmail=self.object
|
||||||
|
)
|
||||||
art.weekmail = None
|
art.weekmail = None
|
||||||
art.rank = -1
|
art.rank = -1
|
||||||
art.save()
|
art.save()
|
||||||
self.quick_notif_list += ['qn_success']
|
self.quick_notif_list += ["qn_success"]
|
||||||
return super(WeekmailEditView, self).get(request, *args, **kwargs)
|
return super(WeekmailEditView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""Add orphan articles """
|
"""Add orphan articles """
|
||||||
kwargs = super(WeekmailEditView, self).get_context_data(**kwargs)
|
kwargs = super(WeekmailEditView, self).get_context_data(**kwargs)
|
||||||
kwargs['orphans'] = WeekmailArticle.objects.filter(weekmail=None)
|
kwargs["orphans"] = WeekmailArticle.objects.filter(weekmail=None)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class WeekmailArticleEditView(ComTabsMixin, QuickNotifMixin, CanEditPropMixin, UpdateView):
|
class WeekmailArticleEditView(
|
||||||
|
ComTabsMixin, QuickNotifMixin, CanEditPropMixin, UpdateView
|
||||||
|
):
|
||||||
"""Edit an article"""
|
"""Edit an article"""
|
||||||
|
|
||||||
model = WeekmailArticle
|
model = WeekmailArticle
|
||||||
fields = ['title', 'club', 'content']
|
fields = ["title", "club", "content"]
|
||||||
pk_url_kwarg = "article_id"
|
pk_url_kwarg = "article_id"
|
||||||
template_name = 'core/edit.jinja'
|
template_name = "core/edit.jinja"
|
||||||
success_url = reverse_lazy('com:weekmail')
|
success_url = reverse_lazy("com:weekmail")
|
||||||
quick_notif_url_arg = "qn_weekmail_article_edit"
|
quick_notif_url_arg = "qn_weekmail_article_edit"
|
||||||
current_tab = "weekmail"
|
current_tab = "weekmail"
|
||||||
|
|
||||||
|
|
||||||
class WeekmailArticleCreateView(QuickNotifMixin, CreateView):
|
class WeekmailArticleCreateView(QuickNotifMixin, CreateView):
|
||||||
"""Post an article"""
|
"""Post an article"""
|
||||||
|
|
||||||
model = WeekmailArticle
|
model = WeekmailArticle
|
||||||
fields = ['title', 'club', 'content']
|
fields = ["title", "club", "content"]
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
success_url = reverse_lazy('core:user_tools')
|
success_url = reverse_lazy("core:user_tools")
|
||||||
quick_notif_url_arg = "qn_weekmail_new_article"
|
quick_notif_url_arg = "qn_weekmail_new_article"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
init = {}
|
init = {}
|
||||||
try:
|
try:
|
||||||
init['club'] = Club.objects.filter(id=self.request.GET['club']).first()
|
init["club"] = Club.objects.filter(id=self.request.GET["club"]).first()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return init
|
return init
|
||||||
@ -456,8 +567,15 @@ class WeekmailArticleCreateView(QuickNotifMixin, CreateView):
|
|||||||
if m.role <= settings.SITH_MAXIMUM_FREE_ROLE:
|
if m.role <= settings.SITH_MAXIMUM_FREE_ROLE:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
form.add_error('club', ValidationError(_("You must be a board member of the selected club to post in the Weekmail.")))
|
form.add_error(
|
||||||
if form.is_valid() and not 'preview' in request.POST.keys():
|
"club",
|
||||||
|
ValidationError(
|
||||||
|
_(
|
||||||
|
"You must be a board member of the selected club to post in the Weekmail."
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if form.is_valid() and not "preview" in request.POST.keys():
|
||||||
return self.form_valid(form)
|
return self.form_valid(form)
|
||||||
else:
|
else:
|
||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
@ -469,9 +587,10 @@ class WeekmailArticleCreateView(QuickNotifMixin, CreateView):
|
|||||||
|
|
||||||
class WeekmailArticleDeleteView(CanEditPropMixin, DeleteView):
|
class WeekmailArticleDeleteView(CanEditPropMixin, DeleteView):
|
||||||
"""Delete an article"""
|
"""Delete an article"""
|
||||||
|
|
||||||
model = WeekmailArticle
|
model = WeekmailArticle
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
success_url = reverse_lazy('com:weekmail')
|
success_url = reverse_lazy("com:weekmail")
|
||||||
pk_url_kwarg = "article_id"
|
pk_url_kwarg = "article_id"
|
||||||
|
|
||||||
|
|
||||||
@ -481,40 +600,43 @@ class MailingListAdminView(ComTabsMixin, ListView):
|
|||||||
current_tab = "mailings"
|
current_tab = "mailings"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not (request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or request.user.is_root):
|
if not (
|
||||||
|
request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
or request.user.is_root
|
||||||
|
):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
return super(MailingListAdminView, self).dispatch(request, *args, **kwargs)
|
return super(MailingListAdminView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(MailingListAdminView, self).get_context_data(**kwargs)
|
kwargs = super(MailingListAdminView, self).get_context_data(**kwargs)
|
||||||
kwargs['moderated'] = self.get_queryset().filter(is_moderated=True).all()
|
kwargs["moderated"] = self.get_queryset().filter(is_moderated=True).all()
|
||||||
kwargs['unmoderated'] = self.get_queryset().filter(is_moderated=False).all()
|
kwargs["unmoderated"] = self.get_queryset().filter(is_moderated=False).all()
|
||||||
kwargs['has_moderated'] = len(kwargs['moderated']) > 0
|
kwargs["has_moderated"] = len(kwargs["moderated"]) > 0
|
||||||
kwargs['has_unmoderated'] = len(kwargs['unmoderated']) > 0
|
kwargs["has_unmoderated"] = len(kwargs["unmoderated"]) > 0
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class MailingModerateView(View):
|
class MailingModerateView(View):
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
mailing = get_object_or_404(Mailing, pk=kwargs['mailing_id'])
|
mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"])
|
||||||
if mailing.can_moderate(request.user):
|
if mailing.can_moderate(request.user):
|
||||||
mailing.is_moderated = True
|
mailing.is_moderated = True
|
||||||
mailing.moderator = request.user
|
mailing.moderator = request.user
|
||||||
mailing.save()
|
mailing.save()
|
||||||
return redirect('com:mailing_admin')
|
return redirect("com:mailing_admin")
|
||||||
|
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
|
|
||||||
class PosterListBaseView(ListView):
|
class PosterListBaseView(ListView):
|
||||||
"""List communication posters"""
|
"""List communication posters"""
|
||||||
|
|
||||||
current_tab = "posters"
|
current_tab = "posters"
|
||||||
model = Poster
|
model = Poster
|
||||||
template_name = 'com/poster_list.jinja'
|
template_name = "com/poster_list.jinja"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
club_id = kwargs.pop('club_id', None)
|
club_id = kwargs.pop("club_id", None)
|
||||||
self.club = None
|
self.club = None
|
||||||
if club_id:
|
if club_id:
|
||||||
self.club = get_object_or_404(Club, pk=club_id)
|
self.club = get_object_or_404(Club, pk=club_id)
|
||||||
@ -522,40 +644,41 @@ class PosterListBaseView(ListView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.request.user.is_com_admin:
|
if self.request.user.is_com_admin:
|
||||||
return Poster.objects.all().order_by('-date_begin')
|
return Poster.objects.all().order_by("-date_begin")
|
||||||
else:
|
else:
|
||||||
return Poster.objects.filter(club=self.club.id)
|
return Poster.objects.filter(club=self.club.id)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterListBaseView, self).get_context_data(**kwargs)
|
kwargs = super(PosterListBaseView, self).get_context_data(**kwargs)
|
||||||
if not self.request.user.is_com_admin:
|
if not self.request.user.is_com_admin:
|
||||||
kwargs['club'] = self.club
|
kwargs["club"] = self.club
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class PosterCreateBaseView(CreateView):
|
class PosterCreateBaseView(CreateView):
|
||||||
"""Create communication poster"""
|
"""Create communication poster"""
|
||||||
|
|
||||||
current_tab = "posters"
|
current_tab = "posters"
|
||||||
form_class = PosterForm
|
form_class = PosterForm
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return Poster.objects.all()
|
return Poster.objects.all()
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if 'club_id' in kwargs:
|
if "club_id" in kwargs:
|
||||||
self.club = get_object_or_404(Club, pk=kwargs['club_id'])
|
self.club = get_object_or_404(Club, pk=kwargs["club_id"])
|
||||||
return super(PosterCreateBaseView, self).dispatch(request, *args, **kwargs)
|
return super(PosterCreateBaseView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super(PosterCreateBaseView, self).get_form_kwargs()
|
kwargs = super(PosterCreateBaseView, self).get_form_kwargs()
|
||||||
kwargs.update({'user': self.request.user})
|
kwargs.update({"user": self.request.user})
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterCreateBaseView, self).get_context_data(**kwargs)
|
kwargs = super(PosterCreateBaseView, self).get_context_data(**kwargs)
|
||||||
if not self.request.user.is_com_admin:
|
if not self.request.user.is_com_admin:
|
||||||
kwargs['club'] = self.club
|
kwargs["club"] = self.club
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
@ -566,27 +689,28 @@ class PosterCreateBaseView(CreateView):
|
|||||||
|
|
||||||
class PosterEditBaseView(UpdateView):
|
class PosterEditBaseView(UpdateView):
|
||||||
"""Edit communication poster"""
|
"""Edit communication poster"""
|
||||||
|
|
||||||
pk_url_kwarg = "poster_id"
|
pk_url_kwarg = "poster_id"
|
||||||
current_tab = "posters"
|
current_tab = "posters"
|
||||||
form_class = PosterForm
|
form_class = PosterForm
|
||||||
template_name = 'com/poster_edit.jinja'
|
template_name = "com/poster_edit.jinja"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
init = {}
|
init = {}
|
||||||
try:
|
try:
|
||||||
init['date_begin'] = self.object.date_begin.strftime('%Y-%m-%d %H:%M:%S')
|
init["date_begin"] = self.object.date_begin.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
init['date_end'] = self.object.date_end.strftime('%Y-%m-%d %H:%M:%S')
|
init["date_end"] = self.object.date_end.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return init
|
return init
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if 'club_id' in kwargs and kwargs['club_id']:
|
if "club_id" in kwargs and kwargs["club_id"]:
|
||||||
try:
|
try:
|
||||||
self.club = Club.objects.get(pk=kwargs['club_id'])
|
self.club = Club.objects.get(pk=kwargs["club_id"])
|
||||||
except Club.DoesNotExist:
|
except Club.DoesNotExist:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
return super(PosterEditBaseView, self).dispatch(request, *args, **kwargs)
|
return super(PosterEditBaseView, self).dispatch(request, *args, **kwargs)
|
||||||
@ -596,13 +720,13 @@ class PosterEditBaseView(UpdateView):
|
|||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super(PosterEditBaseView, self).get_form_kwargs()
|
kwargs = super(PosterEditBaseView, self).get_form_kwargs()
|
||||||
kwargs.update({'user': self.request.user})
|
kwargs.update({"user": self.request.user})
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterEditBaseView, self).get_context_data(**kwargs)
|
kwargs = super(PosterEditBaseView, self).get_context_data(**kwargs)
|
||||||
if not self.request.user.is_com_admin:
|
if not self.request.user.is_com_admin:
|
||||||
kwargs['club'] = self.club
|
kwargs["club"] = self.club
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
@ -613,15 +737,16 @@ class PosterEditBaseView(UpdateView):
|
|||||||
|
|
||||||
class PosterDeleteBaseView(DeleteView):
|
class PosterDeleteBaseView(DeleteView):
|
||||||
"""Edit communication poster"""
|
"""Edit communication poster"""
|
||||||
|
|
||||||
pk_url_kwarg = "poster_id"
|
pk_url_kwarg = "poster_id"
|
||||||
current_tab = "posters"
|
current_tab = "posters"
|
||||||
model = Poster
|
model = Poster
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if 'club_id' in kwargs and kwargs['club_id']:
|
if "club_id" in kwargs and kwargs["club_id"]:
|
||||||
try:
|
try:
|
||||||
self.club = Club.objects.get(pk=kwargs['club_id'])
|
self.club = Club.objects.get(pk=kwargs["club_id"])
|
||||||
except Club.DoesNotExist:
|
except Club.DoesNotExist:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
return super(PosterDeleteBaseView, self).dispatch(request, *args, **kwargs)
|
return super(PosterDeleteBaseView, self).dispatch(request, *args, **kwargs)
|
||||||
@ -632,107 +757,117 @@ class PosterListView(IsComAdminMixin, ComTabsMixin, PosterListBaseView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterListView, self).get_context_data(**kwargs)
|
kwargs = super(PosterListView, self).get_context_data(**kwargs)
|
||||||
kwargs['app'] = "com"
|
kwargs["app"] = "com"
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class PosterCreateView(IsComAdminMixin, ComTabsMixin, PosterCreateBaseView):
|
class PosterCreateView(IsComAdminMixin, ComTabsMixin, PosterCreateBaseView):
|
||||||
"""Create communication poster"""
|
"""Create communication poster"""
|
||||||
success_url = reverse_lazy('com:poster_list')
|
|
||||||
|
success_url = reverse_lazy("com:poster_list")
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterCreateView, self).get_context_data(**kwargs)
|
kwargs = super(PosterCreateView, self).get_context_data(**kwargs)
|
||||||
kwargs['app'] = "com"
|
kwargs["app"] = "com"
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class PosterEditView(IsComAdminMixin, ComTabsMixin, PosterEditBaseView):
|
class PosterEditView(IsComAdminMixin, ComTabsMixin, PosterEditBaseView):
|
||||||
"""Edit communication poster"""
|
"""Edit communication poster"""
|
||||||
success_url = reverse_lazy('com:poster_list')
|
|
||||||
|
success_url = reverse_lazy("com:poster_list")
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterEditView, self).get_context_data(**kwargs)
|
kwargs = super(PosterEditView, self).get_context_data(**kwargs)
|
||||||
kwargs['app'] = "com"
|
kwargs["app"] = "com"
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class PosterDeleteView(IsComAdminMixin, ComTabsMixin, PosterDeleteBaseView):
|
class PosterDeleteView(IsComAdminMixin, ComTabsMixin, PosterDeleteBaseView):
|
||||||
"""Delete communication poster"""
|
"""Delete communication poster"""
|
||||||
success_url = reverse_lazy('com:poster_list')
|
|
||||||
|
success_url = reverse_lazy("com:poster_list")
|
||||||
|
|
||||||
|
|
||||||
class PosterModerateListView(IsComAdminMixin, ComTabsMixin, ListView):
|
class PosterModerateListView(IsComAdminMixin, ComTabsMixin, ListView):
|
||||||
"""Moderate list communication poster"""
|
"""Moderate list communication poster"""
|
||||||
|
|
||||||
current_tab = "posters"
|
current_tab = "posters"
|
||||||
model = Poster
|
model = Poster
|
||||||
template_name = 'com/poster_moderate.jinja'
|
template_name = "com/poster_moderate.jinja"
|
||||||
queryset = Poster.objects.filter(is_moderated=False).all()
|
queryset = Poster.objects.filter(is_moderated=False).all()
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterModerateListView, self).get_context_data(**kwargs)
|
kwargs = super(PosterModerateListView, self).get_context_data(**kwargs)
|
||||||
kwargs['app'] = "com"
|
kwargs["app"] = "com"
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class PosterModerateView(IsComAdminMixin, ComTabsMixin, View):
|
class PosterModerateView(IsComAdminMixin, ComTabsMixin, View):
|
||||||
"""Moderate communication poster"""
|
"""Moderate communication poster"""
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
obj = get_object_or_404(Poster, pk=kwargs['object_id'])
|
obj = get_object_or_404(Poster, pk=kwargs["object_id"])
|
||||||
if obj.can_be_moderated_by(request.user):
|
if obj.can_be_moderated_by(request.user):
|
||||||
obj.is_moderated = True
|
obj.is_moderated = True
|
||||||
obj.moderator = request.user
|
obj.moderator = request.user
|
||||||
obj.save()
|
obj.save()
|
||||||
return redirect('com:poster_moderate_list')
|
return redirect("com:poster_moderate_list")
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(PosterModerateListView, self).get_context_data(**kwargs)
|
kwargs = super(PosterModerateListView, self).get_context_data(**kwargs)
|
||||||
kwargs['app'] = "com"
|
kwargs["app"] = "com"
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class ScreenListView(IsComAdminMixin, ComTabsMixin, ListView):
|
class ScreenListView(IsComAdminMixin, ComTabsMixin, ListView):
|
||||||
"""List communication screens"""
|
"""List communication screens"""
|
||||||
|
|
||||||
current_tab = "screens"
|
current_tab = "screens"
|
||||||
model = Screen
|
model = Screen
|
||||||
template_name = 'com/screen_list.jinja'
|
template_name = "com/screen_list.jinja"
|
||||||
|
|
||||||
|
|
||||||
class ScreenSlideshowView(DetailView):
|
class ScreenSlideshowView(DetailView):
|
||||||
"""Slideshow of actives posters"""
|
"""Slideshow of actives posters"""
|
||||||
|
|
||||||
pk_url_kwarg = "screen_id"
|
pk_url_kwarg = "screen_id"
|
||||||
model = Screen
|
model = Screen
|
||||||
template_name = 'com/screen_slideshow.jinja'
|
template_name = "com/screen_slideshow.jinja"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super(ScreenSlideshowView, self).get_context_data(**kwargs)
|
kwargs = super(ScreenSlideshowView, self).get_context_data(**kwargs)
|
||||||
kwargs['posters'] = self.object.active_posters()
|
kwargs["posters"] = self.object.active_posters()
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class ScreenCreateView(IsComAdminMixin, ComTabsMixin, CreateView):
|
class ScreenCreateView(IsComAdminMixin, ComTabsMixin, CreateView):
|
||||||
"""Create communication screen"""
|
"""Create communication screen"""
|
||||||
|
|
||||||
current_tab = "screens"
|
current_tab = "screens"
|
||||||
model = Screen
|
model = Screen
|
||||||
fields = ['name', ]
|
fields = ["name"]
|
||||||
template_name = 'core/create.jinja'
|
template_name = "core/create.jinja"
|
||||||
success_url = reverse_lazy('com:screen_list')
|
success_url = reverse_lazy("com:screen_list")
|
||||||
|
|
||||||
|
|
||||||
class ScreenEditView(IsComAdminMixin, ComTabsMixin, UpdateView):
|
class ScreenEditView(IsComAdminMixin, ComTabsMixin, UpdateView):
|
||||||
"""Edit communication screen"""
|
"""Edit communication screen"""
|
||||||
|
|
||||||
pk_url_kwarg = "screen_id"
|
pk_url_kwarg = "screen_id"
|
||||||
current_tab = "screens"
|
current_tab = "screens"
|
||||||
model = Screen
|
model = Screen
|
||||||
fields = ['name', ]
|
fields = ["name"]
|
||||||
template_name = 'com/screen_edit.jinja'
|
template_name = "com/screen_edit.jinja"
|
||||||
success_url = reverse_lazy('com:screen_list')
|
success_url = reverse_lazy("com:screen_list")
|
||||||
|
|
||||||
|
|
||||||
class ScreenDeleteView(IsComAdminMixin, ComTabsMixin, DeleteView):
|
class ScreenDeleteView(IsComAdminMixin, ComTabsMixin, DeleteView):
|
||||||
"""Delete communication screen"""
|
"""Delete communication screen"""
|
||||||
|
|
||||||
pk_url_kwarg = "screen_id"
|
pk_url_kwarg = "screen_id"
|
||||||
current_tab = "screens"
|
current_tab = "screens"
|
||||||
model = Screen
|
model = Screen
|
||||||
template_name = 'core/delete_confirm.jinja'
|
template_name = "core/delete_confirm.jinja"
|
||||||
success_url = reverse_lazy('com:screen_list')
|
success_url = reverse_lazy("com:screen_list")
|
||||||
|
@ -22,4 +22,4 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
default_app_config = 'core.apps.SithConfig'
|
default_app_config = "core.apps.SithConfig"
|
||||||
|
@ -32,30 +32,38 @@ from haystack.admin import SearchModelAdmin
|
|||||||
admin.site.unregister(AuthGroup)
|
admin.site.unregister(AuthGroup)
|
||||||
admin.site.register(RealGroup)
|
admin.site.register(RealGroup)
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(SearchModelAdmin):
|
class UserAdmin(SearchModelAdmin):
|
||||||
list_display = ["first_name", "last_name", "username", "email", "nick_name"]
|
list_display = ["first_name", "last_name", "username", "email", "nick_name"]
|
||||||
form = make_ajax_form(User, {
|
form = make_ajax_form(
|
||||||
'godfathers': 'users',
|
User,
|
||||||
'home': 'files', # ManyToManyField
|
{
|
||||||
'profile_pict': 'files', # ManyToManyField
|
"godfathers": "users",
|
||||||
'avatar_pict': 'files', # ManyToManyField
|
"home": "files", # ManyToManyField
|
||||||
'scrub_pict': 'files', # ManyToManyField
|
"profile_pict": "files", # ManyToManyField
|
||||||
})
|
"avatar_pict": "files", # ManyToManyField
|
||||||
|
"scrub_pict": "files", # ManyToManyField
|
||||||
|
},
|
||||||
|
)
|
||||||
search_fields = ["first_name", "last_name", "username"]
|
search_fields = ["first_name", "last_name", "username"]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Page)
|
@admin.register(Page)
|
||||||
class PageAdmin(admin.ModelAdmin):
|
class PageAdmin(admin.ModelAdmin):
|
||||||
form = make_ajax_form(Page, {
|
form = make_ajax_form(
|
||||||
'lock_user': 'users',
|
Page,
|
||||||
'owner_group': 'groups',
|
{
|
||||||
'edit_groups': 'groups',
|
"lock_user": "users",
|
||||||
'view_groups': 'groups',
|
"owner_group": "groups",
|
||||||
})
|
"edit_groups": "groups",
|
||||||
|
"view_groups": "groups",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(SithFile)
|
@admin.register(SithFile)
|
||||||
class SithFileAdmin(admin.ModelAdmin):
|
class SithFileAdmin(admin.ModelAdmin):
|
||||||
form = make_ajax_form(SithFile, {
|
form = make_ajax_form(SithFile, {"parent": "files"}) # ManyToManyField
|
||||||
'parent': 'files', # ManyToManyField
|
|
||||||
})
|
|
||||||
|
12
core/apps.py
12
core/apps.py
@ -29,7 +29,7 @@ from django.core.signals import request_started
|
|||||||
|
|
||||||
|
|
||||||
class SithConfig(AppConfig):
|
class SithConfig(AppConfig):
|
||||||
name = 'core'
|
name = "core"
|
||||||
verbose_name = "Core app of the Sith"
|
verbose_name = "Core app of the Sith"
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
@ -47,6 +47,12 @@ class SithConfig(AppConfig):
|
|||||||
Forum._club_memberships = {}
|
Forum._club_memberships = {}
|
||||||
|
|
||||||
print("Connecting signals!", file=sys.stderr)
|
print("Connecting signals!", file=sys.stderr)
|
||||||
request_started.connect(clear_cached_groups, weak=False, dispatch_uid="clear_cached_groups")
|
request_started.connect(
|
||||||
request_started.connect(clear_cached_memberships, weak=False, dispatch_uid="clear_cached_memberships")
|
clear_cached_groups, weak=False, dispatch_uid="clear_cached_groups"
|
||||||
|
)
|
||||||
|
request_started.connect(
|
||||||
|
clear_cached_memberships,
|
||||||
|
weak=False,
|
||||||
|
dispatch_uid="clear_cached_memberships",
|
||||||
|
)
|
||||||
# TODO: there may be a need to add more cache clearing
|
# TODO: there may be a need to add more cache clearing
|
||||||
|
@ -33,9 +33,11 @@ from accounting.models import ClubAccount, Company
|
|||||||
|
|
||||||
|
|
||||||
def check_token(request):
|
def check_token(request):
|
||||||
return ('counter_token' in request.session.keys() and
|
return (
|
||||||
request.session['counter_token'] and
|
"counter_token" in request.session.keys()
|
||||||
Counter.objects.filter(token=request.session['counter_token']).exists())
|
and request.session["counter_token"]
|
||||||
|
and Counter.objects.filter(token=request.session["counter_token"]).exists()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RightManagedLookupChannel(LookupChannel):
|
class RightManagedLookupChannel(LookupChannel):
|
||||||
@ -44,7 +46,7 @@ class RightManagedLookupChannel(LookupChannel):
|
|||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
|
|
||||||
@register('users')
|
@register("users")
|
||||||
class UsersLookup(RightManagedLookupChannel):
|
class UsersLookup(RightManagedLookupChannel):
|
||||||
model = User
|
model = User
|
||||||
|
|
||||||
@ -58,7 +60,7 @@ class UsersLookup(RightManagedLookupChannel):
|
|||||||
return item.get_display_name()
|
return item.get_display_name()
|
||||||
|
|
||||||
|
|
||||||
@register('groups')
|
@register("groups")
|
||||||
class GroupsLookup(RightManagedLookupChannel):
|
class GroupsLookup(RightManagedLookupChannel):
|
||||||
model = Group
|
model = Group
|
||||||
|
|
||||||
@ -72,7 +74,7 @@ class GroupsLookup(RightManagedLookupChannel):
|
|||||||
return item.name
|
return item.name
|
||||||
|
|
||||||
|
|
||||||
@register('clubs')
|
@register("clubs")
|
||||||
class ClubLookup(RightManagedLookupChannel):
|
class ClubLookup(RightManagedLookupChannel):
|
||||||
model = Club
|
model = Club
|
||||||
|
|
||||||
@ -86,7 +88,7 @@ class ClubLookup(RightManagedLookupChannel):
|
|||||||
return item.name
|
return item.name
|
||||||
|
|
||||||
|
|
||||||
@register('counters')
|
@register("counters")
|
||||||
class CountersLookup(RightManagedLookupChannel):
|
class CountersLookup(RightManagedLookupChannel):
|
||||||
model = Counter
|
model = Counter
|
||||||
|
|
||||||
@ -97,19 +99,21 @@ class CountersLookup(RightManagedLookupChannel):
|
|||||||
return item.name
|
return item.name
|
||||||
|
|
||||||
|
|
||||||
@register('products')
|
@register("products")
|
||||||
class ProductsLookup(RightManagedLookupChannel):
|
class ProductsLookup(RightManagedLookupChannel):
|
||||||
model = Product
|
model = Product
|
||||||
|
|
||||||
def get_query(self, q, request):
|
def get_query(self, q, request):
|
||||||
return (self.model.objects.filter(name__icontains=q) |
|
return (
|
||||||
self.model.objects.filter(code__icontains=q)).filter(archived=False)[:50]
|
self.model.objects.filter(name__icontains=q)
|
||||||
|
| self.model.objects.filter(code__icontains=q)
|
||||||
|
).filter(archived=False)[:50]
|
||||||
|
|
||||||
def format_item_display(self, item):
|
def format_item_display(self, item):
|
||||||
return "%s (%s)" % (item.name, item.code)
|
return "%s (%s)" % (item.name, item.code)
|
||||||
|
|
||||||
|
|
||||||
@register('files')
|
@register("files")
|
||||||
class SithFileLookup(RightManagedLookupChannel):
|
class SithFileLookup(RightManagedLookupChannel):
|
||||||
model = SithFile
|
model = SithFile
|
||||||
|
|
||||||
@ -117,7 +121,7 @@ class SithFileLookup(RightManagedLookupChannel):
|
|||||||
return self.model.objects.filter(name__icontains=q)[:50]
|
return self.model.objects.filter(name__icontains=q)[:50]
|
||||||
|
|
||||||
|
|
||||||
@register('club_accounts')
|
@register("club_accounts")
|
||||||
class ClubAccountLookup(RightManagedLookupChannel):
|
class ClubAccountLookup(RightManagedLookupChannel):
|
||||||
model = ClubAccount
|
model = ClubAccount
|
||||||
|
|
||||||
@ -128,7 +132,7 @@ class ClubAccountLookup(RightManagedLookupChannel):
|
|||||||
return item.name
|
return item.name
|
||||||
|
|
||||||
|
|
||||||
@register('companies')
|
@register("companies")
|
||||||
class CompaniesLookup(RightManagedLookupChannel):
|
class CompaniesLookup(RightManagedLookupChannel):
|
||||||
model = Company
|
model = Company
|
||||||
|
|
||||||
|
@ -21,4 +21,3 @@
|
|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -33,10 +33,14 @@ class Command(BaseCommand):
|
|||||||
help = "Recursively check the file system with respect to the DB"
|
help = "Recursively check the file system with respect to the DB"
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('ids', metavar='ID', type=int, nargs='+', help="The file IDs to process")
|
parser.add_argument(
|
||||||
|
"ids", metavar="ID", type=int, nargs="+", help="The file IDs to process"
|
||||||
|
)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
root_path = os.path.dirname(
|
||||||
files = SithFile.objects.filter(id__in=options['ids']).all()
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
)
|
||||||
|
files = SithFile.objects.filter(id__in=options["ids"]).all()
|
||||||
for f in files:
|
for f in files:
|
||||||
f._check_fs()
|
f._check_fs()
|
||||||
|
@ -33,15 +33,13 @@ class Command(BaseCommand):
|
|||||||
"""
|
"""
|
||||||
Compiles scss in static folder for production
|
Compiles scss in static folder for production
|
||||||
"""
|
"""
|
||||||
|
|
||||||
help = "Compile scss files from static folder"
|
help = "Compile scss files from static folder"
|
||||||
|
|
||||||
def compile(self, filename):
|
def compile(self, filename):
|
||||||
args = {
|
args = {"filename": filename, "include_paths": settings.STATIC_ROOT}
|
||||||
"filename": filename,
|
|
||||||
"include_paths": settings.STATIC_ROOT,
|
|
||||||
}
|
|
||||||
if settings.SASS_PRECISION:
|
if settings.SASS_PRECISION:
|
||||||
args['precision'] = settings.SASS_PRECISION
|
args["precision"] = settings.SASS_PRECISION
|
||||||
return sass.compile(**args)
|
return sass.compile(**args)
|
||||||
|
|
||||||
def is_compilable(self, file, ext_list):
|
def is_compilable(self, file, ext_list):
|
||||||
@ -54,7 +52,7 @@ class Command(BaseCommand):
|
|||||||
file = os.path.join(folder, file)
|
file = os.path.join(folder, file)
|
||||||
if os.path.isdir(file):
|
if os.path.isdir(file):
|
||||||
self.exec_on_folder(file, func)
|
self.exec_on_folder(file, func)
|
||||||
elif self.is_compilable(file, ['.scss']):
|
elif self.is_compilable(file, [".scss"]):
|
||||||
to_exec.append(file)
|
to_exec.append(file)
|
||||||
|
|
||||||
for file in to_exec:
|
for file in to_exec:
|
||||||
@ -62,7 +60,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
def compilescss(self, file):
|
def compilescss(self, file):
|
||||||
print("compiling %s" % file)
|
print("compiling %s" % file)
|
||||||
with(open(file.replace('.scss', '.css'), "w")) as newfile:
|
with (open(file.replace(".scss", ".css"), "w")) as newfile:
|
||||||
newfile.write(self.compile(file))
|
newfile.write(self.compile(file))
|
||||||
|
|
||||||
def removescss(self, file):
|
def removescss(self, file):
|
||||||
@ -77,4 +75,6 @@ class Command(BaseCommand):
|
|||||||
print("---- Removing scss files ----")
|
print("---- Removing scss files ----")
|
||||||
self.exec_on_folder(settings.STATIC_ROOT, self.removescss)
|
self.exec_on_folder(settings.STATIC_ROOT, self.removescss)
|
||||||
else:
|
else:
|
||||||
print("No static folder avalaible, please use collectstatic before compiling scss")
|
print(
|
||||||
|
"No static folder avalaible, please use collectstatic before compiling scss"
|
||||||
|
)
|
||||||
|
@ -27,11 +27,14 @@ from django.core.management.base import BaseCommand
|
|||||||
|
|
||||||
from core.markdown import markdown
|
from core.markdown import markdown
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Output the fully rendered doc/SYNTAX.md file"
|
help = "Output the fully rendered doc/SYNTAX.md file"
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
root_path = os.path.dirname(
|
||||||
with open(os.path.join(root_path) + '/doc/SYNTAX.md', 'r') as md:
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
)
|
||||||
|
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md:
|
||||||
result = markdown(md.read())
|
result = markdown(md.read())
|
||||||
print(result, end='')
|
print(result, end="")
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -33,10 +33,14 @@ class Command(BaseCommand):
|
|||||||
help = "Recursively repair the file system with respect to the DB"
|
help = "Recursively repair the file system with respect to the DB"
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('ids', metavar='ID', type=int, nargs='+', help="The file IDs to process")
|
parser.add_argument(
|
||||||
|
"ids", metavar="ID", type=int, nargs="+", help="The file IDs to process"
|
||||||
|
)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
root_path = os.path.dirname(
|
||||||
files = SithFile.objects.filter(id__in=options['ids']).all()
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
)
|
||||||
|
files = SithFile.objects.filter(id__in=options["ids"]).all()
|
||||||
for f in files:
|
for f in files:
|
||||||
f._repair_fs()
|
f._repair_fs()
|
||||||
|
@ -31,22 +31,24 @@ class Command(BaseCommand):
|
|||||||
help = "Set up a new instance of the Sith AE"
|
help = "Set up a new instance of the Sith AE"
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('--prod', action="store_true")
|
parser.add_argument("--prod", action="store_true")
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
root_path = os.path.dirname(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
os.mkdir(os.path.join(root_path) + '/data')
|
os.mkdir(os.path.join(root_path) + "/data")
|
||||||
print("Data dir created")
|
print("Data dir created")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
repr(e)
|
repr(e)
|
||||||
try:
|
try:
|
||||||
os.remove(os.path.join(root_path, 'db.sqlite3'))
|
os.remove(os.path.join(root_path, "db.sqlite3"))
|
||||||
print("db.sqlite3 deleted")
|
print("db.sqlite3 deleted")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
repr(e)
|
repr(e)
|
||||||
call_command('migrate')
|
call_command("migrate")
|
||||||
if options['prod']:
|
if options["prod"]:
|
||||||
call_command('populate', '--prod')
|
call_command("populate", "--prod")
|
||||||
else:
|
else:
|
||||||
call_command('populate')
|
call_command("populate")
|
||||||
|
116
core/markdown.py
116
core/markdown.py
@ -30,7 +30,7 @@ from django.core.urlresolvers import reverse
|
|||||||
|
|
||||||
class SithRenderer(Renderer):
|
class SithRenderer(Renderer):
|
||||||
def file_link(self, id, suffix):
|
def file_link(self, id, suffix):
|
||||||
return reverse('core:file_detail', kwargs={'file_id': id}) + suffix
|
return reverse("core:file_detail", kwargs={"file_id": id}) + suffix
|
||||||
|
|
||||||
def exposant(self, text):
|
def exposant(self, text):
|
||||||
return """<sup>%s</sup>""" % text
|
return """<sup>%s</sup>""" % text
|
||||||
@ -48,19 +48,19 @@ class SithRenderer(Renderer):
|
|||||||
:param text: alt text of the image.
|
:param text: alt text of the image.
|
||||||
"""
|
"""
|
||||||
style = None
|
style = None
|
||||||
if '?' in original_src:
|
if "?" in original_src:
|
||||||
src, params = original_src.rsplit('?', maxsplit=1)
|
src, params = original_src.rsplit("?", maxsplit=1)
|
||||||
m = re.search(r'(\d+%?)(x(\d+%?))?', params)
|
m = re.search(r"(\d+%?)(x(\d+%?))?", params)
|
||||||
if not m:
|
if not m:
|
||||||
src = original_src
|
src = original_src
|
||||||
else:
|
else:
|
||||||
width = m.group(1)
|
width = m.group(1)
|
||||||
if not width.endswith('%'):
|
if not width.endswith("%"):
|
||||||
width += "px"
|
width += "px"
|
||||||
style = "width: %s; " % width
|
style = "width: %s; " % width
|
||||||
try:
|
try:
|
||||||
height = m.group(3)
|
height = m.group(3)
|
||||||
if not height.endswith('%'):
|
if not height.endswith("%"):
|
||||||
height += "px"
|
height += "px"
|
||||||
style += "height: %s; " % height
|
style += "height: %s; " % height
|
||||||
except:
|
except:
|
||||||
@ -77,67 +77,57 @@ class SithRenderer(Renderer):
|
|||||||
html = '<img src="%s" alt="%s"' % (src, text)
|
html = '<img src="%s" alt="%s"' % (src, text)
|
||||||
if style:
|
if style:
|
||||||
html = '%s style="%s"' % (html, style)
|
html = '%s style="%s"' % (html, style)
|
||||||
if self.options.get('use_xhtml'):
|
if self.options.get("use_xhtml"):
|
||||||
return '%s />' % html
|
return "%s />" % html
|
||||||
return '%s>' % html
|
return "%s>" % html
|
||||||
|
|
||||||
|
|
||||||
class SithInlineGrammar(InlineGrammar):
|
class SithInlineGrammar(InlineGrammar):
|
||||||
double_emphasis = re.compile(
|
double_emphasis = re.compile(r"^\*{2}([\s\S]+?)\*{2}(?!\*)") # **word**
|
||||||
r'^\*{2}([\s\S]+?)\*{2}(?!\*)' # **word**
|
emphasis = re.compile(r"^\*((?:\*\*|[^\*])+?)\*(?!\*)") # *word*
|
||||||
)
|
underline = re.compile(r"^_{2}([\s\S]+?)_{2}(?!_)") # __word__
|
||||||
emphasis = re.compile(
|
exposant = re.compile(r"^<sup>([\s\S]+?)</sup>") # <sup>text</sup>
|
||||||
r'^\*((?:\*\*|[^\*])+?)\*(?!\*)' # *word*
|
indice = re.compile(r"^<sub>([\s\S]+?)</sub>") # <sub>text</sub>
|
||||||
)
|
|
||||||
underline = re.compile(
|
|
||||||
r'^_{2}([\s\S]+?)_{2}(?!_)' # __word__
|
|
||||||
)
|
|
||||||
exposant = re.compile(
|
|
||||||
r'^<sup>([\s\S]+?)</sup>' # <sup>text</sup>
|
|
||||||
)
|
|
||||||
indice = re.compile(
|
|
||||||
r'^<sub>([\s\S]+?)</sub>' # <sub>text</sub>
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SithInlineLexer(InlineLexer):
|
class SithInlineLexer(InlineLexer):
|
||||||
grammar_class = SithInlineGrammar
|
grammar_class = SithInlineGrammar
|
||||||
|
|
||||||
default_rules = [
|
default_rules = [
|
||||||
'escape',
|
"escape",
|
||||||
# 'inline_html',
|
# 'inline_html',
|
||||||
'autolink',
|
"autolink",
|
||||||
'url',
|
"url",
|
||||||
'footnote',
|
"footnote",
|
||||||
'link',
|
"link",
|
||||||
'reflink',
|
"reflink",
|
||||||
'nolink',
|
"nolink",
|
||||||
'exposant',
|
"exposant",
|
||||||
'double_emphasis',
|
"double_emphasis",
|
||||||
'emphasis',
|
"emphasis",
|
||||||
'underline',
|
"underline",
|
||||||
'indice',
|
"indice",
|
||||||
'code',
|
"code",
|
||||||
'linebreak',
|
"linebreak",
|
||||||
'strikethrough',
|
"strikethrough",
|
||||||
'text',
|
"text",
|
||||||
]
|
]
|
||||||
inline_html_rules = [
|
inline_html_rules = [
|
||||||
'escape',
|
"escape",
|
||||||
'autolink',
|
"autolink",
|
||||||
'url',
|
"url",
|
||||||
'link',
|
"link",
|
||||||
'reflink',
|
"reflink",
|
||||||
'nolink',
|
"nolink",
|
||||||
'exposant',
|
"exposant",
|
||||||
'double_emphasis',
|
"double_emphasis",
|
||||||
'emphasis',
|
"emphasis",
|
||||||
'underline',
|
"underline",
|
||||||
'indice',
|
"indice",
|
||||||
'code',
|
"code",
|
||||||
'linebreak',
|
"linebreak",
|
||||||
'strikethrough',
|
"strikethrough",
|
||||||
'text',
|
"text",
|
||||||
]
|
]
|
||||||
|
|
||||||
def output_underline(self, m):
|
def output_underline(self, m):
|
||||||
@ -166,22 +156,18 @@ class SithInlineLexer(InlineLexer):
|
|||||||
|
|
||||||
def _process_link(self, m, link, title=None):
|
def _process_link(self, m, link, title=None):
|
||||||
try: # Add page:// support for links
|
try: # Add page:// support for links
|
||||||
page = re.compile(
|
page = re.compile(r"^page://(\S*)") # page://nom_de_ma_page
|
||||||
r'^page://(\S*)' # page://nom_de_ma_page
|
|
||||||
)
|
|
||||||
match = page.search(link)
|
match = page.search(link)
|
||||||
page = match.group(1) or ""
|
page = match.group(1) or ""
|
||||||
link = reverse('core:page', kwargs={'page_name': page})
|
link = reverse("core:page", kwargs={"page_name": page})
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try: # Add file:// support for links
|
try: # Add file:// support for links
|
||||||
file_link = re.compile(
|
file_link = re.compile(r"^file://(\d*)/?(\S*)?") # file://4000/download
|
||||||
r'^file://(\d*)/?(\S*)?' # file://4000/download
|
|
||||||
)
|
|
||||||
match = file_link.search(link)
|
match = file_link.search(link)
|
||||||
id = match.group(1)
|
id = match.group(1)
|
||||||
suffix = match.group(2) or ""
|
suffix = match.group(2) or ""
|
||||||
link = reverse('core:file_detail', kwargs={'file_id': id}) + suffix
|
link = reverse("core:file_detail", kwargs={"file_id": id}) + suffix
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return super(SithInlineLexer, self)._process_link(m, link, title)
|
return super(SithInlineLexer, self)._process_link(m, link, title)
|
||||||
@ -194,6 +180,6 @@ markdown = Markdown(renderer, inline=inline)
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
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:
|
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md:
|
||||||
result = markdown(md.read())
|
result = markdown(md.read())
|
||||||
print(result, end='')
|
print(result, end="")
|
||||||
|
@ -26,14 +26,16 @@ import importlib
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.functional import SimpleLazyObject
|
from django.utils.functional import SimpleLazyObject
|
||||||
from django.contrib.auth import get_user
|
from django.contrib.auth import get_user
|
||||||
from django.contrib.auth.middleware import AuthenticationMiddleware as DjangoAuthenticationMiddleware
|
from django.contrib.auth.middleware import (
|
||||||
|
AuthenticationMiddleware as DjangoAuthenticationMiddleware,
|
||||||
|
)
|
||||||
|
|
||||||
module, klass = settings.AUTH_ANONYMOUS_MODEL.rsplit('.', 1)
|
module, klass = settings.AUTH_ANONYMOUS_MODEL.rsplit(".", 1)
|
||||||
AnonymousUser = getattr(importlib.import_module(module), klass)
|
AnonymousUser = getattr(importlib.import_module(module), klass)
|
||||||
|
|
||||||
|
|
||||||
def get_cached_user(request):
|
def get_cached_user(request):
|
||||||
if not hasattr(request, '_cached_user'):
|
if not hasattr(request, "_cached_user"):
|
||||||
user = get_user(request)
|
user = get_user(request)
|
||||||
if user.is_anonymous():
|
if user.is_anonymous():
|
||||||
user = AnonymousUser(request)
|
user = AnonymousUser(request)
|
||||||
@ -45,7 +47,7 @@ def get_cached_user(request):
|
|||||||
|
|
||||||
class AuthenticationMiddleware(DjangoAuthenticationMiddleware):
|
class AuthenticationMiddleware(DjangoAuthenticationMiddleware):
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
assert hasattr(request, 'session'), (
|
assert hasattr(request, "session"), (
|
||||||
"The Django authentication middleware requires session middleware "
|
"The Django authentication middleware requires session middleware "
|
||||||
"to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
|
"to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
|
||||||
"'django.contrib.sessions.middleware.SessionMiddleware' before "
|
"'django.contrib.sessions.middleware.SessionMiddleware' before "
|
||||||
|
@ -12,169 +12,559 @@ from django.conf import settings
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("auth", "0006_require_contenttypes_0002")]
|
||||||
('auth', '0006_require_contenttypes_0002'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='User',
|
name="User",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
"id",
|
||||||
('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)),
|
models.AutoField(
|
||||||
('username', models.CharField(help_text='Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, max_length=254, error_messages={'unique': 'A user with that username already exists.'}, verbose_name='username', validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')])),
|
primary_key=True,
|
||||||
('first_name', models.CharField(max_length=64, verbose_name='first name')),
|
serialize=False,
|
||||||
('last_name', models.CharField(max_length=64, verbose_name='last name')),
|
verbose_name="ID",
|
||||||
('email', models.EmailField(unique=True, max_length=254, verbose_name='email address')),
|
auto_created=True,
|
||||||
('date_of_birth', models.DateField(null=True, verbose_name='date of birth', blank=True)),
|
),
|
||||||
('nick_name', models.CharField(max_length=64, null=True, verbose_name='nick name', blank=True)),
|
),
|
||||||
('is_staff', models.BooleanField(help_text='Designates whether the user can log into this admin site.', verbose_name='staff status', default=False)),
|
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||||
('is_active', models.BooleanField(help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active', default=True)),
|
(
|
||||||
('date_joined', models.DateField(auto_now_add=True, verbose_name='date joined')),
|
"last_login",
|
||||||
('last_update', models.DateField(verbose_name='last update', auto_now=True)),
|
models.DateTimeField(
|
||||||
('is_superuser', models.BooleanField(help_text='Designates whether this user is a superuser. ', verbose_name='superuser', default=False)),
|
null=True, verbose_name="last login", blank=True
|
||||||
('sex', models.CharField(choices=[('MAN', 'Man'), ('WOMAN', 'Woman')], max_length=10, default='MAN', verbose_name='sex')),
|
),
|
||||||
('tshirt_size', models.CharField(choices=[('-', '-'), ('XS', 'XS'), ('S', 'S'), ('M', 'M'), ('L', 'L'), ('XL', 'XL'), ('XXL', 'XXL'), ('XXXL', 'XXXL')], max_length=5, default='-', verbose_name='tshirt size')),
|
),
|
||||||
('role', models.CharField(choices=[('STUDENT', 'Student'), ('ADMINISTRATIVE', 'Administrative agent'), ('TEACHER', 'Teacher'), ('AGENT', 'Agent'), ('DOCTOR', 'Doctor'), ('FORMER STUDENT', 'Former student'), ('SERVICE', 'Service')], max_length=15, blank=True, verbose_name='role', default='')),
|
(
|
||||||
('department', models.CharField(choices=[('TC', 'TC'), ('IMSI', 'IMSI'), ('IMAP', 'IMAP'), ('INFO', 'INFO'), ('GI', 'GI'), ('E', 'E'), ('EE', 'EE'), ('GESC', 'GESC'), ('GMC', 'GMC'), ('MC', 'MC'), ('EDIM', 'EDIM'), ('HUMA', 'Humanities'), ('NA', 'N/A')], max_length=15, blank=True, verbose_name='department', default='NA')),
|
"username",
|
||||||
('dpt_option', models.CharField(max_length=32, blank=True, verbose_name='dpt option', default='')),
|
models.CharField(
|
||||||
('semester', models.CharField(max_length=5, blank=True, verbose_name='semester', default='')),
|
help_text="Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
||||||
('quote', models.CharField(max_length=256, blank=True, verbose_name='quote', default='')),
|
unique=True,
|
||||||
('school', models.CharField(max_length=80, blank=True, verbose_name='school', default='')),
|
max_length=254,
|
||||||
('promo', models.IntegerField(null=True, verbose_name='promo', validators=[core.models.validate_promo], blank=True)),
|
error_messages={
|
||||||
('forum_signature', models.TextField(max_length=256, blank=True, verbose_name='forum signature', default='')),
|
"unique": "A user with that username already exists."
|
||||||
('second_email', models.EmailField(max_length=254, null=True, verbose_name='second email address', blank=True)),
|
|
||||||
('phone', phonenumber_field.modelfields.PhoneNumberField(max_length=128, null=True, verbose_name='phone', blank=True)),
|
|
||||||
('parent_phone', phonenumber_field.modelfields.PhoneNumberField(max_length=128, null=True, verbose_name='parent phone', blank=True)),
|
|
||||||
('address', models.CharField(max_length=128, blank=True, verbose_name='address', default='')),
|
|
||||||
('parent_address', models.CharField(max_length=128, blank=True, verbose_name='parent address', default='')),
|
|
||||||
('is_subscriber_viewable', models.BooleanField(verbose_name='is subscriber viewable', default=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'abstract': False,
|
|
||||||
},
|
},
|
||||||
managers=[
|
verbose_name="username",
|
||||||
('objects', django.contrib.auth.models.UserManager()),
|
validators=[
|
||||||
|
django.core.validators.RegexValidator(
|
||||||
|
"^[\\w.@+-]+$",
|
||||||
|
"Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.",
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
),
|
||||||
name='Group',
|
(
|
||||||
fields=[
|
"first_name",
|
||||||
('group_ptr', models.OneToOneField(primary_key=True, parent_link=True, serialize=False, to='auth.Group', auto_created=True)),
|
models.CharField(max_length=64, verbose_name="first name"),
|
||||||
('is_meta', models.BooleanField(help_text='Whether a group is a meta group or not', verbose_name='meta group status', default=False)),
|
),
|
||||||
('description', models.CharField(max_length=60, verbose_name='description')),
|
(
|
||||||
|
"last_name",
|
||||||
|
models.CharField(max_length=64, verbose_name="last name"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"email",
|
||||||
|
models.EmailField(
|
||||||
|
unique=True, max_length=254, verbose_name="email address"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"date_of_birth",
|
||||||
|
models.DateField(
|
||||||
|
null=True, verbose_name="date of birth", blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"nick_name",
|
||||||
|
models.CharField(
|
||||||
|
max_length=64, null=True, verbose_name="nick name", blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_staff",
|
||||||
|
models.BooleanField(
|
||||||
|
help_text="Designates whether the user can log into this admin site.",
|
||||||
|
verbose_name="staff status",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_active",
|
||||||
|
models.BooleanField(
|
||||||
|
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||||
|
verbose_name="active",
|
||||||
|
default=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"date_joined",
|
||||||
|
models.DateField(auto_now_add=True, verbose_name="date joined"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"last_update",
|
||||||
|
models.DateField(verbose_name="last update", auto_now=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_superuser",
|
||||||
|
models.BooleanField(
|
||||||
|
help_text="Designates whether this user is a superuser. ",
|
||||||
|
verbose_name="superuser",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"sex",
|
||||||
|
models.CharField(
|
||||||
|
choices=[("MAN", "Man"), ("WOMAN", "Woman")],
|
||||||
|
max_length=10,
|
||||||
|
default="MAN",
|
||||||
|
verbose_name="sex",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"tshirt_size",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("-", "-"),
|
||||||
|
("XS", "XS"),
|
||||||
|
("S", "S"),
|
||||||
|
("M", "M"),
|
||||||
|
("L", "L"),
|
||||||
|
("XL", "XL"),
|
||||||
|
("XXL", "XXL"),
|
||||||
|
("XXXL", "XXXL"),
|
||||||
],
|
],
|
||||||
bases=('auth.group',),
|
max_length=5,
|
||||||
|
default="-",
|
||||||
|
verbose_name="tshirt size",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"role",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("STUDENT", "Student"),
|
||||||
|
("ADMINISTRATIVE", "Administrative agent"),
|
||||||
|
("TEACHER", "Teacher"),
|
||||||
|
("AGENT", "Agent"),
|
||||||
|
("DOCTOR", "Doctor"),
|
||||||
|
("FORMER STUDENT", "Former student"),
|
||||||
|
("SERVICE", "Service"),
|
||||||
|
],
|
||||||
|
max_length=15,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="role",
|
||||||
|
default="",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"department",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("TC", "TC"),
|
||||||
|
("IMSI", "IMSI"),
|
||||||
|
("IMAP", "IMAP"),
|
||||||
|
("INFO", "INFO"),
|
||||||
|
("GI", "GI"),
|
||||||
|
("E", "E"),
|
||||||
|
("EE", "EE"),
|
||||||
|
("GESC", "GESC"),
|
||||||
|
("GMC", "GMC"),
|
||||||
|
("MC", "MC"),
|
||||||
|
("EDIM", "EDIM"),
|
||||||
|
("HUMA", "Humanities"),
|
||||||
|
("NA", "N/A"),
|
||||||
|
],
|
||||||
|
max_length=15,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="department",
|
||||||
|
default="NA",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"dpt_option",
|
||||||
|
models.CharField(
|
||||||
|
max_length=32, blank=True, verbose_name="dpt option", default=""
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"semester",
|
||||||
|
models.CharField(
|
||||||
|
max_length=5, blank=True, verbose_name="semester", default=""
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"quote",
|
||||||
|
models.CharField(
|
||||||
|
max_length=256, blank=True, verbose_name="quote", default=""
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"school",
|
||||||
|
models.CharField(
|
||||||
|
max_length=80, blank=True, verbose_name="school", default=""
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"promo",
|
||||||
|
models.IntegerField(
|
||||||
|
null=True,
|
||||||
|
verbose_name="promo",
|
||||||
|
validators=[core.models.validate_promo],
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"forum_signature",
|
||||||
|
models.TextField(
|
||||||
|
max_length=256,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="forum signature",
|
||||||
|
default="",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"second_email",
|
||||||
|
models.EmailField(
|
||||||
|
max_length=254,
|
||||||
|
null=True,
|
||||||
|
verbose_name="second email address",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"phone",
|
||||||
|
phonenumber_field.modelfields.PhoneNumberField(
|
||||||
|
max_length=128, null=True, verbose_name="phone", blank=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"parent_phone",
|
||||||
|
phonenumber_field.modelfields.PhoneNumberField(
|
||||||
|
max_length=128,
|
||||||
|
null=True,
|
||||||
|
verbose_name="parent phone",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"address",
|
||||||
|
models.CharField(
|
||||||
|
max_length=128, blank=True, verbose_name="address", default=""
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"parent_address",
|
||||||
|
models.CharField(
|
||||||
|
max_length=128,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="parent address",
|
||||||
|
default="",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_subscriber_viewable",
|
||||||
|
models.BooleanField(
|
||||||
|
verbose_name="is subscriber viewable", default=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={"abstract": False},
|
||||||
|
managers=[("objects", django.contrib.auth.models.UserManager())],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Page',
|
name="Group",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('name', models.CharField(max_length=30, verbose_name='page name')),
|
"group_ptr",
|
||||||
('_full_name', models.CharField(max_length=255, blank=True, verbose_name='page name')),
|
models.OneToOneField(
|
||||||
('edit_groups', models.ManyToManyField(related_name='editable_page', to='core.Group', blank=True, verbose_name='edit group')),
|
primary_key=True,
|
||||||
('owner_group', models.ForeignKey(default=1, related_name='owned_page', verbose_name='owner group', to='core.Group')),
|
parent_link=True,
|
||||||
('parent', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='children', verbose_name='parent', to='core.Page', blank=True)),
|
serialize=False,
|
||||||
('view_groups', models.ManyToManyField(related_name='viewable_page', to='core.Group', blank=True, verbose_name='view group')),
|
to="auth.Group",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_meta",
|
||||||
|
models.BooleanField(
|
||||||
|
help_text="Whether a group is a meta group or not",
|
||||||
|
verbose_name="meta group status",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"description",
|
||||||
|
models.CharField(max_length=60, verbose_name="description"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
bases=("auth.group",),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Page",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=30, verbose_name="page name")),
|
||||||
|
(
|
||||||
|
"_full_name",
|
||||||
|
models.CharField(
|
||||||
|
max_length=255, blank=True, verbose_name="page name"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"edit_groups",
|
||||||
|
models.ManyToManyField(
|
||||||
|
related_name="editable_page",
|
||||||
|
to="core.Group",
|
||||||
|
blank=True,
|
||||||
|
verbose_name="edit group",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"owner_group",
|
||||||
|
models.ForeignKey(
|
||||||
|
default=1,
|
||||||
|
related_name="owned_page",
|
||||||
|
verbose_name="owner group",
|
||||||
|
to="core.Group",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"parent",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
related_name="children",
|
||||||
|
verbose_name="parent",
|
||||||
|
to="core.Page",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"view_groups",
|
||||||
|
models.ManyToManyField(
|
||||||
|
related_name="viewable_page",
|
||||||
|
to="core.Group",
|
||||||
|
blank=True,
|
||||||
|
verbose_name="view group",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'permissions': (('change_prop_page', "Can change the page's properties (groups, ...)"), ('view_page', 'Can view the page')),
|
"permissions": (
|
||||||
|
(
|
||||||
|
"change_prop_page",
|
||||||
|
"Can change the page's properties (groups, ...)",
|
||||||
|
),
|
||||||
|
("view_page", "Can view the page"),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='PageRev',
|
name="PageRev",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('revision', models.IntegerField(verbose_name='revision')),
|
"id",
|
||||||
('title', models.CharField(max_length=255, blank=True, verbose_name='page title')),
|
models.AutoField(
|
||||||
('content', models.TextField(blank=True, verbose_name='page content')),
|
primary_key=True,
|
||||||
('date', models.DateTimeField(verbose_name='date', auto_now=True)),
|
serialize=False,
|
||||||
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='page_rev')),
|
verbose_name="ID",
|
||||||
('page', models.ForeignKey(to='core.Page', related_name='revisions')),
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("revision", models.IntegerField(verbose_name="revision")),
|
||||||
|
(
|
||||||
|
"title",
|
||||||
|
models.CharField(
|
||||||
|
max_length=255, blank=True, verbose_name="page title"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("content", models.TextField(blank=True, verbose_name="page content")),
|
||||||
|
("date", models.DateTimeField(verbose_name="date", auto_now=True)),
|
||||||
|
(
|
||||||
|
"author",
|
||||||
|
models.ForeignKey(
|
||||||
|
to=settings.AUTH_USER_MODEL, related_name="page_rev"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("page", models.ForeignKey(to="core.Page", related_name="revisions")),
|
||||||
],
|
],
|
||||||
options={
|
options={"ordering": ["date"]},
|
||||||
'ordering': ['date'],
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Preferences',
|
name="Preferences",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('show_my_stats', models.BooleanField(help_text='Show your account statistics to others', verbose_name='define if we show a users stats', default=False)),
|
"id",
|
||||||
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='preferences')),
|
models.AutoField(
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
auto_created=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"show_my_stats",
|
||||||
|
models.BooleanField(
|
||||||
|
help_text="Show your account statistics to others",
|
||||||
|
verbose_name="define if we show a users stats",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.OneToOneField(
|
||||||
|
to=settings.AUTH_USER_MODEL, related_name="preferences"
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='SithFile',
|
name="SithFile",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
(
|
||||||
('name', models.CharField(max_length=30, verbose_name='file name')),
|
"id",
|
||||||
('file', models.FileField(upload_to=core.models.get_directory, null=True, verbose_name='file', blank=True)),
|
models.AutoField(
|
||||||
('is_folder', models.BooleanField(verbose_name='is folder', default=True)),
|
primary_key=True,
|
||||||
('mime_type', models.CharField(max_length=30, verbose_name='mime type')),
|
serialize=False,
|
||||||
('size', models.IntegerField(default=0, verbose_name='size')),
|
verbose_name="ID",
|
||||||
('date', models.DateTimeField(verbose_name='date', auto_now=True)),
|
auto_created=True,
|
||||||
('edit_groups', models.ManyToManyField(related_name='editable_files', to='core.Group', blank=True, verbose_name='edit group')),
|
),
|
||||||
('owner', models.ForeignKey(verbose_name='owner', to=settings.AUTH_USER_MODEL, related_name='owned_files')),
|
),
|
||||||
('parent', models.ForeignKey(null=True, related_name='children', verbose_name='parent', to='core.SithFile', blank=True)),
|
("name", models.CharField(max_length=30, verbose_name="file name")),
|
||||||
('view_groups', models.ManyToManyField(related_name='viewable_files', to='core.Group', blank=True, verbose_name='view group')),
|
(
|
||||||
|
"file",
|
||||||
|
models.FileField(
|
||||||
|
upload_to=core.models.get_directory,
|
||||||
|
null=True,
|
||||||
|
verbose_name="file",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_folder",
|
||||||
|
models.BooleanField(verbose_name="is folder", default=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"mime_type",
|
||||||
|
models.CharField(max_length=30, verbose_name="mime type"),
|
||||||
|
),
|
||||||
|
("size", models.IntegerField(default=0, verbose_name="size")),
|
||||||
|
("date", models.DateTimeField(verbose_name="date", auto_now=True)),
|
||||||
|
(
|
||||||
|
"edit_groups",
|
||||||
|
models.ManyToManyField(
|
||||||
|
related_name="editable_files",
|
||||||
|
to="core.Group",
|
||||||
|
blank=True,
|
||||||
|
verbose_name="edit group",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"owner",
|
||||||
|
models.ForeignKey(
|
||||||
|
verbose_name="owner",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
related_name="owned_files",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"parent",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
related_name="children",
|
||||||
|
verbose_name="parent",
|
||||||
|
to="core.SithFile",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"view_groups",
|
||||||
|
models.ManyToManyField(
|
||||||
|
related_name="viewable_files",
|
||||||
|
to="core.Group",
|
||||||
|
blank=True,
|
||||||
|
verbose_name="view group",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={"verbose_name": "file"},
|
||||||
'verbose_name': 'file',
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='avatar_pict',
|
name="avatar_pict",
|
||||||
field=models.OneToOneField(blank=True, on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='avatar_of', verbose_name='avatar', to='core.SithFile'),
|
field=models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
related_name="avatar_of",
|
||||||
|
verbose_name="avatar",
|
||||||
|
to="core.SithFile",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='home',
|
name="home",
|
||||||
field=models.OneToOneField(blank=True, null=True, related_name='home_of', verbose_name='home', to='core.SithFile'),
|
field=models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name="home_of",
|
||||||
|
verbose_name="home",
|
||||||
|
to="core.SithFile",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='profile_pict',
|
name="profile_pict",
|
||||||
field=models.OneToOneField(blank=True, on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='profile_of', verbose_name='profile', to='core.SithFile'),
|
field=models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
related_name="profile_of",
|
||||||
|
verbose_name="profile",
|
||||||
|
to="core.SithFile",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='scrub_pict',
|
name="scrub_pict",
|
||||||
field=models.OneToOneField(blank=True, on_delete=django.db.models.deletion.SET_NULL, null=True, related_name='scrub_of', verbose_name='scrub', to='core.SithFile'),
|
field=models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
related_name="scrub_of",
|
||||||
|
verbose_name="scrub",
|
||||||
|
to="core.SithFile",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='MetaGroup',
|
name="MetaGroup",
|
||||||
fields=[
|
fields=[],
|
||||||
],
|
options={"proxy": True},
|
||||||
options={
|
bases=("core.group",),
|
||||||
'proxy': True,
|
managers=[("objects", core.models.MetaGroupManager())],
|
||||||
},
|
|
||||||
bases=('core.group',),
|
|
||||||
managers=[
|
|
||||||
('objects', core.models.MetaGroupManager()),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='RealGroup',
|
name="RealGroup",
|
||||||
fields=[
|
fields=[],
|
||||||
],
|
options={"proxy": True},
|
||||||
options={
|
bases=("core.group",),
|
||||||
'proxy': True,
|
managers=[("objects", core.models.RealGroupManager())],
|
||||||
},
|
|
||||||
bases=('core.group',),
|
|
||||||
managers=[
|
|
||||||
('objects', core.models.RealGroupManager()),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
migrations.AlterUniqueTogether(
|
||||||
name='page',
|
name="page", unique_together=set([("name", "parent")])
|
||||||
unique_together=set([('name', 'parent')]),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='groups',
|
name="groups",
|
||||||
field=models.ManyToManyField(to='core.RealGroup', blank=True, related_name='users'),
|
field=models.ManyToManyField(
|
||||||
|
to="core.RealGroup", blank=True, related_name="users"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0001_initial")]
|
||||||
('core', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='name',
|
name="name",
|
||||||
field=models.CharField(verbose_name='file name', max_length=256),
|
field=models.CharField(verbose_name="file name", max_length=256),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,24 @@ import django.core.validators
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0002_auto_20160831_0144")]
|
||||||
('core', '0002_auto_20160831_0144'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='username',
|
name="username",
|
||||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=254, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.+-]+$', 'Enter a valid username. This value may contain only letters, numbers and ./+/-/_ characters.')], help_text='Required. 254 characters or fewer. Letters, digits and ./+/-/_ only.', verbose_name='username'),
|
field=models.CharField(
|
||||||
|
error_messages={"unique": "A user with that username already exists."},
|
||||||
|
max_length=254,
|
||||||
|
unique=True,
|
||||||
|
validators=[
|
||||||
|
django.core.validators.RegexValidator(
|
||||||
|
"^[\\w.+-]+$",
|
||||||
|
"Enter a valid username. This value may contain only letters, numbers and ./+/-/_ characters.",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
help_text="Required. 254 characters or fewer. Letters, digits and ./+/-/_ only.",
|
||||||
|
verbose_name="username",
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,14 @@ from django.conf import settings
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0003_auto_20160902_1914")]
|
||||||
('core', '0003_auto_20160902_1914'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='godfathers',
|
name="godfathers",
|
||||||
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, related_name='godchildren', blank=True),
|
field=models.ManyToManyField(
|
||||||
|
to=settings.AUTH_USER_MODEL, related_name="godchildren", blank=True
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,19 +7,26 @@ from django.conf import settings
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0004_user_godfathers")]
|
||||||
('core', '0004_user_godfathers'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='page',
|
model_name="page",
|
||||||
name='lock_timeout',
|
name="lock_timeout",
|
||||||
field=models.DateTimeField(verbose_name='lock_timeout', null=True, blank=True, default=None),
|
field=models.DateTimeField(
|
||||||
|
verbose_name="lock_timeout", null=True, blank=True, default=None
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='page',
|
model_name="page",
|
||||||
name='lock_user',
|
name="lock_user",
|
||||||
field=models.ForeignKey(verbose_name='lock user', default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True, related_name='locked_pages'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="lock user",
|
||||||
|
default=None,
|
||||||
|
blank=True,
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
null=True,
|
||||||
|
related_name="locked_pages",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0005_auto_20161105_1035")]
|
||||||
('core', '0005_auto_20161105_1035'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='is_moderated',
|
name="is_moderated",
|
||||||
field=models.BooleanField(verbose_name='is moderated', default=False),
|
field=models.BooleanField(verbose_name="is moderated", default=False),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0006_auto_20161108_1703")]
|
||||||
('core', '0006_auto_20161108_1703'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='asked_for_removal',
|
name="asked_for_removal",
|
||||||
field=models.BooleanField(default=False, verbose_name='asked for removal'),
|
field=models.BooleanField(default=False, verbose_name="asked for removal"),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
@ -8,24 +8,39 @@ import core.models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0008_sithfile_asked_for_removal")]
|
||||||
('core', '0008_sithfile_asked_for_removal'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='compressed',
|
name="compressed",
|
||||||
field=models.FileField(upload_to=core.models.get_compressed_directory, null=True, verbose_name='compressed file', blank=True),
|
field=models.FileField(
|
||||||
|
upload_to=core.models.get_compressed_directory,
|
||||||
|
null=True,
|
||||||
|
verbose_name="compressed file",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='thumbnail',
|
name="thumbnail",
|
||||||
field=models.FileField(upload_to=core.models.get_thumbnail_directory, null=True, verbose_name='thumbnail', blank=True),
|
field=models.FileField(
|
||||||
|
upload_to=core.models.get_thumbnail_directory,
|
||||||
|
null=True,
|
||||||
|
verbose_name="thumbnail",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='home',
|
name="home",
|
||||||
field=models.OneToOneField(verbose_name='home', related_name='home_of', on_delete=django.db.models.deletion.SET_NULL, null=True, to='core.SithFile', blank=True),
|
field=models.OneToOneField(
|
||||||
|
verbose_name="home",
|
||||||
|
related_name="home_of",
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
to="core.SithFile",
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0009_auto_20161120_1155")]
|
||||||
('core', '0009_auto_20161120_1155'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='is_in_sas',
|
name="is_in_sas",
|
||||||
field=models.BooleanField(verbose_name='is in the SAS', default=False),
|
field=models.BooleanField(verbose_name="is in the SAS", default=False),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
@ -8,29 +8,47 @@ import core.models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0010_sithfile_is_in_sas")]
|
||||||
('core', '0010_sithfile_is_in_sas'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='compressed',
|
name="compressed",
|
||||||
field=models.FileField(verbose_name='compressed file', upload_to=core.models.get_compressed_directory, null=True, blank=True, max_length=256),
|
field=models.FileField(
|
||||||
|
verbose_name="compressed file",
|
||||||
|
upload_to=core.models.get_compressed_directory,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
max_length=256,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='date',
|
name="date",
|
||||||
field=models.DateTimeField(verbose_name='date', default=django.utils.timezone.now),
|
field=models.DateTimeField(
|
||||||
|
verbose_name="date", default=django.utils.timezone.now
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='file',
|
name="file",
|
||||||
field=models.FileField(verbose_name='file', upload_to=core.models.get_directory, null=True, blank=True, max_length=256),
|
field=models.FileField(
|
||||||
|
verbose_name="file",
|
||||||
|
upload_to=core.models.get_directory,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
max_length=256,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='thumbnail',
|
name="thumbnail",
|
||||||
field=models.FileField(verbose_name='thumbnail', upload_to=core.models.get_thumbnail_directory, null=True, blank=True, max_length=256),
|
field=models.FileField(
|
||||||
|
verbose_name="thumbnail",
|
||||||
|
upload_to=core.models.get_thumbnail_directory,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
max_length=256,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -8,20 +8,49 @@ import django.utils.timezone
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0011_auto_20161124_0848")]
|
||||||
('core', '0011_auto_20161124_0848'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Notification',
|
name="Notification",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
|
(
|
||||||
('url', models.CharField(max_length=255, verbose_name='url')),
|
"id",
|
||||||
('text', models.CharField(max_length=512, verbose_name='text')),
|
models.AutoField(
|
||||||
('type', models.CharField(max_length=16, choices=[('FILE_MODERATION', 'File moderation'), ('SAS_MODERATION', 'SAS moderation'), ('NEW_PICTURES', 'New pictures')], verbose_name='text', null=True, blank=True)),
|
primary_key=True,
|
||||||
('date', models.DateTimeField(verbose_name='date', default=django.utils.timezone.now)),
|
verbose_name="ID",
|
||||||
('user', models.ForeignKey(related_name='notifications', to=settings.AUTH_USER_MODEL)),
|
auto_created=True,
|
||||||
],
|
serialize=False,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
("url", models.CharField(max_length=255, verbose_name="url")),
|
||||||
|
("text", models.CharField(max_length=512, verbose_name="text")),
|
||||||
|
(
|
||||||
|
"type",
|
||||||
|
models.CharField(
|
||||||
|
max_length=16,
|
||||||
|
choices=[
|
||||||
|
("FILE_MODERATION", "File moderation"),
|
||||||
|
("SAS_MODERATION", "SAS moderation"),
|
||||||
|
("NEW_PICTURES", "New pictures"),
|
||||||
|
],
|
||||||
|
verbose_name="text",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"date",
|
||||||
|
models.DateTimeField(
|
||||||
|
verbose_name="date", default=django.utils.timezone.now
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
related_name="notifications", to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,23 +6,18 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0012_notification")]
|
||||||
('core', '0012_notification'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(model_name="notification", name="text"),
|
||||||
model_name='notification',
|
migrations.AddField(
|
||||||
name='text',
|
model_name="notification",
|
||||||
|
name="param",
|
||||||
|
field=models.CharField(verbose_name="param", default="", max_length=128),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='param',
|
name="viewed",
|
||||||
field=models.CharField(verbose_name='param', default='', max_length=128),
|
field=models.BooleanField(verbose_name="viewed", default=False),
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='notification',
|
|
||||||
name='viewed',
|
|
||||||
field=models.BooleanField(verbose_name='viewed', default=False),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,24 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0013_auto_20161209_2338")]
|
||||||
('core', '0013_auto_20161209_2338'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='type',
|
name="type",
|
||||||
field=models.CharField(verbose_name='type', max_length=32, default='GENERIC', choices=[('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')]),
|
field=models.CharField(
|
||||||
|
verbose_name="type",
|
||||||
|
max_length=32,
|
||||||
|
default="GENERIC",
|
||||||
|
choices=[
|
||||||
|
("FILE_MODERATION", "New files to be moderated"),
|
||||||
|
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||||
|
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||||
|
("REFILLING", "You just refilled of %s €"),
|
||||||
|
("SELLING", "You just bought %s"),
|
||||||
|
("GENERIC", "You have a notification"),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,15 +7,18 @@ from django.conf import settings
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0014_auto_20161210_0009")]
|
||||||
('core', '0014_auto_20161210_0009'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='moderator',
|
name="moderator",
|
||||||
field=models.ForeignKey(related_name='moderated_files', verbose_name='owner', default=0, to=settings.AUTH_USER_MODEL),
|
field=models.ForeignKey(
|
||||||
preserve_default=False,
|
related_name="moderated_files",
|
||||||
|
verbose_name="owner",
|
||||||
|
default=0,
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
),
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,18 @@ from django.conf import settings
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0015_sithfile_moderator")]
|
||||||
('core', '0015_sithfile_moderator'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='sithfile',
|
model_name="sithfile",
|
||||||
name='moderator',
|
name="moderator",
|
||||||
field=models.ForeignKey(related_name='moderated_files', blank=True, null=True, to=settings.AUTH_USER_MODEL, verbose_name='owner'),
|
field=models.ForeignKey(
|
||||||
|
related_name="moderated_files",
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="owner",
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,12 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0016_auto_20161212_1922")]
|
||||||
('core', '0016_auto_20161212_1922'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='last_update',
|
name="last_update",
|
||||||
field=models.DateTimeField(verbose_name='last update', auto_now=True),
|
field=models.DateTimeField(verbose_name="last update", auto_now=True),
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,25 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0017_auto_20161220_1626")]
|
||||||
('core', '0017_auto_20161220_1626'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='type',
|
name="type",
|
||||||
field=models.CharField(choices=[('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], default='GENERIC', max_length=32, verbose_name='type'),
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("NEWS_MODERATION", "A fresh new to be moderated"),
|
||||||
|
("FILE_MODERATION", "New files to be moderated"),
|
||||||
|
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||||
|
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||||
|
("REFILLING", "You just refilled of %s €"),
|
||||||
|
("SELLING", "You just bought %s"),
|
||||||
|
("GENERIC", "You have a notification"),
|
||||||
|
],
|
||||||
|
default="GENERIC",
|
||||||
|
max_length=32,
|
||||||
|
verbose_name="type",
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,14 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0018_auto_20161224_0211")]
|
||||||
('core', '0018_auto_20161224_0211'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='preferences',
|
model_name="preferences",
|
||||||
name='receive_weekmail',
|
name="receive_weekmail",
|
||||||
field=models.BooleanField(default=False, verbose_name='do you want to receive the weekmail'),
|
field=models.BooleanField(
|
||||||
|
default=False, verbose_name="do you want to receive the weekmail"
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,18 +7,22 @@ import django.core.validators
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0019_preferences_receive_weekmail")]
|
||||||
('core', '0019_preferences_receive_weekmail'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterModelOptions(
|
migrations.AlterModelOptions(name="group", options={"ordering": ["name"]}),
|
||||||
name='group',
|
|
||||||
options={'ordering': ['name']},
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name="page",
|
||||||
name='name',
|
name="name",
|
||||||
field=models.CharField(validators=[django.core.validators.RegexValidator('^[A-z.+-]+$', 'Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.')], max_length=30, verbose_name='page unix name'),
|
field=models.CharField(
|
||||||
|
validators=[
|
||||||
|
django.core.validators.RegexValidator(
|
||||||
|
"^[A-z.+-]+$",
|
||||||
|
"Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
max_length=30,
|
||||||
|
verbose_name="page unix name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,26 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0020_auto_20170324_0917")]
|
||||||
('core', '0020_auto_20170324_0917'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='type',
|
name="type",
|
||||||
field=models.CharField(verbose_name='type', default='GENERIC', max_length=32, choices=[('MAILING_MODERATION', 'A new mailing list neet to be moderated'), ('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')]),
|
field=models.CharField(
|
||||||
|
verbose_name="type",
|
||||||
|
default="GENERIC",
|
||||||
|
max_length=32,
|
||||||
|
choices=[
|
||||||
|
("MAILING_MODERATION", "A new mailing list neet to be moderated"),
|
||||||
|
("NEWS_MODERATION", "A fresh new to be moderated"),
|
||||||
|
("FILE_MODERATION", "New files to be moderated"),
|
||||||
|
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||||
|
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||||
|
("REFILLING", "You just refilled of %s €"),
|
||||||
|
("SELLING", "You just bought %s"),
|
||||||
|
("GENERIC", "You have a notification"),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,26 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0021_auto_20170822_1529")]
|
||||||
('core', '0021_auto_20170822_1529'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='type',
|
name="type",
|
||||||
field=models.CharField(choices=[('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'A fresh new to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], default='GENERIC', max_length=32, verbose_name='type'),
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||||
|
("NEWS_MODERATION", "A fresh new to be moderated"),
|
||||||
|
("FILE_MODERATION", "New files to be moderated"),
|
||||||
|
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||||
|
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||||
|
("REFILLING", "You just refilled of %s €"),
|
||||||
|
("SELLING", "You just bought %s"),
|
||||||
|
("GENERIC", "You have a notification"),
|
||||||
|
],
|
||||||
|
default="GENERIC",
|
||||||
|
max_length=32,
|
||||||
|
verbose_name="type",
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,29 +7,35 @@ from django.conf import settings
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0022_auto_20170822_2232")]
|
||||||
('core', '0022_auto_20170822_2232'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='preferences',
|
model_name="preferences",
|
||||||
name='notify_on_click',
|
name="notify_on_click",
|
||||||
field=models.BooleanField(verbose_name='get a notification for every click', default=False),
|
field=models.BooleanField(
|
||||||
|
verbose_name="get a notification for every click", default=False
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='preferences',
|
model_name="preferences",
|
||||||
name='notify_on_refill',
|
name="notify_on_refill",
|
||||||
field=models.BooleanField(verbose_name='get a notification for every refilling', default=False),
|
field=models.BooleanField(
|
||||||
|
verbose_name="get a notification for every refilling", default=False
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='preferences',
|
model_name="preferences",
|
||||||
name='show_my_stats',
|
name="show_my_stats",
|
||||||
field=models.BooleanField(verbose_name='show your stats to others', default=False),
|
field=models.BooleanField(
|
||||||
|
verbose_name="show your stats to others", default=False
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='preferences',
|
model_name="preferences",
|
||||||
name='user',
|
name="user",
|
||||||
field=models.OneToOneField(related_name='_preferences', to=settings.AUTH_USER_MODEL),
|
field=models.OneToOneField(
|
||||||
|
related_name="_preferences", to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,26 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0023_auto_20170902_1226")]
|
||||||
('core', '0023_auto_20170902_1226'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='type',
|
name="type",
|
||||||
field=models.CharField(choices=[('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'There are %s fresh news to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'New pictures/album to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], verbose_name='type', default='GENERIC', max_length=32),
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||||
|
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
|
||||||
|
("FILE_MODERATION", "New files to be moderated"),
|
||||||
|
("SAS_MODERATION", "New pictures/album to be moderated in the SAS"),
|
||||||
|
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||||
|
("REFILLING", "You just refilled of %s €"),
|
||||||
|
("SELLING", "You just bought %s"),
|
||||||
|
("GENERIC", "You have a notification"),
|
||||||
|
],
|
||||||
|
verbose_name="type",
|
||||||
|
default="GENERIC",
|
||||||
|
max_length=32,
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,21 @@ import django.core.validators
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0024_auto_20170906_1317")]
|
||||||
('core', '0024_auto_20170906_1317'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name="page",
|
||||||
name='name',
|
name="name",
|
||||||
field=models.CharField(max_length=30, verbose_name='page unix name', validators=[django.core.validators.RegexValidator('^[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]$', 'Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.')]),
|
field=models.CharField(
|
||||||
|
max_length=30,
|
||||||
|
verbose_name="page unix name",
|
||||||
|
validators=[
|
||||||
|
django.core.validators.RegexValidator(
|
||||||
|
"^[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]$",
|
||||||
|
"Enter a valid page name. This value may contain only unaccented letters, numbers and ./+/-/_ characters.",
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,29 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0025_auto_20170919_1521")]
|
||||||
('core', '0025_auto_20170919_1521'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='type',
|
name="type",
|
||||||
field=models.CharField(choices=[('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'There are %s fresh news to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'There are %s pictures to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')], verbose_name='type', max_length=32, default='GENERIC'),
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||||
|
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
|
||||||
|
("FILE_MODERATION", "New files to be moderated"),
|
||||||
|
(
|
||||||
|
"SAS_MODERATION",
|
||||||
|
"There are %s pictures to be moderated in the SAS",
|
||||||
),
|
),
|
||||||
|
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||||
|
("REFILLING", "You just refilled of %s €"),
|
||||||
|
("SELLING", "You just bought %s"),
|
||||||
|
("GENERIC", "You have a notification"),
|
||||||
|
],
|
||||||
|
verbose_name="type",
|
||||||
|
max_length=32,
|
||||||
|
default="GENERIC",
|
||||||
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -8,18 +8,34 @@ import django.utils.timezone
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0026_auto_20170926_1512")]
|
||||||
('core', '0026_auto_20170926_1512'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Gift',
|
name="Gift",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
|
(
|
||||||
('label', models.CharField(max_length=255, verbose_name='label')),
|
"id",
|
||||||
('date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date')),
|
models.AutoField(
|
||||||
('user', models.ForeignKey(related_name='gifts', to=settings.AUTH_USER_MODEL)),
|
primary_key=True,
|
||||||
],
|
auto_created=True,
|
||||||
|
verbose_name="ID",
|
||||||
|
serialize=False,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
("label", models.CharField(max_length=255, verbose_name="label")),
|
||||||
|
(
|
||||||
|
"date",
|
||||||
|
models.DateTimeField(
|
||||||
|
default=django.utils.timezone.now, verbose_name="date"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
related_name="gifts", to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -6,14 +6,30 @@ from django.db import migrations, models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0027_gift")]
|
||||||
('core', '0027_gift'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='notification',
|
model_name="notification",
|
||||||
name='type',
|
name="type",
|
||||||
field=models.CharField(default='GENERIC', verbose_name='type', max_length=32, choices=[('POSTER_MODERATION', 'A new poster needs to be moderated'), ('MAILING_MODERATION', 'A new mailing list needs to be moderated'), ('NEWS_MODERATION', 'There are %s fresh news to be moderated'), ('FILE_MODERATION', 'New files to be moderated'), ('SAS_MODERATION', 'There are %s pictures to be moderated in the SAS'), ('NEW_PICTURES', "You've been identified on some pictures"), ('REFILLING', 'You just refilled of %s €'), ('SELLING', 'You just bought %s'), ('GENERIC', 'You have a notification')]),
|
field=models.CharField(
|
||||||
|
default="GENERIC",
|
||||||
|
verbose_name="type",
|
||||||
|
max_length=32,
|
||||||
|
choices=[
|
||||||
|
("POSTER_MODERATION", "A new poster needs to be moderated"),
|
||||||
|
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||||
|
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
|
||||||
|
("FILE_MODERATION", "New files to be moderated"),
|
||||||
|
(
|
||||||
|
"SAS_MODERATION",
|
||||||
|
"There are %s pictures to be moderated in the SAS",
|
||||||
),
|
),
|
||||||
|
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||||
|
("REFILLING", "You just refilled of %s €"),
|
||||||
|
("SELLING", "You just bought %s"),
|
||||||
|
("GENERIC", "You have a notification"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
@ -7,14 +7,17 @@ import core.models
|
|||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("core", "0028_auto_20171216_2044")]
|
||||||
('core', '0028_auto_20171216_2044'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name="page",
|
||||||
name='owner_group',
|
name="owner_group",
|
||||||
field=models.ForeignKey(verbose_name='owner group', default=core.models.Page.get_default_owner_group, related_name='owned_page', to='core.Group'),
|
field=models.ForeignKey(
|
||||||
|
verbose_name="owner group",
|
||||||
|
default=core.models.Page.get_default_owner_group,
|
||||||
|
related_name="owned_page",
|
||||||
|
to="core.Group",
|
||||||
),
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
598
core/models.py
598
core/models.py
File diff suppressed because it is too large
Load Diff
@ -46,5 +46,5 @@ class PsqlRunOnly(migrations.RunSQL):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def _run_sql(self, schema_editor, sqls):
|
def _run_sql(self, schema_editor, sqls):
|
||||||
if connection.vendor == 'postgresql':
|
if connection.vendor == "postgresql":
|
||||||
super(PsqlRunOnly, self)._run_sql(schema_editor, sqls)
|
super(PsqlRunOnly, self)._run_sql(schema_editor, sqls)
|
||||||
|
@ -34,21 +34,20 @@ class ScssFinder(FileSystemFinder):
|
|||||||
"""
|
"""
|
||||||
Find static *.css files compiled on the fly
|
Find static *.css files compiled on the fly
|
||||||
"""
|
"""
|
||||||
|
|
||||||
locations = []
|
locations = []
|
||||||
|
|
||||||
def __init__(self, apps=None, *args, **kwargs):
|
def __init__(self, apps=None, *args, **kwargs):
|
||||||
location = settings.STATIC_ROOT
|
location = settings.STATIC_ROOT
|
||||||
if not os.path.isdir(location):
|
if not os.path.isdir(location):
|
||||||
return
|
return
|
||||||
self.locations = [
|
self.locations = [("", location)]
|
||||||
('', location),
|
|
||||||
]
|
|
||||||
self.storages = OrderedDict()
|
self.storages = OrderedDict()
|
||||||
filesystem_storage = FileSystemStorage(location=location)
|
filesystem_storage = FileSystemStorage(location=location)
|
||||||
filesystem_storage.prefix = self.locations[0][0]
|
filesystem_storage.prefix = self.locations[0][0]
|
||||||
self.storages[location] = filesystem_storage
|
self.storages[location] = filesystem_storage
|
||||||
|
|
||||||
def find(self, path, all=False):
|
def find(self, path, all=False):
|
||||||
if path.endswith('.css'):
|
if path.endswith(".css"):
|
||||||
return super(ScssFinder, self).find(path, all)
|
return super(ScssFinder, self).find(path, all)
|
||||||
return []
|
return []
|
||||||
|
@ -39,7 +39,8 @@ class ScssProcessor(object):
|
|||||||
Else : give the path of the corresponding css supposed to already be compiled
|
Else : give the path of the corresponding css supposed to already be compiled
|
||||||
Don't forget to use compilestatics to compile scss for production
|
Don't forget to use compilestatics to compile scss for production
|
||||||
"""
|
"""
|
||||||
prefix = iri_to_uri(getattr(settings, 'STATIC_URL', '/static/'))
|
|
||||||
|
prefix = iri_to_uri(getattr(settings, "STATIC_URL", "/static/"))
|
||||||
storage = ScssFileStorage()
|
storage = ScssFileStorage()
|
||||||
scss_extensions = [".scss"]
|
scss_extensions = [".scss"]
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ class ScssProcessor(object):
|
|||||||
"include_paths": settings.SASS_INCLUDE_FOLDERS,
|
"include_paths": settings.SASS_INCLUDE_FOLDERS,
|
||||||
}
|
}
|
||||||
if settings.SASS_PRECISION:
|
if settings.SASS_PRECISION:
|
||||||
compile_args['precision'] = settings.SASS_PRECISION
|
compile_args["precision"] = settings.SASS_PRECISION
|
||||||
content = sass.compile(**compile_args)
|
content = sass.compile(**compile_args)
|
||||||
content = force_bytes(content)
|
content = force_bytes(content)
|
||||||
|
|
||||||
|
@ -21,4 +21,3 @@
|
|||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -38,11 +38,11 @@ register = template.Library()
|
|||||||
@register.filter(is_safe=False)
|
@register.filter(is_safe=False)
|
||||||
@stringfilter
|
@stringfilter
|
||||||
def markdown(text):
|
def markdown(text):
|
||||||
return mark_safe("<div class=\"markdown\">%s</div>" % md(text))
|
return mark_safe('<div class="markdown">%s</div>' % md(text))
|
||||||
|
|
||||||
@register.filter(name='phonenumber')
|
|
||||||
def phonenumber(value, country='FR',
|
@register.filter(name="phonenumber")
|
||||||
format=phonenumbers.PhoneNumberFormat.NATIONAL):
|
def phonenumber(value, country="FR", format=phonenumbers.PhoneNumberFormat.NATIONAL):
|
||||||
"""
|
"""
|
||||||
This filter is kindly borrowed from https://github.com/foundertherapy/django-phonenumber-filter
|
This filter is kindly borrowed from https://github.com/foundertherapy/django-phonenumber-filter
|
||||||
"""
|
"""
|
||||||
@ -53,13 +53,37 @@ def phonenumber(value, country='FR',
|
|||||||
except phonenumbers.NumberParseException as e:
|
except phonenumbers.NumberParseException as e:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
@register.filter()
|
@register.filter()
|
||||||
@stringfilter
|
@stringfilter
|
||||||
def datetime_format_python_to_PHP(python_format_string):
|
def datetime_format_python_to_PHP(python_format_string):
|
||||||
"""
|
"""
|
||||||
Given a python datetime format string, attempts to convert it to the nearest PHP datetime format string possible.
|
Given a python datetime format string, attempts to convert it to the nearest PHP datetime format string possible.
|
||||||
"""
|
"""
|
||||||
python2PHP = {"%a": "D", "%a": "D", "%A": "l", "%b": "M", "%B": "F", "%c": "", "%d": "d", "%H": "H", "%I": "h", "%j": "z", "%m": "m", "%M": "i", "%p": "A", "%S": "s", "%U": "", "%w": "w", "%W": "W", "%x": "", "%X": "", "%y": "y", "%Y": "Y", "%Z": "e"}
|
python2PHP = {
|
||||||
|
"%a": "D",
|
||||||
|
"%a": "D",
|
||||||
|
"%A": "l",
|
||||||
|
"%b": "M",
|
||||||
|
"%B": "F",
|
||||||
|
"%c": "",
|
||||||
|
"%d": "d",
|
||||||
|
"%H": "H",
|
||||||
|
"%I": "h",
|
||||||
|
"%j": "z",
|
||||||
|
"%m": "m",
|
||||||
|
"%M": "i",
|
||||||
|
"%p": "A",
|
||||||
|
"%S": "s",
|
||||||
|
"%U": "",
|
||||||
|
"%w": "w",
|
||||||
|
"%W": "W",
|
||||||
|
"%x": "",
|
||||||
|
"%X": "",
|
||||||
|
"%y": "y",
|
||||||
|
"%Y": "Y",
|
||||||
|
"%Z": "e",
|
||||||
|
}
|
||||||
|
|
||||||
php_format_string = python_format_string
|
php_format_string = python_format_string
|
||||||
for py, php in python2PHP.items():
|
for py, php in python2PHP.items():
|
||||||
|
392
core/tests.py
392
core/tests.py
@ -49,161 +49,203 @@ class UserRegistrationTest(TestCase):
|
|||||||
Should register a user correctly
|
Should register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
response = c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'guy@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Guy",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "guy@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
|
"captcha_0": "dummy-value",
|
||||||
|
"captcha_1": "PASSED",
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_OK' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_OK" in str(response.content))
|
||||||
|
|
||||||
def test_register_user_form_fail_password(self):
|
def test_register_user_form_fail_password(self):
|
||||||
"""
|
"""
|
||||||
Should not register a user correctly
|
Should not register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
response = c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Guy",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop2',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop2",
|
||||||
|
"captcha_0": "dummy-value",
|
||||||
|
"captcha_1": "PASSED",
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||||
|
|
||||||
def test_register_user_form_fail_email(self):
|
def test_register_user_form_fail_email(self):
|
||||||
"""
|
"""
|
||||||
Should not register a user correctly
|
Should not register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
response = c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou.git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Guy",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "bibou.git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
|
"captcha_0": "dummy-value",
|
||||||
|
"captcha_1": "PASSED",
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||||
|
|
||||||
def test_register_user_form_fail_missing_name(self):
|
def test_register_user_form_fail_missing_name(self):
|
||||||
"""
|
"""
|
||||||
Should not register a user correctly
|
Should not register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
response = c.post(reverse('core:register'), {'first_name': 'Guy',
|
response = c.post(
|
||||||
'last_name': '',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Guy",
|
||||||
'password1': 'plop',
|
"last_name": "",
|
||||||
'password2': 'plop',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
|
"captcha_0": "dummy-value",
|
||||||
|
"captcha_1": "PASSED",
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||||
|
|
||||||
def test_register_user_form_fail_missing_date_of_birth(self):
|
def test_register_user_form_fail_missing_date_of_birth(self):
|
||||||
"""
|
"""
|
||||||
Should not register a user correctly
|
Should not register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
response = c.post(reverse('core:register'), {'first_name': '',
|
response = c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '',
|
"first_name": "",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
|
"captcha_0": "dummy-value",
|
||||||
|
"captcha_1": "PASSED",
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||||
|
|
||||||
def test_register_user_form_fail_missing_first_name(self):
|
def test_register_user_form_fail_missing_first_name(self):
|
||||||
"""
|
"""
|
||||||
Should not register a user correctly
|
Should not register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
response = c.post(reverse('core:register'), {'first_name': '',
|
response = c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
|
"captcha_0": "dummy-value",
|
||||||
|
"captcha_1": "PASSED",
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||||
|
|
||||||
def test_register_user_form_fail_wrong_captcha(self):
|
def test_register_user_form_fail_wrong_captcha(self):
|
||||||
"""
|
"""
|
||||||
Should not register a user correctly
|
Should not register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
response = c.post(reverse('core:register'), {'first_name': 'Bibou',
|
response = c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Bibou",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'WRONG_CAPTCHA'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
|
"captcha_0": "dummy-value",
|
||||||
|
"captcha_1": "WRONG_CAPTCHA",
|
||||||
|
},
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||||
|
|
||||||
def test_register_user_form_fail_already_exists(self):
|
def test_register_user_form_fail_already_exists(self):
|
||||||
"""
|
"""
|
||||||
Should not register a user correctly
|
Should not register a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
c.post(reverse('core:register'), {'first_name': 'Guy',
|
c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Guy",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
response = c.post(reverse('core:register'), {'first_name': 'Bibou',
|
"captcha_0": "dummy-value",
|
||||||
'last_name': 'Carlier',
|
"captcha_1": "PASSED",
|
||||||
'email': 'bibou@git.an',
|
},
|
||||||
'date_of_birth': '12/6/1942',
|
)
|
||||||
'password1': 'plop',
|
response = c.post(
|
||||||
'password2': 'plop',
|
reverse("core:register"),
|
||||||
'captcha_0': 'dummy-value',
|
{
|
||||||
'captcha_1': 'PASSED'
|
"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(response.status_code == 200)
|
||||||
self.assertTrue('TEST_REGISTER_USER_FORM_FAIL' in str(response.content))
|
self.assertTrue("TEST_REGISTER_USER_FORM_FAIL" in str(response.content))
|
||||||
|
|
||||||
def test_login_success(self):
|
def test_login_success(self):
|
||||||
"""
|
"""
|
||||||
Should login a user correctly
|
Should login a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
c.post(reverse('core:register'), {'first_name': 'Guy',
|
c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Guy",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
response = c.post(reverse('core:login'), {'username': 'gcarlier', 'password': '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(response.status_code == 302)
|
||||||
# self.assertTrue('Hello, world' in str(response.content))
|
# self.assertTrue('Hello, world' in str(response.content))
|
||||||
|
|
||||||
@ -212,40 +254,56 @@ class UserRegistrationTest(TestCase):
|
|||||||
Should not login a user correctly
|
Should not login a user correctly
|
||||||
"""
|
"""
|
||||||
c = Client()
|
c = Client()
|
||||||
c.post(reverse('core:register'), {'first_name': 'Guy',
|
c.post(
|
||||||
'last_name': 'Carlier',
|
reverse("core:register"),
|
||||||
'email': 'bibou@git.an',
|
{
|
||||||
'date_of_birth': '12/6/1942',
|
"first_name": "Guy",
|
||||||
'password1': 'plop',
|
"last_name": "Carlier",
|
||||||
'password2': 'plop',
|
"email": "bibou@git.an",
|
||||||
'captcha_0': 'dummy-value',
|
"date_of_birth": "12/6/1942",
|
||||||
'captcha_1': 'PASSED'
|
"password1": "plop",
|
||||||
})
|
"password2": "plop",
|
||||||
response = c.post(reverse('core:login'), {'username': 'gcarlier', 'password': 'guy'})
|
"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(response.status_code == 200)
|
||||||
self.assertTrue("""<p>Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>""" in str(response.content))
|
self.assertTrue(
|
||||||
|
"""<p>Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>"""
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MarkdownTest(TestCase):
|
class MarkdownTest(TestCase):
|
||||||
def test_full_markdown_syntax(self):
|
def test_full_markdown_syntax(self):
|
||||||
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
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:
|
with open(os.path.join(root_path) + "/doc/SYNTAX.md", "r") as md_file:
|
||||||
md = md_file.read()
|
md = md_file.read()
|
||||||
with open(os.path.join(root_path) + '/doc/SYNTAX.html', 'r') as html_file:
|
with open(os.path.join(root_path) + "/doc/SYNTAX.html", "r") as html_file:
|
||||||
html = html_file.read()
|
html = html_file.read()
|
||||||
result = markdown(md)
|
result = markdown(md)
|
||||||
self.assertTrue(result == html)
|
self.assertTrue(result == html)
|
||||||
|
|
||||||
|
|
||||||
class PageHandlingTest(TestCase):
|
class PageHandlingTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
try:
|
try:
|
||||||
Group.objects.create(name="root")
|
Group.objects.create(name="root")
|
||||||
u = User(username='root', last_name="", first_name="Bibou",
|
u = User(
|
||||||
|
username="root",
|
||||||
|
last_name="",
|
||||||
|
first_name="Bibou",
|
||||||
email="ae.info@utbm.fr",
|
email="ae.info@utbm.fr",
|
||||||
date_of_birth="1942-06-12",
|
date_of_birth="1942-06-12",
|
||||||
is_superuser=True, is_staff=True)
|
is_superuser=True,
|
||||||
|
is_staff=True,
|
||||||
|
)
|
||||||
u.set_password("plop")
|
u.set_password("plop")
|
||||||
u.save()
|
u.save()
|
||||||
self.client.login(username='root', password='plop')
|
self.client.login(username="root", password="plop")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
@ -253,12 +311,10 @@ class PageHandlingTest(TestCase):
|
|||||||
"""
|
"""
|
||||||
Should create a page correctly
|
Should create a page correctly
|
||||||
"""
|
"""
|
||||||
self.client.post(reverse('core:page_new'), {
|
self.client.post(
|
||||||
'parent': '',
|
reverse("core:page_new"), {"parent": "", "name": "guy", "owner_group": 1}
|
||||||
'name': 'guy',
|
)
|
||||||
'owner_group': 1,
|
response = self.client.get(reverse("core:page", kwargs={"page_name": "guy"}))
|
||||||
})
|
|
||||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy'}))
|
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('<a href="/page/guy/hist">' in str(response.content))
|
self.assertTrue('<a href="/page/guy/hist">' in str(response.content))
|
||||||
|
|
||||||
@ -266,17 +322,16 @@ class PageHandlingTest(TestCase):
|
|||||||
"""
|
"""
|
||||||
Should create a page correctly
|
Should create a page correctly
|
||||||
"""
|
"""
|
||||||
self.client.post(reverse('core:page_new'), {
|
self.client.post(
|
||||||
'parent': '',
|
reverse("core:page_new"), {"parent": "", "name": "guy", "owner_group": "1"}
|
||||||
'name': 'guy',
|
)
|
||||||
'owner_group': '1',
|
response = self.client.post(
|
||||||
})
|
reverse("core:page_new"),
|
||||||
response = self.client.post(reverse('core:page_new'), {
|
{"parent": "1", "name": "bibou", "owner_group": "1"},
|
||||||
'parent': '1',
|
)
|
||||||
'name': 'bibou',
|
response = self.client.get(
|
||||||
'owner_group': '1',
|
reverse("core:page", kwargs={"page_name": "guy/bibou"})
|
||||||
})
|
)
|
||||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy/bibou'}))
|
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('<a href="/page/guy/bibou/">' in str(response.content))
|
self.assertTrue('<a href="/page/guy/bibou/">' in str(response.content))
|
||||||
|
|
||||||
@ -286,17 +341,24 @@ class PageHandlingTest(TestCase):
|
|||||||
"""
|
"""
|
||||||
parent = Page(name="guy", owner_group=Group.objects.filter(id=1).first())
|
parent = Page(name="guy", owner_group=Group.objects.filter(id=1).first())
|
||||||
parent.save(force_lock=True)
|
parent.save(force_lock=True)
|
||||||
page = Page(name="bibou", owner_group=Group.objects.filter(id=1).first(), parent=parent)
|
page = Page(
|
||||||
|
name="bibou", owner_group=Group.objects.filter(id=1).first(), parent=parent
|
||||||
|
)
|
||||||
page.save(force_lock=True)
|
page.save(force_lock=True)
|
||||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy/bibou'}))
|
response = self.client.get(
|
||||||
|
reverse("core:page", kwargs={"page_name": "guy/bibou"})
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('<a href="/page/guy/bibou/edit">\\xc3\\x89diter</a>' in str(response.content))
|
self.assertTrue(
|
||||||
|
'<a href="/page/guy/bibou/edit">\\xc3\\x89diter</a>'
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
def test_access_page_not_found(self):
|
def test_access_page_not_found(self):
|
||||||
"""
|
"""
|
||||||
Should not display a page correctly
|
Should not display a page correctly
|
||||||
"""
|
"""
|
||||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'swagg'}))
|
response = self.client.get(reverse("core:page", kwargs={"page_name": "swagg"}))
|
||||||
response = self.client.get("/page/swagg/")
|
response = self.client.get("/page/swagg/")
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue('<a href="/page/create?page=swagg">' in str(response.content))
|
self.assertTrue('<a href="/page/create?page=swagg">' in str(response.content))
|
||||||
@ -305,15 +367,14 @@ class PageHandlingTest(TestCase):
|
|||||||
"""
|
"""
|
||||||
Should format the markdown and escape html correctly
|
Should format the markdown and escape html correctly
|
||||||
"""
|
"""
|
||||||
self.client.post(reverse('core:page_new'), {
|
self.client.post(
|
||||||
'parent': '',
|
reverse("core:page_new"), {"parent": "", "name": "guy", "owner_group": "1"}
|
||||||
'name': 'guy',
|
)
|
||||||
'owner_group': '1',
|
self.client.post(
|
||||||
})
|
reverse("core:page_edit", kwargs={"page_name": "guy"}),
|
||||||
self.client.post(reverse('core:page_edit', kwargs={'page_name': 'guy'}), {
|
{
|
||||||
'title': 'Bibou',
|
"title": "Bibou",
|
||||||
'content':
|
"content": """Guy *bibou*
|
||||||
'''Guy *bibou*
|
|
||||||
|
|
||||||
http://git.an
|
http://git.an
|
||||||
|
|
||||||
@ -322,13 +383,18 @@ http://git.an
|
|||||||
<guy>Bibou</guy>
|
<guy>Bibou</guy>
|
||||||
|
|
||||||
<script>alert('Guy');</script>
|
<script>alert('Guy');</script>
|
||||||
''',
|
""",
|
||||||
})
|
},
|
||||||
response = self.client.get(reverse('core:page', kwargs={'page_name': 'guy'}))
|
)
|
||||||
|
response = self.client.get(reverse("core:page", kwargs={"page_name": "guy"}))
|
||||||
self.assertTrue(response.status_code == 200)
|
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' +
|
self.assertTrue(
|
||||||
'<h1>Swag</h1>\\n<guy>Bibou</guy>' +
|
'<p>Guy <em>bibou</em></p>\\n<p><a href="http://git.an">http://git.an</a></p>\\n'
|
||||||
"<script>alert(\\'Guy\\');</script>" in str(response.content))
|
+ "<h1>Swag</h1>\\n<guy>Bibou</guy>"
|
||||||
|
+ "<script>alert(\\'Guy\\');</script>"
|
||||||
|
in str(response.content)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# TODO: many tests on the pages:
|
# TODO: many tests on the pages:
|
||||||
# - renaming a page
|
# - renaming a page
|
||||||
@ -341,23 +407,33 @@ class FileHandlingTest(TestCase):
|
|||||||
try:
|
try:
|
||||||
call_command("populate")
|
call_command("populate")
|
||||||
self.subscriber = User.objects.filter(username="subscriber").first()
|
self.subscriber = User.objects.filter(username="subscriber").first()
|
||||||
self.client.login(username='subscriber', password='plop')
|
self.client.login(username="subscriber", password="plop")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
def test_create_folder_home(self):
|
def test_create_folder_home(self):
|
||||||
response = self.client.post(reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}),
|
response = self.client.post(
|
||||||
{"folder_name": "GUY_folder_test"})
|
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}),
|
||||||
|
{"folder_name": "GUY_folder_test"},
|
||||||
|
)
|
||||||
self.assertTrue(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}))
|
response = self.client.get(
|
||||||
|
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id})
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue("GUY_folder_test</a>" in str(response.content))
|
self.assertTrue("GUY_folder_test</a>" in str(response.content))
|
||||||
|
|
||||||
def test_upload_file_home(self):
|
def test_upload_file_home(self):
|
||||||
with open("/bin/ls", "rb") as f:
|
with open("/bin/ls", "rb") as f:
|
||||||
response = self.client.post(reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}),
|
response = self.client.post(
|
||||||
{"file_field": f})
|
reverse(
|
||||||
|
"core:file_detail", kwargs={"file_id": self.subscriber.home.id}
|
||||||
|
),
|
||||||
|
{"file_field": f},
|
||||||
|
)
|
||||||
self.assertTrue(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}))
|
response = self.client.get(
|
||||||
|
reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id})
|
||||||
|
)
|
||||||
self.assertTrue(response.status_code == 200)
|
self.assertTrue(response.status_code == 200)
|
||||||
self.assertTrue("ls</a>" in str(response.content))
|
self.assertTrue("ls</a>" in str(response.content))
|
||||||
|
232
core/urls.py
232
core/urls.py
@ -28,73 +28,181 @@ from django.conf.urls import url
|
|||||||
from core.views import *
|
from core.views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', index, name='index'),
|
url(r"^$", index, name="index"),
|
||||||
url(r'^to_markdown$', ToMarkdownView.as_view(), name='to_markdown'),
|
url(r"^to_markdown$", ToMarkdownView.as_view(), name="to_markdown"),
|
||||||
url(r'^notifications$', NotificationList.as_view(), name='notification_list'),
|
url(r"^notifications$", NotificationList.as_view(), name="notification_list"),
|
||||||
url(r'^notification/(?P<notif_id>[0-9]+)$', notification, name='notification'),
|
url(r"^notification/(?P<notif_id>[0-9]+)$", notification, name="notification"),
|
||||||
|
|
||||||
# Search
|
# Search
|
||||||
url(r'^search/$', search_view, name='search'),
|
url(r"^search/$", search_view, name="search"),
|
||||||
url(r'^search_json/$', search_json, name='search_json'),
|
url(r"^search_json/$", search_json, name="search_json"),
|
||||||
url(r'^search_user/$', search_user_json, name='search_user'),
|
url(r"^search_user/$", search_user_json, name="search_user"),
|
||||||
|
|
||||||
# Login and co
|
# Login and co
|
||||||
url(r'^login/$', login, name='login'),
|
url(r"^login/$", login, name="login"),
|
||||||
url(r'^logout/$', logout, name='logout'),
|
url(r"^logout/$", logout, name="logout"),
|
||||||
url(r'^password_change/$', password_change, name='password_change'),
|
url(r"^password_change/$", password_change, name="password_change"),
|
||||||
url(r'^password_change/(?P<user_id>[0-9]+)$', password_root_change, name='password_root_change'),
|
url(
|
||||||
url(r'^password_change/done$', password_change_done, name='password_change_done'),
|
r"^password_change/(?P<user_id>[0-9]+)$",
|
||||||
url(r'^password_reset/$', password_reset, name='password_reset'),
|
password_root_change,
|
||||||
url(r'^password_reset/done$', password_reset_done, name='password_reset_done'),
|
name="password_root_change",
|
||||||
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', password_reset_confirm, name='password_reset_confirm'),
|
),
|
||||||
url(r'^reset/done/$', password_reset_complete, name='password_reset_complete'),
|
url(r"^password_change/done$", password_change_done, name="password_change_done"),
|
||||||
url(r'^register$', register, name='register'),
|
url(r"^password_reset/$", password_reset, name="password_reset"),
|
||||||
|
url(r"^password_reset/done$", password_reset_done, name="password_reset_done"),
|
||||||
|
url(
|
||||||
|
r"^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$",
|
||||||
|
password_reset_confirm,
|
||||||
|
name="password_reset_confirm",
|
||||||
|
),
|
||||||
|
url(r"^reset/done/$", password_reset_complete, name="password_reset_complete"),
|
||||||
|
url(r"^register$", register, name="register"),
|
||||||
# Group handling
|
# Group handling
|
||||||
url(r'^group/$', GroupListView.as_view(), name='group_list'),
|
url(r"^group/$", GroupListView.as_view(), name="group_list"),
|
||||||
url(r'^group/new$', GroupCreateView.as_view(), name='group_new'),
|
url(r"^group/new$", GroupCreateView.as_view(), name="group_new"),
|
||||||
url(r'^group/(?P<group_id>[0-9]+)/$', GroupEditView.as_view(), name='group_edit'),
|
url(r"^group/(?P<group_id>[0-9]+)/$", GroupEditView.as_view(), name="group_edit"),
|
||||||
url(r'^group/(?P<group_id>[0-9]+)/delete$', GroupDeleteView.as_view(), name='group_delete'),
|
url(
|
||||||
|
r"^group/(?P<group_id>[0-9]+)/delete$",
|
||||||
|
GroupDeleteView.as_view(),
|
||||||
|
name="group_delete",
|
||||||
|
),
|
||||||
# User views
|
# User views
|
||||||
url(r'^user/$', UserListView.as_view(), name='user_list'),
|
url(r"^user/$", UserListView.as_view(), name="user_list"),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/mini$', UserMiniView.as_view(), name='user_profile_mini'),
|
url(
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/$', UserView.as_view(), name='user_profile'),
|
r"^user/(?P<user_id>[0-9]+)/mini$",
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/pictures$', UserPicturesView.as_view(), name='user_pictures'),
|
UserMiniView.as_view(),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers$', UserGodfathersView.as_view(), name='user_godfathers'),
|
name="user_profile_mini",
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers/tree$', UserGodfathersTreeView.as_view(), name='user_godfathers_tree'),
|
),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers/tree/pict$', UserGodfathersTreePictureView.as_view(), name='user_godfathers_tree_pict'),
|
url(r"^user/(?P<user_id>[0-9]+)/$", UserView.as_view(), name="user_profile"),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/godfathers/(?P<godfather_id>[0-9]+)/(?P<is_father>(True)|(False))/delete$', DeleteUserGodfathers, name='user_godfathers_delete'),
|
url(
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/edit$', UserUpdateProfileView.as_view(), name='user_edit'),
|
r"^user/(?P<user_id>[0-9]+)/pictures$",
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/profile_upload$', UserUploadProfilePictView.as_view(), name='user_profile_upload'),
|
UserPicturesView.as_view(),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/clubs$', UserClubView.as_view(), name='user_clubs'),
|
name="user_pictures",
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/prefs$', UserPreferencesView.as_view(), name='user_prefs'),
|
),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/groups$', UserUpdateGroupView.as_view(), name='user_groups'),
|
url(
|
||||||
url(r'^user/tools/$', UserToolsView.as_view(), name='user_tools'),
|
r"^user/(?P<user_id>[0-9]+)/godfathers$",
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/account$', UserAccountView.as_view(), name='user_account'),
|
UserGodfathersView.as_view(),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/account/(?P<year>[0-9]+)/(?P<month>[0-9]+)$', UserAccountDetailView.as_view(), name='user_account_detail'),
|
name="user_godfathers",
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/stats$', UserStatsView.as_view(), name='user_stats'),
|
),
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/gift/create$', GiftCreateView.as_view(), name='user_gift_create'),
|
url(
|
||||||
url(r'^user/(?P<user_id>[0-9]+)/gift/delete/(?P<gift_id>[0-9]+)/$', GiftDeleteView.as_view(), name='user_gift_delete'),
|
r"^user/(?P<user_id>[0-9]+)/godfathers/tree$",
|
||||||
|
UserGodfathersTreeView.as_view(),
|
||||||
|
name="user_godfathers_tree",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/godfathers/tree/pict$",
|
||||||
|
UserGodfathersTreePictureView.as_view(),
|
||||||
|
name="user_godfathers_tree_pict",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/godfathers/(?P<godfather_id>[0-9]+)/(?P<is_father>(True)|(False))/delete$",
|
||||||
|
DeleteUserGodfathers,
|
||||||
|
name="user_godfathers_delete",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/edit$",
|
||||||
|
UserUpdateProfileView.as_view(),
|
||||||
|
name="user_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/profile_upload$",
|
||||||
|
UserUploadProfilePictView.as_view(),
|
||||||
|
name="user_profile_upload",
|
||||||
|
),
|
||||||
|
url(r"^user/(?P<user_id>[0-9]+)/clubs$", UserClubView.as_view(), name="user_clubs"),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/prefs$",
|
||||||
|
UserPreferencesView.as_view(),
|
||||||
|
name="user_prefs",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/groups$",
|
||||||
|
UserUpdateGroupView.as_view(),
|
||||||
|
name="user_groups",
|
||||||
|
),
|
||||||
|
url(r"^user/tools/$", UserToolsView.as_view(), name="user_tools"),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/account$",
|
||||||
|
UserAccountView.as_view(),
|
||||||
|
name="user_account",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/account/(?P<year>[0-9]+)/(?P<month>[0-9]+)$",
|
||||||
|
UserAccountDetailView.as_view(),
|
||||||
|
name="user_account_detail",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/stats$", UserStatsView.as_view(), name="user_stats"
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/gift/create$",
|
||||||
|
GiftCreateView.as_view(),
|
||||||
|
name="user_gift_create",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^user/(?P<user_id>[0-9]+)/gift/delete/(?P<gift_id>[0-9]+)/$",
|
||||||
|
GiftDeleteView.as_view(),
|
||||||
|
name="user_gift_delete",
|
||||||
|
),
|
||||||
# File views
|
# File views
|
||||||
# url(r'^file/add/(?P<popup>popup)?$', FileCreateView.as_view(), name='file_new'),
|
# url(r'^file/add/(?P<popup>popup)?$', FileCreateView.as_view(), name='file_new'),
|
||||||
url(r'^file/(?P<popup>popup)?$', FileListView.as_view(), name='file_list'),
|
url(r"^file/(?P<popup>popup)?$", FileListView.as_view(), name="file_list"),
|
||||||
url(r'^file/(?P<file_id>[0-9]+)/(?P<popup>popup)?$', FileView.as_view(), name='file_detail'),
|
url(
|
||||||
url(r'^file/(?P<file_id>[0-9]+)/edit/(?P<popup>popup)?$', FileEditView.as_view(), name='file_edit'),
|
r"^file/(?P<file_id>[0-9]+)/(?P<popup>popup)?$",
|
||||||
url(r'^file/(?P<file_id>[0-9]+)/prop/(?P<popup>popup)?$', FileEditPropView.as_view(), name='file_prop'),
|
FileView.as_view(),
|
||||||
url(r'^file/(?P<file_id>[0-9]+)/delete/(?P<popup>popup)?$', FileDeleteView.as_view(), name='file_delete'),
|
name="file_detail",
|
||||||
url(r'^file/moderation$', FileModerationView.as_view(), name='file_moderation'),
|
),
|
||||||
url(r'^file/(?P<file_id>[0-9]+)/moderate$', FileModerateView.as_view(), name='file_moderate'),
|
url(
|
||||||
url(r'^file/(?P<file_id>[0-9]+)/download$', send_file, name='download'),
|
r"^file/(?P<file_id>[0-9]+)/edit/(?P<popup>popup)?$",
|
||||||
|
FileEditView.as_view(),
|
||||||
|
name="file_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^file/(?P<file_id>[0-9]+)/prop/(?P<popup>popup)?$",
|
||||||
|
FileEditPropView.as_view(),
|
||||||
|
name="file_prop",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^file/(?P<file_id>[0-9]+)/delete/(?P<popup>popup)?$",
|
||||||
|
FileDeleteView.as_view(),
|
||||||
|
name="file_delete",
|
||||||
|
),
|
||||||
|
url(r"^file/moderation$", FileModerationView.as_view(), name="file_moderation"),
|
||||||
|
url(
|
||||||
|
r"^file/(?P<file_id>[0-9]+)/moderate$",
|
||||||
|
FileModerateView.as_view(),
|
||||||
|
name="file_moderate",
|
||||||
|
),
|
||||||
|
url(r"^file/(?P<file_id>[0-9]+)/download$", send_file, name="download"),
|
||||||
# Page views
|
# Page views
|
||||||
url(r'^page/$', PageListView.as_view(), name='page_list'),
|
url(r"^page/$", PageListView.as_view(), name="page_list"),
|
||||||
url(r'^page/create$', PageCreateView.as_view(), name='page_new'),
|
url(r"^page/create$", PageCreateView.as_view(), name="page_new"),
|
||||||
url(r'^page/(?P<page_id>[0-9]*)/delete$', PageDeleteView.as_view(), name='page_delete'),
|
url(
|
||||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/edit$', PageEditView.as_view(), name='page_edit'),
|
r"^page/(?P<page_id>[0-9]*)/delete$",
|
||||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/prop$', PagePropView.as_view(), name='page_prop'),
|
PageDeleteView.as_view(),
|
||||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/hist$', PageHistView.as_view(), name='page_hist'),
|
name="page_delete",
|
||||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/rev/(?P<rev>[0-9]+)/', PageRevView.as_view(), name='page_rev'),
|
),
|
||||||
url(r'^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/$', PageView.as_view(), name='page'),
|
url(
|
||||||
|
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/edit$",
|
||||||
|
PageEditView.as_view(),
|
||||||
|
name="page_edit",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/prop$",
|
||||||
|
PagePropView.as_view(),
|
||||||
|
name="page_prop",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/hist$",
|
||||||
|
PageHistView.as_view(),
|
||||||
|
name="page_hist",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/rev/(?P<rev>[0-9]+)/",
|
||||||
|
PageRevView.as_view(),
|
||||||
|
name="page_rev",
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r"^page/(?P<page_name>([/a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])+)/$",
|
||||||
|
PageView.as_view(),
|
||||||
|
name="page",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user