Compare commits

...

143 commits

Author SHA1 Message Date
Martin Pépin
c3d465d75a Clipper ≤ 8 chars in cof.migrations.0008_py3 2017-10-30 15:25:14 +01:00
Martin Pépin
30fcd1217a Copy the kpsul_checkout_data view from master 2017-10-30 14:56:45 +01:00
Martin Pépin
18dc063ae6 Rename / import some forms in kfet.views 2017-10-30 14:06:07 +01:00
Martin Pépin
345fcf8228 Rewrite Account.is_cof using has_perm("cof.member") 2017-10-30 12:49:37 +01:00
Martin Pépin
8895024a23 Fix COF membership unittest
We did not reload the right user from the database
2017-10-30 12:45:04 +01:00
Martin Pépin
14fa40c1ff Fix COF membership test in loadkfetdevdata
cofprofile.is_cof don't exist anymore. The membership test should be performed
like `cofprofile.profile.user.has_perm("cof.member")`
2017-10-30 12:43:47 +01:00
Martin Pépin
5794f0945f rename userN -> cbds_userN in check_olddata 2017-10-30 11:26:05 +01:00
Martin Pepin
cf2a3f64d5 Merge branch 'aureplop/yolo/misc' into 'yolo'
Misc fix for supportBDS

See merge request !271
2017-10-30 09:53:21 +01:00
Aurélien Delobelle
09a88f768d Fix username conflicts with test suite and the…
…check_supportBDS_migrations script.
2017-10-28 18:08:40 +02:00
Aurélien Delobelle
09a96a0375 Fix postgres sequences
When manually assigning a value to AutoField, sequences must be updated
manually.

https://docs.djangoproject.com/en/1.11/ref/databases/#manually-specifying-values-of-auto-incrementing-primary-keys
2017-10-28 17:30:37 +02:00
Aurélien Delobelle
f843c337e3 cof.{settings,asgi} -> gestioCOF.{…} 2017-10-28 17:28:04 +02:00
Martin Pépin
139a2e8293 rename url 'cof-logout' -> 'gestion:logout' 2017-10-27 11:10:01 +02:00
Martin Pépin
d2a0240900 Remove accidentally committed (dummy) secret file 2017-10-27 11:10:01 +02:00
Martin Pépin
34b4a453e6 rename cof -> gestioCOF in some settings options 2017-10-27 10:25:56 +02:00
Martin Pépin
ad60907b67 Change module names in CI config 2017-10-27 10:20:11 +02:00
Martin Pépin
8beff1fd37 Merge branch 'yolo' of git.eleves.ens.fr:cof-geek/gestioCOF into yolo 2017-10-27 10:16:55 +02:00
Martin Pepin
69c994ca5e Merge branch 'aureplop/yolo/fix-duplicate-perms' into 'yolo'
Empêche d'obtenir des permissions dupliquées

See merge request !269
2017-10-27 10:15:57 +02:00
Aurélien Delobelle
772d0b6895 Update kfet migrations history 2017-10-27 03:40:41 +02:00
Aurélien Delobelle
5b378d621a Delete GlobalPermissions model (migrations)
It is an old model which doesn't exist anymore in kfet.models module.

This adds its missing DeleteModel in migrations.
2017-10-27 03:39:51 +02:00
Martin Pepin
dff19199ec Merge branch 'aureplop/yolo/fix-setup-kfet-generic-user' into 'yolo'
Fix setup of the kfet generic user when…

See merge request !268
2017-10-26 17:14:59 +02:00
Aurélien Delobelle
6e28f1260a Fix setup of the kfet generic user when…
…a specific migration is targeted.
2017-10-26 15:44:21 +02:00
Martin Pépin
72691b2d98 Merge branch 'supportBDS' into supportBDS 2017-10-26 15:11:11 +02:00
Martin Pépin
6d99fab45b kfet.signals has moved to kfet.auth.signals 2017-10-26 15:05:59 +02:00
Martin Pépin
d26da74520 Add missing module cof.signals 2017-10-26 14:50:47 +02:00
Martin Pépin
6fc7df8b7b Renamings cofprofile -> profile in the kfet app 2017-10-26 14:07:45 +02:00
Martin Pépin
0eecdb8648 Fix on_delete policy for kfet.Account 2017-10-26 14:07:45 +02:00
Martin Pépin
5ab090fa72 rm cofprofile.num, add PEI / GRATIS 2017-10-26 14:07:45 +02:00
Martin Pépin
704731addd Remove accidentally merged file 2017-10-26 14:07:45 +02:00
Martin Pépin
0162f431d4 Some renamings gestioncof -> cof
The tests fail for an obscure reason:
django.db.utils.OperationalError: no such column: cof_cofprofile.num
2017-10-26 11:38:53 +02:00
Martin Pépin
36827cef6b Hack to handle duplicate permission entries…
ONLY A TEMPORARY FIX
But migrations pass now
2017-10-26 11:16:56 +02:00
Martin Pépin
547d866955 Update the check_migrations_supportBDS script
Doesn't work yet
2017-10-26 11:16:12 +02:00
Martin Pépin
9409b55df5 Merge migrations from master and supportBDS
- Add missing migrations
- Fix dependencies
- rename gestioncof -> cof
2017-10-26 11:06:17 +02:00
Martin Pépin
63963ce1f0 tmp 2017-10-26 09:34:56 +02:00
Martin Pépin
2aa2dafa13 Merge branch 'master' into supportBDS 2017-10-26 09:25:26 +02:00
Martin Pepin
e4d5489549 Merge branch 'aureplop/supportBDS/fix-profile-test' into 'supportBDS'
Fix profile test

See merge request !267
2017-10-26 02:37:50 +02:00
Aurélien Delobelle
0149323b79 Fix profile test 2017-10-26 01:40:17 +02:00
Martin Pepin
c575f75591 Merge branch 'aureplop/supportBDS/migrations' into 'supportBDS'
Clean supportBDS migrations.

See merge request !250
2017-10-26 01:09:07 +02:00
Aurélien Delobelle
5621c6f81e Merge branch 'Kerl/supportBDS/migrations' into 'aureplop/supportBDS/migrations'
Kerl/support bds/migrations

- merge supportBDS
- rajoute des classes `Meta` disparues et autres renommages

See merge request !266
2017-10-26 01:07:00 +02:00
Martin Pépin
e867662996 renamings in the migrationq, missing Meta classes 2017-10-25 23:36:18 +02:00
Martin Pépin
9787770fc6 Merge branch 'supportBDS' into blah 2017-10-25 23:08:38 +02:00
Aurélien Delobelle
c65ddba1d6 Fix and merge kfet migrations 2017-10-12 00:04:06 +02:00
Martin Pepin
8602c2bc77 Merge branch 'aureplop/supportBDS/assoc_perms' into 'supportBDS'
Fix permissions setup of associations.

See merge request !249
2017-09-09 15:58:37 +02:00
Martin Pépin
52aadc636b Add custommail perms to staff groups 2017-09-09 15:55:22 +02:00
Aurélien Delobelle
29d288c567 Fix permissions setup of associations.
- Permissions of 'gestion' app are correctly added to the staff groups
of associations.
- Add tests to ensure staff groups of COF and BDS are correctly setup.
- Shortcut functions are added to retrieve COF and BDS association.
2017-09-05 15:02:33 +02:00
Aurélien Delobelle
5d572b3603 Clean supportBDS migrations.
- Fix some issues and improve efficiency of some RunPython code in
migrations.
- Merge some migrations.
- To simplify, any RunPython don't get a revert function.
2017-09-05 14:41:13 +02:00
Aurélien Delobelle
131c45e1c7 Add tests to check data migrations of supportBDS.
Run 'bash provisioning/check_migrations_supportBDS.sh' from the vagrant
VM.

This will do the following:
- delete the existing database 'cof_gestion', if applicable,
- apply migrations to render the database as pre-supportBDS,
- the last pre-supportBDS migration of 'cof' app creates some instances
using old database schema,
- supportBDS migrations are applied,
- finally, the 'check_olddata' command of 'cof' app ensures data has
been correctly migrated.

This commit should be reverted before reaching production stage.
2017-09-05 14:16:59 +02:00
Aurélien Delobelle
3842b5d160 Merge branch 'Kerl/supportBDS/events' into supportBDS
Move event-related models from 'cof' app to 'gestion' app.

Add 'Association' model to register name, related groups (buro,
members), etc.

Club is now associated with a single Association instance.

Migrations take care of these changes.
2017-08-11 19:59:24 +02:00
Martin Pépin
d4669ec873 Model.natural_key should return a list/tuple 2017-08-11 15:42:33 +01:00
Martin Pépin
714e702af7 Use natural foreign keys to refer associations 2017-08-11 15:34:19 +01:00
Martin Pepin
be87708704 Merge branch 'aureplop/supportBDS/clubs' into 'supportBDS'
Clubs - Partie 1

See merge request !240
2017-08-09 23:24:10 +02:00
Aurélien Delobelle
fe840f2003 Add club view / update profile view
Profile view
- Let the user see his information.
- List the clubs whose he is a member.

Profile edition view
- Renamed from previous "profile" view
- User can now change "occupation" field.

Club detail view
- Informations about a club.
- Accessible by staff members and "respos" of the club.
- List members, with subscription fee (if applicable).

Club admin
- Change memberships of clubs added.
2017-08-09 12:53:44 +02:00
Martin Pépin
10543341b7 The location is not mandatory for an event 2017-08-07 21:17:24 +01:00
Martin Pépin
b1a56b07f3 Bump django-bootstrap-form to 3.3 2017-08-06 20:55:12 +01:00
Martin Pépin
2fb56afa95 typos + renamings + other MR changes 2017-08-06 20:05:07 +01:00
Martin Pépin
e578aef74d Fix circular deps in the migrations 2017-08-06 18:28:07 +01:00
Martin Pépin
894c70149c Add a fixture with 2 events for testing purpose 2017-06-25 20:27:58 +01:00
Martin Pépin
7633ed1dab Typo in requirements.txt: '=' -> '==' 2017-06-25 18:04:30 +01:00
Martin Pépin
7967983b5c More sophisticated admin site for the gestion app
- Nested inlines
- Limiting access to the events : you can only edit/create events linked to
  associations you for which you have the `<assoc>.buro` permission.
2017-06-25 17:57:23 +01:00
Martin Pépin
a9e6ef6c5c Create an Association model
The previous fk and m2m to groups representing associations are replaced by a
proper link to the Association table.
2017-06-24 23:45:04 +01:00
Martin Pépin
b68590ffd7 Set the permissions for buro and members
BDS + COF

The permissions assignation is triggered by the `post_migrate` signal since the
permission table will only be populated after the migrations have been applied.
2017-06-24 23:45:04 +01:00
Martin Pépin
a1ffb630c0 Setup events + add verbosity in gestion.models
- Mark more strings for further translations
    - in verbose names
    - in the __str__ method
- Turn all verbose names into lowercase
- Add more verbose names

- Set an ordering on gestion.EventCommentField

- More database constraints on EventCommentValue
    - `TextField` is not nullable
      (https://docs.djangoproject.com/en/1.11/ref/models/fields/#null)
    - `unique_together` constraint on the two fk
2017-06-24 23:44:58 +01:00
Martin Pépin
cacdde3f87 Remove duplicate locations 2017-05-14 15:47:07 +01:00
Martin Pépin
8a751e5c85 Use a separate models for events' locations 2017-05-14 13:02:06 +01:00
Martin Pépin
18ee33e1e0 Remove the EventTimeSlot model
It was pointless and is replaced by 3 additionnal fields in the `Event`
model: `location`, `start_date`  and `end_date`.
2017-04-05 00:11:24 +01:00
Martin Pépin
7c0bd2a271 Upgrade to Django's actual 1.11 release 2017-04-04 17:29:15 +01:00
Martin Pépin
8a346bf834 Reformat code in 79 columns 2017-04-01 18:29:36 +01:00
Martin Pépin
ec3a9a9658 Remove every occurrence of Event from views, forms, etc
The views have to be re-implemented later
2017-04-01 14:29:02 +01:00
Martin Pépin
745e7a1c0c register the events stuff into the admin site
A simple admin interface which may be modified later
2017-04-01 14:26:05 +01:00
Martin Pépin
c217b549bd Move the events stuff to gestion
- The models are moved to the `gestion` app
- A new field `associations` is added
- The location and datetime fields are removed in favour of a new model
  `EventTimeSlot`
- The old events are migrated to the new app and linked to the
  `cof_buro` association
2017-04-01 14:25:48 +01:00
Aurélien Delobelle
95b96d470f Merge branch 'Kerl/1_11_urls' into 'supportBDS'
Properly include ddt's urls using `include`

See merge request !190
2017-03-26 15:41:12 +02:00
Martin Pepin
33dedc7474 Merge branch 'aureplop/1_11/fix_querysets' into 'supportBDS'
Aureplop/1 11/fix querysets

See merge request !183
2017-03-19 16:16:05 +01:00
Martin Pépin
1a107be4ba Properly include ddt's urls using include 2017-03-18 19:14:51 +00:00
Aurélien Delobelle
e2c4214efc fix history kpsul view 2017-02-25 01:36:53 +01:00
Aurélien Delobelle
a98c6b233e fix checkout data error on k-psul 2017-02-25 01:30:26 +01:00
Qwann
e1713a1d4f Merge branch 'Kerl/datetime_warnings' into supportBDS 2017-02-24 15:02:27 +01:00
Qwann
9c6f5533ec Merge branch 'supportBDS' of git.eleves.ens.fr:cof-geek/gestioCOF into supportBDS 2017-02-23 19:00:58 +01:00
Qwann
486d3c4ced Merge branch 'Kerl/fix_autocomplete' into supportBDS 2017-02-23 18:53:55 +01:00
Martin Pépin
80f1514d39 handle timezones in petits_cours_views 2017-02-23 18:35:38 +01:00
Martin Pépin
1663a03a33 Use timezones everywhere in migrations 2017-02-23 18:33:44 +01:00
Martin Pepin
0e4cfc5121 Merge branch 'Kerl/django111-packages' into 'supportBDS'
Upgrade to Django 1.11

- We upgrade our django packages to 1.11 (beta 1)
- We apply some necessary changes in the settings file
- We prepare to upgrade Django-autocomplete-light
- We upgrade some other packages

See merge request !179
2017-02-23 17:58:28 +01:00
Martin Pépin
856faf2b73 Merge branch 'supportBDS' into Kerl/django111-packages 2017-02-23 17:56:12 +01:00
Martin Pepin
646b213d97 Merge branch 'Kerl/django111-urls' into 'supportBDS'
Write modern-style urls

- Proper use of include
- Defining namespaces (I do not use them for now because many urls are
  going to change)
- Do not try to reverse with old-style references: 'cof.views.XXX'

See merge request !178
2017-02-23 17:32:05 +01:00
Martin Pepin
cc25685aa3 Merge branch 'Kerl/bds_groups' into 'supportBDS'
BDS groups and permissions

Creates groups and permissions for the BDS members and staff.

Fixes #136 

See merge request !176
2017-02-23 12:58:44 +01:00
Martin Pépin
5ce4809f06 Merge branch 'supportBDS' into Kerl/bds_groups 2017-02-23 12:58:10 +01:00
Martin Pepin
4d825b485d Merge branch 'Kerl/clubs_support' into 'supportBDS'
Kerl/clubs support

- Add the club-related models
- Register them into the admin site in order to be able to play with them

See #133 

See merge request !175
2017-02-23 12:46:27 +01:00
Martin Pépin
7988fb24a0 Merge branch 'supportBDS' into Kerl/clubs_support 2017-02-23 12:35:37 +01:00
Martin Pepin
4b4d570e07 Merge branch 'Kerl/fix_generic_team_ath' into 'supportBDS'
Change CofProfile to Profile in kfet/backends.py

- K-Fêt accounts are now linked to profiles
- There is no need to perform the `get_or_create` as long as the profile
  creation has been automated.
- This file is now PEP8 compliant

See merge request !180
2017-02-23 12:31:55 +01:00
Martin Pépin
83e73376ad Change CofProfile to Profile in kfet/backends.py
- K-Fêt accounts are now linked to profiles
- There is no need to perform the `get_or_create` as long as the profile
  creation has been automated.
- This file is now PEP8 compliant
2017-02-23 12:04:33 +01:00
Martin Pépin
7742ad999f Typo in url reverse name
`liste_bda_diff` -> `liste_bdadiff`
2017-02-23 11:05:53 +01:00
Martin Pepin
6444ae3b92 Merge branch 'Kerl/django111-models' into 'supportBDS'
Specify `on_delete`

Two kind of files are affected: 
- Models
- Migrations

You can use the `-Wall` flag to check that the warning `RemovedInDjango20Warning: on_delete…` is not raised:

    python -Wall manage.py runserver 0.0.0.0:8000

See merge request !177
2017-02-23 11:04:26 +01:00
Martin Pépin
213c11721e Prevent petits cours demandes deletion 2017-02-23 11:03:28 +01:00
Martin Pépin
7d1c1fc868 Specify the on_delete strategy
- Remove an absurd debug line in the migration
- Specify the on_delete strategy for the club-related models
2017-02-23 10:56:36 +01:00
Martin Pépin
6c34742cc4 Remove an erroneous RegistrationUserForm
This form appeared twice in `cof/forms.py` and the second occurrence
(which was used by the views) was erroneous.
2017-02-23 10:36:25 +01:00
Martin Pépin
7abcf28666 Move the registration_form template 2017-02-23 10:35:46 +01:00
Martin Pépin
3f52af8ca0 Upgrade requirements
- Upgrade some dependencies
- We do not specify the version for some packages: we use them in a very
  simple way so we may not be affected by upgrades.
2017-02-23 02:03:15 +01:00
Martin Pépin
6bf16441e6 Drop old context processors
Some context processors disappear in Django 1.11, we have to drop them
2017-02-23 02:02:22 +01:00
Martin Pépin
69f748acbd Django1.11-style MiddleWares
The design of middlewares has changed in Django 1.11
2017-02-23 02:00:34 +01:00
Martin Pépin
8b905f66dc Remove dependencies of an old version of dal
Django-autocomplete-light does not support the `modelform_factory`
anymore in recent versions. We are actually using an old version of dal
because of this.

This had to be dropped at some point… So now is a good time
2017-02-23 01:57:50 +01:00
Martin Pépin
e1bab7e4ed Use the AppConfig class 2017-02-23 01:56:59 +01:00
Martin Pépin
68c0ff559d Drop Grappelli
It's ugly and does not really improve the admin site
2017-02-23 01:55:43 +01:00
Martin Pépin
2dcc17298a Use Django 1.11 (beta 1)
Starting to use Django 1.11.
The final version will be released before we push this to production.
2017-02-23 01:55:26 +01:00
Martin Pépin
1aed36330f Write modern-style urls
- Proper use of include
- Defining namespaces (I do not use them for now because many urls are
  going to change)
- Do not try to reverse with old-style references: 'cof.views.XXX'
2017-02-23 01:52:55 +01:00
Martin Pépin
9f401b66e9 Specify the on_delete attribute everywhere
- Models
- Migrations
2017-02-23 01:40:25 +01:00
Martin Pépin
c81b849785 Prevent conflicts in COF perm migration
There may be a conflict during the migration cof 0009 if the permissions
are referenced only by their codename.
2017-02-22 18:21:23 +01:00
Martin Pépin
d36d69238d Add groups and permissions for BDS staff & members 2017-02-22 18:19:49 +01:00
Martin Pépin
f8a8465630 Remove useless imports 2017-02-22 15:23:37 +01:00
Martin Pépin
5632cdaa22 Uses the cof_members groups in kfet's autocomplete
The is_cof attribute cannot be used in database queries anymore
2017-02-22 15:03:34 +01:00
Martin Pépin
68b38228a9 Apply the new db structure to autocomplete in cof
- The autocompletion feature works again
- The template is a bit more readable (indentation)
- The `options` variable in the template is no longer a integer but a
  boolean.
2017-02-22 14:49:34 +01:00
Martin Pépin
1f85f75896 Include the Clubs into the admin site 2017-02-20 01:16:50 +01:00
Martin Pépin
669129e30d Move the club model to the gestion app
- Move the model
- Add some BDS-related fields
- Add an `associations` fields to be able to separate the clubs between
  the different associations using groups
2017-02-20 01:12:06 +01:00
Martin Pépin
859f191894 Simpler admin interface 2017-02-18 19:06:43 +01:00
Martin Pépin
52bdd9824a Merge branch 'supportBDS' of git.eleves.ens.fr:michele.orru/gestioCOF into michele 2017-02-18 13:00:21 +01:00
Martin Pépin
d7a13229ad Fix CI config
- The setting file has moved to `gestioCOF/`
2017-02-13 13:41:34 +01:00
Martin Pépin
7f5132961f Add the cof_members group
GestioCOF cannot run without it.
There is no permission associated to it: this has to been thought about
2017-02-12 19:49:30 +01:00
Martin Pépin
659c6e720a Merge branch 'master' into supportBDS 2017-02-12 19:36:17 +01:00
Martin Pépin
e1a8c0e8dd Add missing files 2017-02-12 19:21:53 +01:00
Martin Pépin
1d7499d3b2 simplify profile edition and test it 2017-02-12 19:21:53 +01:00
Martin Pépin
0420839b20 Test the authentication
- An "outsider" must use django's authentication backend
- A user with a login_clipper should use CAS
2017-02-12 15:38:20 +01:00
Martin Pépin
8b620a5319 PEP8 in gestion/tests.py 2017-02-12 15:38:20 +01:00
Martin Pépin
a28c00e474 Move the auth stuff to gestion/
- The login views are in `gestion/`
- The templates are under `gestion/templates/gestion/`
- `cof/shared.py` moves to `gestion/` and is splitted into 3 files:
    - The auth backends are in `backends.py`.
    - The context_processor is in `context_processor.py`
    - The LOCK/UNLOCK functions remain in `shared.py`
2017-02-12 15:38:14 +01:00
Martin Pépin
50b667993f Merge branch 'master' into supportBDS
- Mise en page
- Cleanup des petits cours
- Utilisation de custommail
- Utilisation du ldap du SPI pour fetch les nouveaux comptes
2017-02-12 04:26:43 +01:00
Michele Orrù
94937fc7cd Add groups cof_members and cof_buro.
- remove is_buro from the database in the same way we did for is_cof
- make a decent migration that *SHOULD* take into account is_cof for old
  databases. note, this has been tested only through unittests.
- make unittests pass again accordin=gly fixing views.

Note: we should make a method for filtering with specific group members,
something like
map(lambda x: x.profile.cof, filter… group…)
2017-02-11 23:05:51 +01:00
Qwann
b5037329dd small fixes + migration
enable admin interface for bds
2017-02-11 20:36:16 +01:00
Qwann
d46ab87e9b Merge branch 'michele.orru/gestioCOF-supportBDS' into supportBDS 2017-02-11 20:17:23 +01:00
Qwann
f53ced6a33 Merge branch 'supportBDS' into michele.orru/gestioCOF-supportBDS 2017-02-11 19:21:23 +01:00
Michele Orrù
ee1f29b17d Make is_cof a property and start developing permissions.
Rmeove the is_cof flag to check permission and start implementing
a group and a permission for the respective cof members.
XXX. note: migrations do NOT add old is_cof members to the new group
(as actually they're just on the tests…)
2017-02-11 18:48:13 +01:00
Qwann
b9ed7320ec Fix user registration 2017-02-11 18:41:47 +01:00
Qwann
fcf392f40d Merge remote-tracking branch 'origin/tmp' into michele.orru/gestioCOF-supportBDS 2017-02-11 18:02:05 +01:00
Martin Pépin
3365d7b9a1 Updates the decorators 2017-02-11 18:00:01 +01:00
Qwann
b16219f8ee fixing profile view 2017-02-11 17:57:37 +01:00
Martin Pépin
6c3e1bd2db Fix the loaddevdata script 2017-02-11 17:18:42 +01:00
Michele Orrù
a2b8dee022 Fix #134.
Fill bds.models with the required fields; add migration scripts, and a stupid
unittests that checks the model really works.
Note: old fields will migrate to datetime.now().
2017-02-11 17:13:48 +01:00
Michele Orrù
f0c3def935 Make the test really works.
This fixes the proble with debug_toolbar,
the fucking toolbar that messes all your tests.
2017-02-11 15:47:31 +01:00
Michele Orrù
376e829502 Reaching a point where I can query /k-fet.
Edit forms and views in app kfet to make the depend on gestion.Profile and not
on cof.CofProfile.
2017-02-11 15:07:45 +01:00
Michele Orrù
f50ef1d51a Merge remote-tracking branch 'origin/supportBDS-fixes1' into supportBDS 2017-02-11 14:26:55 +01:00
Martin Pépin
b639c04549 Fix the registration forms
- The former `RegistrationUserProfileForm` is splitted in two.
- There is a new form: `RegistrationCofProfileForm`
2017-02-11 12:42:36 +01:00
Martin Pépin
b1cf96d0ae Move profile editing to gestion 2017-02-11 01:43:17 +00:00
Michele Orrù
815a5f274c Fix some reviewing considerations.
- appropriate naming for migration
- remove __future__ imports.
- remove "CofProfile" left in kfet/models.py
2017-02-11 00:33:46 +01:00
Michele Orrù
25c3106168 Add some tests about how profiles types should relate to each other. 2017-02-11 00:33:36 +01:00
Michele Orrù
22da04c3e2 s/cofprofile/profile/g into k-fêt.
This commit also restores the only unittest present.
2017-02-11 00:32:58 +01:00
Martin Pépin
58d708b791 Move profile editing to gestion 2017-02-10 23:50:19 +01:00
Ubuntu
f39d1545f0 Generic profiles and migrations.
Creating profiles for BDS, COF and K-Fêt.
2017-02-10 22:12:03 +01:00
Martin Pépin
5aff771d9c Set the new structure of gestioCOF
- `cof` is renamed `gestioCOF`
- `gestioncof` become `cof` (yes it looks pretty stupid but it is not)
- `bds` is created
2017-02-09 21:28:36 +01:00
249 changed files with 3938 additions and 8360 deletions

2
.gitignore vendored
View file

@ -1,7 +1,7 @@
*.pyc *.pyc
*.swp *.swp
*.swo *.swo
cof/settings.py gestioCOF/settings/settings.py
settings.py settings.py
*~ *~
venv/ venv/

View file

@ -4,7 +4,7 @@ services:
variables: variables:
# GestioCOF settings # GestioCOF settings
DJANGO_SETTINGS_MODULE: "cof.settings.prod" DJANGO_SETTINGS_MODULE: "gestioCOF.settings.prod"
DBHOST: "postgres" DBHOST: "postgres"
REDIS_HOST: "redis" REDIS_HOST: "redis"
REDIS_PASSWD: "dummy" REDIS_PASSWD: "dummy"
@ -29,8 +29,8 @@ cache:
before_script: before_script:
- mkdir -p vendor/{python,pip,apt} - mkdir -p vendor/{python,pip,apt}
- apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client
- sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' cof/settings/secret_example.py > cof/settings/secret.py - sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' gestioCOF/settings/secret_example.py > gestioCOF/settings/secret.py
- sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' cof/settings/secret.py - sed -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' gestioCOF/settings/secret.py
# Remove the old test database if it has not been done yet # Remove the old test database if it has not been done yet
- psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB" - psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB"
- pip install --upgrade --cache-dir vendor/pip -t vendor/python -r requirements.txt - pip install --upgrade --cache-dir vendor/pip -t vendor/python -r requirements.txt

View file

@ -111,11 +111,11 @@ Vous pouvez maintenant installer les dépendances Python depuis le fichier
pip install -U pip pip install -U pip
pip install -r requirements-devel.txt pip install -r requirements-devel.txt
Pour terminer, copier le fichier `cof/settings/secret_example.py` vers Pour terminer, copier le fichier `gestioCOF/settings/secret_example.py` vers
`cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique `gestioCOF/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien
pour profiter de façon transparente des mises à jour du fichier: symbolique pour profiter de façon transparente des mises à jour du fichier:
ln -s secret_example.py cof/settings/secret.py ln -s secret_example.py gestioCOF/settings/secret.py
#### Fin d'installation #### Fin d'installation

View file

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import autocomplete_light
from datetime import timedelta from datetime import timedelta
from custommail.shortcuts import send_mass_custom_mail from custommail.shortcuts import send_mass_custom_mail
@ -180,8 +179,6 @@ class AttributionAdmin(ReadOnlyMixin, admin.ModelAdmin):
class ChoixSpectacleAdmin(admin.ModelAdmin): class ChoixSpectacleAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[])
def tirage(self, obj): def tirage(self, obj):
return obj.participant.tirage return obj.participant.tirage
list_display = ("participant", "tirage", "spectacle", "priority", list_display = ("participant", "tirage", "spectacle", "priority",

6
bda/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class BdAConfig(AppConfig):
name = "bda"
verbose_name = "Gestion des tirages du BdA"

View file

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import autocomplete_light
from bda.models import Participant, Spectacle
autocomplete_light.register(
Participant, search_fields=('user__username', 'user__first_name',
'user__last_name'),
autocomplete_js_attributes={'placeholder': 'participant...'})
autocomplete_light.register(
Spectacle, search_fields=('title', ),
autocomplete_js_attributes={'placeholder': 'spectacle...'})

View file

@ -6,9 +6,9 @@ import os
import random import random
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.models import User from django.contrib.auth.models import Group
from gestioncof.management.base import MyBaseCommand from cof.management.base import MyBaseCommand
from bda.models import Tirage, Spectacle, Salle, Participant, ChoixSpectacle from bda.models import Tirage, Spectacle, Salle, Participant, ChoixSpectacle
from bda.views import do_tirage from bda.views import do_tirage
@ -77,7 +77,8 @@ class Command(MyBaseCommand):
self.stdout.write("Inscription des utilisateurs aux tirages") self.stdout.write("Inscription des utilisateurs aux tirages")
ChoixSpectacle.objects.all().delete() ChoixSpectacle.objects.all().delete()
choices = [] choices = []
for user in User.objects.filter(profile__is_cof=True): cof_members = Group.objects.get(name="cof_members")
for user in cof_members.user_set.all():
for tirage in tirages: for tirage in tirages:
part, _ = Participant.objects.get_or_create( part, _ = Participant.objects.get_or_create(
user=user, user=user,

View file

@ -59,7 +59,9 @@ class Migration(migrations.Migration):
('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)), ('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)),
('slots', models.IntegerField(verbose_name=b'Places')), ('slots', models.IntegerField(verbose_name=b'Places')),
('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')), ('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')),
('location', models.ForeignKey(to='bda.Salle')), ('location', models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Salle')),
], ],
options={ options={
'ordering': ('priority', 'date', 'title'), 'ordering': ('priority', 'date', 'title'),
@ -79,27 +81,39 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='participant', model_name='participant',
name='user', name='user',
field=models.OneToOneField(to=settings.AUTH_USER_MODEL), field=models.OneToOneField(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='choixspectacle', model_name='choixspectacle',
name='participant', name='participant',
field=models.ForeignKey(to='bda.Participant'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant'),
), ),
migrations.AddField( migrations.AddField(
model_name='choixspectacle', model_name='choixspectacle',
name='spectacle', name='spectacle',
field=models.ForeignKey(related_name='participants', to='bda.Spectacle'), field=models.ForeignKey(
on_delete=models.CASCADE,
related_name='participants',
to='bda.Spectacle'),
), ),
migrations.AddField( migrations.AddField(
model_name='attribution', model_name='attribution',
name='participant', name='participant',
field=models.ForeignKey(to='bda.Participant'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant'),
), ),
migrations.AddField( migrations.AddField(
model_name='attribution', model_name='attribution',
name='spectacle', name='spectacle',
field=models.ForeignKey(related_name='attribues', to='bda.Spectacle'), field=models.ForeignKey(
related_name='attribues',
on_delete=models.CASCADE,
to='bda.Spectacle'),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='choixspectacle', name='choixspectacle',

View file

@ -55,7 +55,9 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='participant', model_name='participant',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
# Create fields `spectacle` for `Participant` and `Spectacle` models. # Create fields `spectacle` for `Participant` and `Spectacle` models.
# These fields are not nullable, but we first create them as nullable # These fields are not nullable, but we first create them as nullable
@ -63,12 +65,20 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='participant', model_name='participant',
name='tirage', name='tirage',
field=models.ForeignKey(to='bda.Tirage', null=True), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Tirage',
null=True
),
), ),
migrations.AddField( migrations.AddField(
model_name='spectacle', model_name='spectacle',
name='tirage', name='tirage',
field=models.ForeignKey(to='bda.Tirage', null=True), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Tirage',
null=True
),
), ),
migrations.RunPython(fill_tirage_fields, migrations.RunPython.noop), migrations.RunPython(fill_tirage_fields, migrations.RunPython.noop),
migrations.AlterField( migrations.AlterField(

View file

@ -72,8 +72,11 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='spectacle', model_name='spectacle',
name='category', name='category',
field=models.ForeignKey(blank=True, to='bda.CategorieSpectacle', field=models.ForeignKey(
null=True), on_delete=models.CASCADE,
blank=True,
to='bda.CategorieSpectacle',
null=True),
), ),
migrations.AddField( migrations.AddField(
model_name='spectacle', model_name='spectacle',
@ -84,6 +87,8 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='quote', model_name='quote',
name='spectacle', name='spectacle',
field=models.ForeignKey(to='bda.Spectacle'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Spectacle'),
), ),
] ]

View file

@ -46,21 +46,28 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='spectaclerevente', model_name='spectaclerevente',
name='attribution', name='attribution',
field=models.OneToOneField(to='bda.Attribution', field=models.OneToOneField(
related_name='revente'), to='bda.Attribution',
on_delete=models.CASCADE,
related_name='revente'),
), ),
migrations.AddField( migrations.AddField(
model_name='spectaclerevente', model_name='spectaclerevente',
name='seller', name='seller',
field=models.ForeignKey(to='bda.Participant', field=models.ForeignKey(
verbose_name='Vendeur', on_delete=models.CASCADE,
related_name='original_shows'), to='bda.Participant',
verbose_name='Vendeur',
related_name='original_shows'),
), ),
migrations.AddField( migrations.AddField(
model_name='spectaclerevente', model_name='spectaclerevente',
name='soldTo', name='soldTo',
field=models.ForeignKey(to='bda.Participant', field=models.ForeignKey(
verbose_name='Vendue à', null=True, on_delete=models.CASCADE,
blank=True), to='bda.Participant',
verbose_name='Vendue à',
null=True,
blank=True),
), ),
] ]

View file

@ -59,9 +59,14 @@ class CategorieSpectacle(models.Model):
class Spectacle(models.Model): class Spectacle(models.Model):
title = models.CharField("Titre", max_length=300) title = models.CharField("Titre", max_length=300)
category = models.ForeignKey(CategorieSpectacle, blank=True, null=True) category = models.ForeignKey(
CategorieSpectacle,
on_delete=models.CASCADE,
blank=True,
null=True
)
date = models.DateTimeField("Date & heure") date = models.DateTimeField("Date & heure")
location = models.ForeignKey(Salle) location = models.ForeignKey(Salle, on_delete=models.CASCADE)
vips = models.TextField('Personnalités', blank=True) vips = models.TextField('Personnalités', blank=True)
description = models.TextField("Description", blank=True) description = models.TextField("Description", blank=True)
slots_description = models.TextField("Description des places", blank=True) slots_description = models.TextField("Description des places", blank=True)
@ -71,7 +76,7 @@ class Spectacle(models.Model):
max_length=500) max_length=500)
price = models.FloatField("Prix d'une place") price = models.FloatField("Prix d'une place")
slots = models.IntegerField("Places") slots = models.IntegerField("Places")
tirage = models.ForeignKey(Tirage) tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE)
listing = models.BooleanField("Les places sont sur listing") listing = models.BooleanField("Les places sont sur listing")
rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True, rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True,
null=True) null=True)
@ -135,7 +140,7 @@ class Spectacle(models.Model):
class Quote(models.Model): class Quote(models.Model):
spectacle = models.ForeignKey(Spectacle) spectacle = models.ForeignKey(Spectacle, on_delete=models.CASCADE)
text = models.TextField('Citation') text = models.TextField('Citation')
author = models.CharField('Auteur', max_length=200) author = models.CharField('Auteur', max_length=200)
@ -149,7 +154,7 @@ PAYMENT_TYPES = (
class Participant(models.Model): class Participant(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User, on_delete=models.CASCADE)
choices = models.ManyToManyField(Spectacle, choices = models.ManyToManyField(Spectacle,
through="ChoixSpectacle", through="ChoixSpectacle",
related_name="chosen_by") related_name="chosen_by")
@ -160,7 +165,7 @@ class Participant(models.Model):
paymenttype = models.CharField("Moyen de paiement", paymenttype = models.CharField("Moyen de paiement",
max_length=6, choices=PAYMENT_TYPES, max_length=6, choices=PAYMENT_TYPES,
blank=True) blank=True)
tirage = models.ForeignKey(Tirage) tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE)
choicesrevente = models.ManyToManyField(Spectacle, choicesrevente = models.ManyToManyField(Spectacle,
related_name="subscribed", related_name="subscribed",
blank=True) blank=True)
@ -176,8 +181,15 @@ DOUBLE_CHOICES = (
class ChoixSpectacle(models.Model): class ChoixSpectacle(models.Model):
participant = models.ForeignKey(Participant) participant = models.ForeignKey(
spectacle = models.ForeignKey(Spectacle, related_name="participants") Participant,
on_delete=models.CASCADE
)
spectacle = models.ForeignKey(
Spectacle,
on_delete=models.CASCADE,
related_name="participants"
)
priority = models.PositiveIntegerField("Priorité") priority = models.PositiveIntegerField("Priorité")
double_choice = models.CharField("Nombre de places", double_choice = models.CharField("Nombre de places",
default="1", choices=DOUBLE_CHOICES, default="1", choices=DOUBLE_CHOICES,
@ -204,8 +216,15 @@ class ChoixSpectacle(models.Model):
class Attribution(models.Model): class Attribution(models.Model):
participant = models.ForeignKey(Participant) participant = models.ForeignKey(
spectacle = models.ForeignKey(Spectacle, related_name="attribues") Participant,
on_delete=models.CASCADE
)
spectacle = models.ForeignKey(
Spectacle,
on_delete=models.CASCADE,
related_name="attribues"
)
given = models.BooleanField("Donnée", default=False) given = models.BooleanField("Donnée", default=False)
def __str__(self): def __str__(self):
@ -214,19 +233,29 @@ class Attribution(models.Model):
class SpectacleRevente(models.Model): class SpectacleRevente(models.Model):
attribution = models.OneToOneField(Attribution, attribution = models.OneToOneField(
related_name="revente") Attribution,
on_delete=models.CASCADE,
related_name="revente"
)
date = models.DateTimeField("Date de mise en vente", date = models.DateTimeField("Date de mise en vente",
default=timezone.now) default=timezone.now)
answered_mail = models.ManyToManyField(Participant, answered_mail = models.ManyToManyField(Participant,
related_name="wanted", related_name="wanted",
blank=True) blank=True)
seller = models.ForeignKey(Participant, seller = models.ForeignKey(
related_name="original_shows", Participant,
verbose_name="Vendeur") on_delete=models.CASCADE,
soldTo = models.ForeignKey(Participant, blank=True, null=True, related_name="original_shows",
verbose_name="Vendue à") verbose_name="Vendeur"
)
soldTo = models.ForeignKey(
Participant,
on_delete=models.CASCADE,
blank=True,
null=True,
verbose_name="Vendue à"
)
notif_sent = models.BooleanField("Notification envoyée", notif_sent = models.BooleanField("Notification envoyée",
default=False) default=False)
tirage_done = models.BooleanField("Tirage effectué", tirage_done = models.BooleanField("Tirage effectué",

View file

@ -16,7 +16,7 @@
<h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4> <h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4>
<br/> <br/>
<p>Ne manque pas un spectacle avec le <p>Ne manque pas un spectacle avec le
<a href="{% url "gestioncof.views.calendar" %}">calendrier <a href="{% url "calendar" %}">calendrier
automatique&#8239;!</a></p> automatique&#8239;!</a></p>
{% else %} {% else %}
<h3>Vous n'avez aucune place :(</h3> <h3>Vous n'avez aucune place :(</h3>

View file

@ -5,7 +5,7 @@ from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf.urls import url from django.conf.urls import url
from gestioncof.decorators import buro_required from cof.decorators import buro_required
from bda.views import SpectacleListView from bda.views import SpectacleListView
from bda import views from bda import views

View file

@ -1,34 +1,36 @@
# -*- coding: utf-8 -*-
from collections import defaultdict
import random import random
import hashlib import hashlib
import time import time
import json import json
from datetime import timedelta
from collections import defaultdict
from custommail.shortcuts import send_mass_custom_mail, send_custom_mail from custommail.shortcuts import send_mass_custom_mail, send_custom_mail
from custommail.models import CustomMail from custommail.models import CustomMail
from django.shortcuts import render, get_object_or_404 from datetime import timedelta
from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.db import transaction from django.contrib.auth.decorators import login_required
from django.core import serializers from django.core import serializers
from django.core.urlresolvers import reverse
from django.db import transaction
from django.db.models import Count, Q, Prefetch from django.db.models import Count, Q, Prefetch
from django.forms.models import inlineformset_factory from django.forms.models import inlineformset_factory
from django.http import ( from django.http import (
HttpResponseBadRequest, HttpResponseRedirect, JsonResponse HttpResponseBadRequest, HttpResponseRedirect, JsonResponse
) )
from django.core.urlresolvers import reverse from django.shortcuts import render, get_object_or_404
from django.conf import settings
from django.utils import timezone, formats from django.utils import timezone, formats
from django.views.generic.list import ListView from django.views.generic.list import ListView
from gestioncof.decorators import cof_required, buro_required
from bda.models import ( from cof.decorators import cof_required, buro_required
Spectacle, Participant, ChoixSpectacle, Attribution, Tirage,
SpectacleRevente, Salle, CategorieSpectacle from .models import (
Attribution, CategorieSpectacle, ChoixSpectacle, Participant, Salle,
Spectacle, SpectacleRevente, Tirage
) )
from bda.algorithm import Algorithm from .algorithm import Algorithm
from bda.forms import ( from .forms import (
TokenForm, ResellForm, AnnulForm, InscriptionReventeForm, SoldForm, TokenForm, ResellForm, AnnulForm, InscriptionReventeForm, SoldForm,
InscriptionInlineFormSet, InscriptionInlineFormSet,
) )

4
bds/admin.py Normal file
View file

@ -0,0 +1,4 @@
from django.contrib import admin
from .models import BdsProfile
admin.site.register(BdsProfile)

22
bds/apps.py Normal file
View file

@ -0,0 +1,22 @@
from django.apps import AppConfig
from django.db.models.signals import post_migrate
from gestion.apps import setup_assoc_perms
class BDSConfig(AppConfig):
name = "bds"
verbose_name = "Application de gestion du BDS"
def setup_bds_perms(sender, apps, **kwargs):
from bds.models import get_bds_assoc
setup_assoc_perms(
apps, get_bds_assoc,
buro_of_apps=['gestion', 'bds'],
perms=["custommail.add_custommail", "custommail.change_custommail"]
)
# Setup permissions of defaults groups of BDS association after Permission
# instances have been created, i.e. after applying migrations.
post_migrate.connect(setup_bds_perms)

View file

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import bds.models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0002_create_cof_bds'),
]
operations = [
migrations.CreateModel(
name='BdsProfile',
fields=[
('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
('ASPSL_number', models.CharField(null=True, blank=True, verbose_name='Numéro AS PSL', max_length=50)),
('FFSU_number', models.CharField(null=True, blank=True, verbose_name='Numéro FFSU', max_length=50)),
('have_certificate', models.BooleanField(verbose_name='Certificat médical', default=False)),
('certificate_file', models.FileField(blank=True, upload_to=bds.models.BdsProfile.issue_file_name, verbose_name='Fichier de certificat médical')),
('cotisation_period', models.CharField(choices=[('ANN', 'Année'), ('SE1', 'Premier semestre'), ('SE2', 'Deuxième semestre')], verbose_name='Inscription', max_length=3, default='ANN')),
('registration_date', models.DateField(verbose_name="Date d'inscription", auto_now_add=True)),
('payment_method', models.CharField(choices=[('CASH', 'Liquide'), ('BANK', 'Transfer bancaire'), ('CHEQUE', 'Cheque'), ('OTHER', 'Autre')], verbose_name='Methode de paiement', max_length=6, default='CASH')),
('profile', models.OneToOneField(
related_name='bds',
on_delete=models.CASCADE,
to='gestion.Profile')),
],
options={
'permissions': [
('member', 'Is a BDS member'),
('buro', 'Is part of the BDS staff')
],
'verbose_name': 'Profil BDS',
'verbose_name_plural': 'Profils BDS'
},
),
]

69
bds/models.py Normal file
View file

@ -0,0 +1,69 @@
import os.path
from django.utils import timezone
from django.db import models
from gestion.models import Association, Profile
def get_bds_assoc():
return Association.objects.get(name='BDS')
class BdsProfile(models.Model):
profile = models.OneToOneField(Profile,
related_name='bds',
on_delete=models.CASCADE)
def issue_file_name(sportif, filename):
fn, extension = os.path.splitext(filename)
year = timezone.now().year
return "certifs/{!s}-{:d}{:s}".format(sportif, year, extension)
COTIZ_DURATION_CHOICES = (
('ANN', 'Année'),
('SE1', 'Premier semestre'),
('SE2', 'Deuxième semestre'),
)
PAYMENT_METHOD_CHOICES = (
('CASH', 'Liquide'),
('BANK', 'Transfer bancaire'),
('CHEQUE', 'Cheque'),
('OTHER', 'Autre'),
)
ASPSL_number = models.CharField("Numéro AS PSL",
max_length=50,
blank=True,
null=True)
FFSU_number = models.CharField("Numéro FFSU",
max_length=50,
blank=True,
null=True)
have_certificate = models.BooleanField("Certificat médical",
default=False)
certificate_file = models.FileField("Fichier de certificat médical",
upload_to=issue_file_name,
blank=True)
cotisation_period = models.CharField("Inscription",
default="ANN",
choices=COTIZ_DURATION_CHOICES,
max_length=3)
registration_date = models.DateField(auto_now_add=True,
verbose_name="Date d'inscription")
payment_method = models.CharField('Methode de paiement',
default='CASH',
choices=PAYMENT_METHOD_CHOICES,
max_length=6)
class Meta:
verbose_name = "Profil BDS"
verbose_name_plural = "Profils BDS"
permissions = [
("member", "Is a BDS member"),
("buro", "Is part of the BDS staff")
]

12
bds/tests.py Normal file
View file

@ -0,0 +1,12 @@
from django.test import TestCase
from gestion.tests import create_profile
from .models import BdsProfile
class TestBdsProfile(TestCase):
def test_profile(self):
# each bdspofile should have an associated profile
p = create_profile('foo')
bdsp = BdsProfile.objects.create(profile=p)
self.assertEqual(p.bds, bdsp)

3
bds/views.py Normal file
View file

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

103
cof/admin.py Normal file
View file

@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
import django.utils.six as six
from .petits_cours_models import PetitCoursDemande, \
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
PetitCoursAttributionCounter
from .models import (
SurveyQuestionAnswer, SurveyQuestion, CofProfile, Survey
)
def add_link_field(target_model='', field='', link_text=six.text_type,
desc_text=six.text_type):
def add_link(cls):
reverse_name = target_model or cls.model.__name__.lower()
def link(self, instance):
app_name = instance._meta.app_label
reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
link_obj = getattr(instance, field, None) or instance
if not link_obj.id:
return ""
url = reverse(reverse_path, args=(link_obj.id,))
return mark_safe("<a href='%s'>%s</a>"
% (url, link_text(link_obj)))
link.allow_tags = True
link.short_description = desc_text(reverse_name + ' link')
cls.link = link
cls.readonly_fields =\
list(getattr(cls, 'readonly_fields', [])) + ['link']
return cls
return add_link
class SurveyQuestionAnswerInline(admin.TabularInline):
model = SurveyQuestionAnswer
@add_link_field(desc_text=lambda x: "Réponses",
link_text=lambda x: "Éditer les réponses")
class SurveyQuestionInline(admin.TabularInline):
model = SurveyQuestion
class SurveyQuestionAdmin(admin.ModelAdmin):
search_fields = ('survey__title', 'answer')
inlines = [
SurveyQuestionAnswerInline,
]
class SurveyAdmin(admin.ModelAdmin):
search_fields = ('title', 'details')
inlines = [
SurveyQuestionInline,
]
class PetitCoursAbilityAdmin(admin.ModelAdmin):
list_display = ('user', 'matiere', 'niveau', 'agrege')
search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'matiere__name', 'niveau')
list_filter = ('matiere', 'niveau', 'agrege')
class PetitCoursAttributionAdmin(admin.ModelAdmin):
list_display = ('user', 'demande', 'matiere', 'rank', )
search_fields = ('user__username', 'matiere__name')
class PetitCoursAttributionCounterAdmin(admin.ModelAdmin):
list_display = ('user', 'matiere', 'count', )
list_filter = ('matiere',)
search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'matiere__name')
actions = ['reset', ]
actions_on_bottom = True
def reset(self, request, queryset):
queryset.update(count=0)
reset.short_description = "Remise à zéro du compteur"
class PetitCoursDemandeAdmin(admin.ModelAdmin):
list_display = ('name', 'email', 'agrege_requis', 'niveau', 'created',
'traitee', 'processed')
list_filter = ('traitee', 'niveau')
search_fields = ('name', 'email', 'phone', 'lieu', 'remarques')
admin.site.register(Survey, SurveyAdmin)
admin.site.register(SurveyQuestion, SurveyQuestionAdmin)
admin.site.register(CofProfile)
admin.site.register(PetitCoursSubject)
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
admin.site.register(PetitCoursAttributionCounter,
PetitCoursAttributionCounterAdmin)
admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin)

22
cof/apps.py Normal file
View file

@ -0,0 +1,22 @@
from django.apps import AppConfig
from django.db.models.signals import post_migrate
from gestion.apps import setup_assoc_perms
class COFConfig(AppConfig):
name = "cof"
verbose_name = "Application de gestion du COF"
def setup_cof_perms(sender, apps, **kwargs):
from cof.models import get_cof_assoc
setup_assoc_perms(
apps, get_cof_assoc,
buro_of_apps=['gestion', 'cof'],
perms=["custommail.add_custommail", "custommail.change_custommail"]
)
# Setup permissions of defaults groups of BDS association after Permission
# instances have been created, i.e. after applying migrations.
post_migrate.connect(setup_cof_perms)

View file

@ -1,16 +1,12 @@
# -*- coding: utf-8 -*-
from ldap3 import Connection from ldap3 import Connection
from django import shortcuts from django import shortcuts
from django.http import Http404 from django.http import Http404
from django.db.models import Q from django.db.models import Q
from django.contrib.auth.models import User from django.contrib.auth.models import User, Group
from .decorators import buro_required
from django.conf import settings from django.conf import settings
from gestioncof.models import CofProfile
from gestioncof.decorators import buro_required
class Clipper(object): class Clipper(object):
def __init__(self, clipper, fullname): def __init__(self, clipper, fullname):
@ -27,22 +23,21 @@ def autocomplete(request):
if "q" not in request.GET: if "q" not in request.GET:
raise Http404 raise Http404
q = request.GET['q'] q = request.GET['q']
data = { data = {'q': q}
'q': q, cof_members = Group.objects.get(name="cof_members")
}
queries = {} queries = {}
bits = q.split() bits = q.split()
# Fetching data from User and CofProfile tables # Fetching data from User and Profile tables
queries['members'] = CofProfile.objects.filter(is_cof=True) queries['members'] = User.objects.filter(groups=cof_members)
queries['users'] = User.objects.filter(profile__is_cof=False) queries['users'] = User.objects.exclude(groups=cof_members)
for bit in bits: for bit in bits:
queries['members'] = queries['members'].filter( queries['members'] = queries['members'].filter(
Q(user__first_name__icontains=bit) Q(first_name__icontains=bit)
| Q(user__last_name__icontains=bit) | Q(last_name__icontains=bit)
| Q(user__username__icontains=bit) | Q(username__icontains=bit)
| Q(login_clipper__icontains=bit)) | Q(profile__login_clipper__icontains=bit))
queries['users'] = queries['users'].filter( queries['users'] = queries['users'].filter(
Q(first_name__icontains=bit) Q(first_name__icontains=bit)
| Q(last_name__icontains=bit) | Q(last_name__icontains=bit)
@ -52,7 +47,8 @@ def autocomplete(request):
# Clearing redundancies # Clearing redundancies
usernames = ( usernames = (
set(queries['members'].values_list('login_clipper', flat='True')) set(queries['members'].values_list('profile__login_clipper',
flat='True'))
| set(queries['users'].values_list('profile__login_clipper', | set(queries['users'].values_list('profile__login_clipper',
flat='True')) flat='True'))
) )
@ -83,6 +79,6 @@ def autocomplete(request):
# Resulting data # Resulting data
data.update(queries) data.update(queries)
data['options'] = sum(len(query) for query in queries) data['options'] = any(bool(query) for query in queries.values())
return shortcuts.render(request, "autocomplete_user.html", data) return shortcuts.render(request, "cof/autocomplete_user.html", data)

8
cof/decorators.py Normal file
View file

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
from django.contrib.auth.decorators import permission_required
cof_required = permission_required('cof.member')
cof_required_customdenied = permission_required('cof.member',
login_url="cof-denied")
buro_required = permission_required('cof.buro')

View file

@ -6,7 +6,7 @@
"survey_open": true, "survey_open": true,
"title": "Sort du barde" "title": "Sort du barde"
}, },
"model": "gestioncof.survey", "model": "cof.survey",
"pk": 1 "pk": 1
}, },
{ {
@ -15,7 +15,7 @@
"survey": 1, "survey": 1,
"multi_answers": true "multi_answers": true
}, },
"model": "gestioncof.surveyquestion", "model": "cof.surveyquestion",
"pk": 1 "pk": 1
}, },
{ {
@ -24,7 +24,7 @@
"survey": 1, "survey": 1,
"multi_answers": false "multi_answers": false
}, },
"model": "gestioncof.surveyquestion", "model": "cof.surveyquestion",
"pk": 2 "pk": 2
}, },
{ {
@ -32,7 +32,7 @@
"answer": "On l'ernestise", "answer": "On l'ernestise",
"survey_question": 1 "survey_question": 1
}, },
"model": "gestioncof.surveyquestionanswer", "model": "cof.surveyquestionanswer",
"pk": 1 "pk": 1
}, },
{ {
@ -40,7 +40,7 @@
"answer": "On ligote", "answer": "On ligote",
"survey_question": 1 "survey_question": 1
}, },
"model": "gestioncof.surveyquestionanswer", "model": "cof.surveyquestionanswer",
"pk": 2 "pk": 2
}, },
{ {
@ -48,7 +48,7 @@
"answer": "On le prive de banquet", "answer": "On le prive de banquet",
"survey_question": 1 "survey_question": 1
}, },
"model": "gestioncof.surveyquestionanswer", "model": "cof.surveyquestionanswer",
"pk": 3 "pk": 3
}, },
{ {
@ -56,7 +56,7 @@
"answer": "Oui", "answer": "Oui",
"survey_question": 2 "survey_question": 2
}, },
"model": "gestioncof.surveyquestionanswer", "model": "cof.surveyquestionanswer",
"pk": 4 "pk": 4
}, },
{ {
@ -64,92 +64,35 @@
"answer": "Non", "answer": "Non",
"survey_question": 2 "survey_question": 2
}, },
"model": "gestioncof.surveyquestionanswer", "model": "cof.surveyquestionanswer",
"pk": 5 "pk": 5
}, },
{
"fields": {
"old": false,
"description": "On va casser du romain.",
"end_date": "2016-09-12T00:00:00Z",
"title": "Bataille de Gergovie",
"image": "",
"location": "Gergovie",
"registration_open": true,
"start_date": "2016-09-09T00:00:00Z"
},
"model": "gestioncof.event",
"pk": 1
},
{
"fields": {
"default": "",
"event": 1,
"fieldtype": "text",
"name": "Commentaires"
},
"model": "gestioncof.eventcommentfield",
"pk": 1
},
{
"fields": {
"multi_choices": true,
"event": 1,
"name": "Potion magique"
},
"model": "gestioncof.eventoption",
"pk": 1
},
{
"fields": {
"event_option": 1,
"value": "Je suis alergique"
},
"model": "gestioncof.eventoptionchoice",
"pk": 1
},
{
"fields": {
"event_option": 1,
"value": "J'en veux"
},
"model": "gestioncof.eventoptionchoice",
"pk": 2
},
{
"fields": {
"event_option": 1,
"value": "Je suis tomb\u00e9 dans la marmite quand j'\u00e9tais petit"
},
"model": "gestioncof.eventoptionchoice",
"pk": 3
},
{ {
"fields": { "fields": {
"name": "Bagarre" "name": "Bagarre"
}, },
"model": "gestioncof.petitcourssubject", "model": "cof.petitcourssubject",
"pk": 1 "pk": 1
}, },
{ {
"fields": { "fields": {
"name": "Lancer de menhir" "name": "Lancer de menhir"
}, },
"model": "gestioncof.petitcourssubject", "model": "cof.petitcourssubject",
"pk": 2 "pk": 2
}, },
{ {
"fields": { "fields": {
"name": "Pr\u00e9paration de potions" "name": "Pr\u00e9paration de potions"
}, },
"model": "gestioncof.petitcourssubject", "model": "cof.petitcourssubject",
"pk": 3 "pk": 3
}, },
{ {
"fields": { "fields": {
"name": "Chant" "name": "Chant"
}, },
"model": "gestioncof.petitcourssubject", "model": "cof.petitcourssubject",
"pk": 4 "pk": 4
}, },
{ {
@ -171,7 +114,7 @@
"email": "jules.cesar@polytechnique.edu", "email": "jules.cesar@polytechnique.edu",
"processed": null "processed": null
}, },
"model": "gestioncof.petitcoursdemande", "model": "cof.petitcoursdemande",
"pk": 1 "pk": 1
}, },
{ {
@ -193,7 +136,7 @@
"email": "jules.cesar@polytechnique.edu", "email": "jules.cesar@polytechnique.edu",
"processed": null "processed": null
}, },
"model": "gestioncof.petitcoursdemande", "model": "cof.petitcoursdemande",
"pk": 2 "pk": 2
} }
] ]

View file

@ -1,59 +1,17 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.formsets import BaseFormSet, formset_factory
from djconfig.forms import ConfigForm from djconfig.forms import ConfigForm
from gestioncof.models import CofProfile, EventCommentValue, \ from django import forms
CalendarSubscription, Club from django.contrib.auth.models import User
from gestioncof.widgets import TriStateCheckbox from django.forms.formsets import BaseFormSet, formset_factory
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.utils.translation import ugettext_lazy as _
from bda.models import Spectacle from bda.models import Spectacle
from gestion.models import Profile, EventCommentValue
class EventForm(forms.Form): from .models import CofProfile, CalendarSubscription
def __init__(self, *args, **kwargs): from .widgets import TriStateCheckbox
event = kwargs.pop("event")
self.event = event
current_choices = kwargs.pop("current_choices", None)
super(EventForm, self).__init__(*args, **kwargs)
choices = {}
if current_choices:
for choice in current_choices.all():
if choice.event_option.id not in choices:
choices[choice.event_option.id] = [choice.id]
else:
choices[choice.event_option.id].append(choice.id)
all_choices = choices
for option in event.options.all():
choices = [(choice.id, choice.value)
for choice in option.choices.all()]
if option.multi_choices:
initial = [] if option.id not in all_choices \
else all_choices[option.id]
field = forms.MultipleChoiceField(
label=option.name,
choices=choices,
widget=CheckboxSelectMultiple,
required=False,
initial=initial)
else:
initial = None if option.id not in all_choices \
else all_choices[option.id][0]
field = forms.ChoiceField(label=option.name,
choices=choices,
widget=RadioSelect,
required=False,
initial=initial)
field.option_id = option.id
self.fields["option_%d" % option.id] = field
def choices(self):
for name, value in self.cleaned_data.items():
if name.startswith('option_'):
yield (self.fields[name].option_id, value)
class SurveyForm(forms.Form): class SurveyForm(forms.Form):
@ -170,27 +128,6 @@ class EventStatusFilterForm(forms.Form):
yield ("has_paid", None, value) yield ("has_paid", None, value)
class UserProfileForm(forms.ModelForm):
first_name = forms.CharField(label=_('Prénom'), max_length=30)
last_name = forms.CharField(label=_('Nom'), max_length=30)
def __init__(self, *args, **kw):
super(UserProfileForm, self).__init__(*args, **kw)
self.fields['first_name'].initial = self.instance.user.first_name
self.fields['last_name'].initial = self.instance.user.last_name
def save(self, *args, **kw):
super(UserProfileForm, self).save(*args, **kw)
self.instance.user.first_name = self.cleaned_data.get('first_name')
self.instance.user.last_name = self.cleaned_data.get('last_name')
self.instance.user.save()
class Meta:
model = CofProfile
fields = ["first_name", "last_name", "phone", "mailing_cof",
"mailing_bda", "mailing_bda_revente"]
class RegistrationUserForm(forms.ModelForm): class RegistrationUserForm(forms.ModelForm):
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
super(RegistrationUserForm, self).__init__(*args, **kw) super(RegistrationUserForm, self).__init__(*args, **kw)
@ -198,7 +135,7 @@ class RegistrationUserForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
fields = ("username", "first_name", "last_name", "email") fields = ["username", "first_name", "last_name", "email"]
class RegistrationPassUserForm(RegistrationUserForm): class RegistrationPassUserForm(RegistrationUserForm):
@ -227,31 +164,22 @@ class RegistrationPassUserForm(RegistrationUserForm):
return user return user
class RegistrationProfileForm(forms.ModelForm): class RegistrationCofProfileForm(forms.ModelForm):
def __init__(self, *args, **kw):
super(RegistrationProfileForm, self).__init__(*args, **kw)
self.fields['mailing_cof'].initial = True
self.fields['mailing_bda'].initial = True
self.fields['mailing_bda_revente'].initial = True
self.fields.keyOrder = [
'login_clipper',
'phone',
'occupation',
'departement',
'is_cof',
'type_cotiz',
'mailing_cof',
'mailing_bda',
'mailing_bda_revente',
'comments'
]
class Meta: class Meta:
model = CofProfile model = CofProfile
fields = ("login_clipper", "phone", "occupation", fields = [
"departement", "is_cof", "type_cotiz", "mailing_cof", "type_cotiz",
"mailing_bda", "mailing_bda_revente", "comments") "mailing", "mailing_bda", "mailing_bda_revente",
]
class RegistrationProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = [
"login_clipper", "phone", "occupation", "departement", "comments"
]
STATUS_CHOICES = (('no', 'Non'), STATUS_CHOICES = (('no', 'Non'),
('wait', 'Oui mais attente paiement'), ('wait', 'Oui mais attente paiement'),
@ -367,17 +295,6 @@ class CalendarForm(forms.ModelForm):
'other_shows'] 'other_shows']
class ClubsForm(forms.Form):
"""
Formulaire d'inscription d'un membre à plusieurs clubs du COF.
"""
clubs = forms.ModelMultipleChoiceField(
label="Inscriptions aux clubs du COF",
queryset=Club.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=False)
# --- # ---
# Announcements banner # Announcements banner
# TODO: move this to the `gestion` app once the supportBDS branch is merged # TODO: move this to the `gestion` app once the supportBDS branch is merged

View file

@ -0,0 +1,93 @@
from django.contrib.auth.models import User, Group
from django.core.management import BaseCommand
from gestion.models import (
Association, Club, ClubUser, Event, EventCommentField, EventCommentValue,
EventRegistration, Location,
)
class Command(BaseCommand):
def handle(self, *args, **options):
self.check_cof_assoc()
self.check_users()
self.check_clubs()
self.check_events()
self.stdout.write("All good, gg wp! :-)")
def check_cof_assoc(self):
self.stdout.write("* COF assoc... ", ending='')
self.assoc = Association.objects.get(name='COF')
self.g_staff = Group.objects.get(name='cof_buro')
self.g_members = Group.objects.get(name='cof_members')
assert self.assoc.staff_group == self.g_staff
assert self.assoc.members_group == self.g_members
self.stdout.write("OK")
def check_users(self):
self.stdout.write("* Utilisateurs... ", ending='')
self.u1 = User.objects.get(username='cbdsusr1')
assert self.u1.profile.login_clipper == 'cbdsusr1'
assert self.g_staff in self.u1.groups.all()
assert self.g_members in self.u1.groups.all()
assert self.u1.has_perm('cof.buro')
assert self.u1.has_perm('cof.member')
self.u2 = User.objects.get(username='cbdsusr2')
assert self.u2.profile.login_clipper == 'cbdsusr2'
assert self.g_staff not in self.u2.groups.all()
assert self.g_members in self.u2.groups.all()
assert not self.u2.has_perm('cof.buro')
assert self.u2.has_perm('cof.member')
self.u3 = User.objects.get(username='cbdsusr3')
assert self.u3.profile.login_clipper == 'cbdsusr3'
assert self.g_staff not in self.u3.groups.all()
assert self.g_members not in self.u3.groups.all()
assert not self.u3.has_perm('cof.buro')
assert not self.u3.has_perm('cof.member')
self.stdout.write("OK")
def check_clubs(self):
self.stdout.write("* Clubs... ", ending='')
c1 = Club.objects.get(name='Club 1')
m1_1 = ClubUser.objects.get(user=self.u1, club=c1)
assert not m1_1.is_respo
m1_2 = ClubUser.objects.get(user=self.u2, club=c1)
assert m1_2.is_respo
c2 = Club.objects.get(name='Club 2')
assert c2.members.count() == 0
self.stdout.write("OK")
def check_events(self):
self.stdout.write("* Évènements... ", ending='')
Location.objects.get(name='Location 1')
assert Location.objects.count() == 1
e1 = Event.objects.get(title='Event 1')
assert e1.associations.count() == 1
assert e1.commentfields.count() == 2
er1 = e1.eventregistration_set.all()
assert len(er1) == 2
er1_1 = EventRegistration.objects.get(user=self.u2, event=e1)
assert er1_1.filledcomments.count() == 1
er1_2 = EventRegistration.objects.get(user=self.u3, event=e1)
assert er1_2.filledcomments.count() == 1
Event.objects.get(title='Event 2')
self.stdout.write("OK")

View file

@ -13,12 +13,14 @@ import random
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.management import call_command from django.core.management import call_command
from gestioncof.management.base import MyBaseCommand from cof.management.base import MyBaseCommand
from gestioncof.petits_cours_models import ( from cof.petits_cours_models import (
PetitCoursAbility, PetitCoursSubject, LEVELS_CHOICES, PetitCoursAbility, PetitCoursSubject, LEVELS_CHOICES,
PetitCoursAttributionCounter PetitCoursAttributionCounter
) )
from cof.models import CofProfile
# Où sont stockés les fichiers json # Où sont stockés les fichiers json
DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
'data') 'data')
@ -47,8 +49,10 @@ class Command(MyBaseCommand):
# Gaulois # Gaulois
gaulois = self.from_json('gaulois.json', DATA_DIR, User) gaulois = self.from_json('gaulois.json', DATA_DIR, User)
for user in gaulois: for user in gaulois:
user.profile.is_cof = True cofprofile = CofProfile.objects.create(
user.profile.save() profile=user.profile,
)
cofprofile.is_cof = True
# Romains # Romains
self.from_json('romains.json', DATA_DIR, User) self.from_json('romains.json', DATA_DIR, User)
@ -65,10 +69,12 @@ class Command(MyBaseCommand):
root.set_password('root') root.set_password('root')
root.is_staff = True root.is_staff = True
root.is_superuser = True root.is_superuser = True
root.profile.is_cof = True
root.profile.is_buro = True
root.profile.save()
root.save() root.save()
CofProfile.objects.create(
profile=root.profile,
is_cof=True,
is_buro=True
)
# --- # ---
# Petits cours # Petits cours

View file

@ -48,7 +48,10 @@ class Migration(migrations.Migration):
('is_buro', models.BooleanField(default=False, verbose_name=b'Membre du Bur\xc3\xb4')), ('is_buro', models.BooleanField(default=False, verbose_name=b'Membre du Bur\xc3\xb4')),
('petits_cours_accept', models.BooleanField(default=False, verbose_name=b'Recevoir des petits cours')), ('petits_cours_accept', models.BooleanField(default=False, verbose_name=b'Recevoir des petits cours')),
('petits_cours_remarques', models.TextField(default=b'', verbose_name='Remarques et pr\xe9cisions pour les petits cours', blank=True)), ('petits_cours_remarques', models.TextField(default=b'', verbose_name='Remarques et pr\xe9cisions pour les petits cours', blank=True)),
('user', models.OneToOneField(related_name='profile', to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(
related_name='profile',
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'Profil COF', 'verbose_name': 'Profil COF',
@ -91,7 +94,10 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=200, verbose_name=b'Champ')), ('name', models.CharField(max_length=200, verbose_name=b'Champ')),
('fieldtype', models.CharField(default=b'text', max_length=10, verbose_name=b'Type', choices=[(b'text', 'Texte long'), (b'char', 'Texte court')])), ('fieldtype', models.CharField(default=b'text', max_length=10, verbose_name=b'Type', choices=[(b'text', 'Texte long'), (b'char', 'Texte court')])),
('default', models.TextField(verbose_name=b'Valeur par d\xc3\xa9faut', blank=True)), ('default', models.TextField(verbose_name=b'Valeur par d\xc3\xa9faut', blank=True)),
('event', models.ForeignKey(related_name='commentfields', to='gestioncof.Event')), ('event', models.ForeignKey(
related_name='commentfields',
on_delete=models.CASCADE,
to='cof.Event')),
], ],
options={ options={
'verbose_name': 'Champ', 'verbose_name': 'Champ',
@ -102,7 +108,10 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('content', models.TextField(null=True, verbose_name=b'Contenu', blank=True)), ('content', models.TextField(null=True, verbose_name=b'Contenu', blank=True)),
('commentfield', models.ForeignKey(related_name='values', to='gestioncof.EventCommentField')), ('commentfield', models.ForeignKey(
related_name='values',
on_delete=models.CASCADE,
to='cof.EventCommentField')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -111,7 +120,10 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=200, verbose_name=b'Option')), ('name', models.CharField(max_length=200, verbose_name=b'Option')),
('multi_choices', models.BooleanField(default=False, verbose_name=b'Choix multiples')), ('multi_choices', models.BooleanField(default=False, verbose_name=b'Choix multiples')),
('event', models.ForeignKey(related_name='options', to='gestioncof.Event')), ('event', models.ForeignKey(
related_name='options',
on_delete=models.CASCADE,
to='cof.Event')),
], ],
options={ options={
'verbose_name': 'Option', 'verbose_name': 'Option',
@ -122,7 +134,10 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('value', models.CharField(max_length=200, verbose_name=b'Valeur')), ('value', models.CharField(max_length=200, verbose_name=b'Valeur')),
('event_option', models.ForeignKey(related_name='choices', to='gestioncof.EventOption')), ('event_option', models.ForeignKey(
related_name='choices',
on_delete=models.CASCADE,
to='cof.EventOption')),
], ],
options={ options={
'verbose_name': 'Choix', 'verbose_name': 'Choix',
@ -133,10 +148,14 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('paid', models.BooleanField(default=False, verbose_name=b'A pay\xc3\xa9')), ('paid', models.BooleanField(default=False, verbose_name=b'A pay\xc3\xa9')),
('event', models.ForeignKey(to='gestioncof.Event')), ('event', models.ForeignKey(
('filledcomments', models.ManyToManyField(to='gestioncof.EventCommentField', through='gestioncof.EventCommentValue')), on_delete=models.CASCADE,
('options', models.ManyToManyField(to='gestioncof.EventOptionChoice')), to='cof.Event')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), ('filledcomments', models.ManyToManyField(to='cof.EventCommentField', through='cof.EventCommentValue')),
('options', models.ManyToManyField(to='cof.EventOptionChoice')),
('user', models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'Inscription', 'verbose_name': 'Inscription',
@ -205,7 +224,7 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=30, verbose_name='Mati\xe8re')), ('name', models.CharField(max_length=30, verbose_name='Mati\xe8re')),
('users', models.ManyToManyField(related_name='petits_cours_matieres', through='gestioncof.PetitCoursAbility', to=settings.AUTH_USER_MODEL)), ('users', models.ManyToManyField(related_name='petits_cours_matieres', through='cof.PetitCoursAbility', to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'Mati\xe8re de petits cours', 'verbose_name': 'Mati\xe8re de petits cours',
@ -240,7 +259,10 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('question', models.CharField(max_length=200, verbose_name=b'Question')), ('question', models.CharField(max_length=200, verbose_name=b'Question')),
('multi_answers', models.BooleanField(default=False, verbose_name=b'Choix multiples')), ('multi_answers', models.BooleanField(default=False, verbose_name=b'Choix multiples')),
('survey', models.ForeignKey(related_name='questions', to='gestioncof.Survey')), ('survey', models.ForeignKey(
on_delete=models.CASCADE,
related_name='questions',
to='cof.Survey')),
], ],
options={ options={
'verbose_name': 'Question', 'verbose_name': 'Question',
@ -251,7 +273,10 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('answer', models.CharField(max_length=200, verbose_name=b'R\xc3\xa9ponse')), ('answer', models.CharField(max_length=200, verbose_name=b'R\xc3\xa9ponse')),
('survey_question', models.ForeignKey(related_name='answers', to='gestioncof.SurveyQuestion')), ('survey_question', models.ForeignKey(
related_name='answers',
on_delete=models.CASCADE,
to='cof.SurveyQuestion')),
], ],
options={ options={
'verbose_name': 'R\xe9ponse', 'verbose_name': 'R\xe9ponse',
@ -260,67 +285,96 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='surveyanswer', model_name='surveyanswer',
name='answers', name='answers',
field=models.ManyToManyField(related_name='selected_by', to='gestioncof.SurveyQuestionAnswer'), field=models.ManyToManyField(related_name='selected_by', to='cof.SurveyQuestionAnswer'),
), ),
migrations.AddField( migrations.AddField(
model_name='surveyanswer', model_name='surveyanswer',
name='survey', name='survey',
field=models.ForeignKey(to='gestioncof.Survey'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='cof.Survey'),
), ),
migrations.AddField( migrations.AddField(
model_name='surveyanswer', model_name='surveyanswer',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursdemande', model_name='petitcoursdemande',
name='matieres', name='matieres',
field=models.ManyToManyField(related_name='demandes', verbose_name='Mati\xe8res', to='gestioncof.PetitCoursSubject'), field=models.ManyToManyField(related_name='demandes', verbose_name='Mati\xe8res', to='cof.PetitCoursSubject'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursdemande', model_name='petitcoursdemande',
name='traitee_par', name='traitee_par',
field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True), field=models.ForeignKey(
on_delete=models.PROTECT,
blank=True,
to=settings.AUTH_USER_MODEL,
null=True),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattributioncounter', model_name='petitcoursattributioncounter',
name='matiere', name='matiere',
field=models.ForeignKey(verbose_name='Matiere', to='gestioncof.PetitCoursSubject'), field=models.ForeignKey(
on_delete=models.PROTECT,
verbose_name='Matiere',
to='cof.PetitCoursSubject'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattributioncounter', model_name='petitcoursattributioncounter',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.PROTECT,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattribution', model_name='petitcoursattribution',
name='demande', name='demande',
field=models.ForeignKey(verbose_name='Demande', to='gestioncof.PetitCoursDemande'), field=models.ForeignKey(
on_delete=models.CASCADE,
verbose_name='Demande',
to='cof.PetitCoursDemande'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattribution', model_name='petitcoursattribution',
name='matiere', name='matiere',
field=models.ForeignKey(verbose_name='Mati\xe8re', to='gestioncof.PetitCoursSubject'), field=models.ForeignKey(
on_delete=models.PROTECT,
verbose_name='Mati\xe8re',
to='cof.PetitCoursSubject'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattribution', model_name='petitcoursattribution',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursability', model_name='petitcoursability',
name='matiere', name='matiere',
field=models.ForeignKey(verbose_name='Mati\xe8re', to='gestioncof.PetitCoursSubject'), field=models.ForeignKey(
on_delete=models.CASCADE,
verbose_name='Mati\xe8re',
to='cof.PetitCoursSubject'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursability', model_name='petitcoursability',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='eventcommentvalue', model_name='eventcommentvalue',
name='registration', name='registration',
field=models.ForeignKey(related_name='comments', to='gestioncof.EventRegistration'), field=models.ForeignKey(
on_delete=models.CASCADE,
related_name='comments',
to='cof.EventRegistration'),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='surveyanswer', name='surveyanswer',

View file

@ -7,7 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0001_initial'), ('cof', '0001_initial'),
] ]
operations = [ operations = [

View file

@ -7,7 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0002_enable_unprocessed_demandes'), ('cof', '0002_enable_unprocessed_demandes'),
] ]
operations = [ operations = [

View file

@ -5,7 +5,7 @@ from django.db import migrations
def create_mail(apps, schema_editor): def create_mail(apps, schema_editor):
CustomMail = apps.get_model("gestioncof", "CustomMail") CustomMail = apps.get_model("cof", "CustomMail")
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
if CustomMail.objects.filter(shortname="bienvenue").count() == 0: if CustomMail.objects.filter(shortname="bienvenue").count() == 0:
CustomMail.objects.using(db_alias).bulk_create([ CustomMail.objects.using(db_alias).bulk_create([
@ -24,7 +24,7 @@ def create_mail(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0003_event_image'), ('cof', '0003_event_image'),
] ]
operations = [ operations = [

View file

@ -7,7 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0004_registration_mail'), ('cof', '0004_registration_mail'),
] ]
operations = [ operations = [

View file

@ -10,7 +10,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
('bda', '0004_mails-rappel'), ('bda', '0004_mails-rappel'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('gestioncof', '0005_encoding'), ('cof', '0005_encoding'),
] ]
operations = [ operations = [
@ -23,7 +23,9 @@ class Migration(migrations.Migration):
('subscribe_to_events', models.BooleanField(default=True)), ('subscribe_to_events', models.BooleanField(default=True)),
('subscribe_to_my_shows', models.BooleanField(default=True)), ('subscribe_to_my_shows', models.BooleanField(default=True)),
('other_shows', models.ManyToManyField(to='bda.Spectacle')), ('other_shows', models.ManyToManyField(to='bda.Spectacle')),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL)),
], ],
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(

View file

@ -8,7 +8,7 @@ from django.conf import settings
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0006_add_calendar'), ('cof', '0006_add_calendar'),
] ]
operations = [ operations = [

View file

@ -5,14 +5,100 @@ from django.db import models, migrations
def forwards(apps, schema_editor): def forwards(apps, schema_editor):
Profile = apps.get_model("gestioncof", "CofProfile") Profile = apps.get_model("cof", "CofProfile")
Profile.objects.update(comments="") Profile.objects.update(comments="")
def load_user(apps, username, is_cof=False):
User = apps.get_model('auth', 'User')
CofProfile = apps.get_model('cof', 'CofProfile')
u = User.objects.create(
username=username,
first_name=username,
last_name=username,
)
p = CofProfile.objects.create(user=u)
p.login_clipper = username
p.is_cof = is_cof
p.save()
return u
def load_olddata(apps, schema_editor):
print(
">>> Insertion de données utilisant le schéma de DB pré-supportBDS...",
end=' ',
)
# Setup users.
u1 = load_user(apps, 'cbdsusr1', is_cof=True)
u1.profile.is_buro = True
u1.profile.save()
u2 = load_user(apps, 'cbdsusr2', is_cof=True)
u3 = load_user(apps, 'cbdsusr3')
# Setup clubs.
Club = apps.get_model('cof', 'Club')
c1 = Club.objects.create(name='Club 1')
c2 = Club.objects.create(name='Club 2')
c1.membres.add(u1, u2)
c1.respos.add(u2)
# Setup events.
Event = apps.get_model('cof', 'Event')
e1 = Event.objects.create(
title='Event 1',
location='Location 1',
)
e2 = Event.objects.create(
title='Event 2',
location='Location 1',
)
EventRegistration = apps.get_model('cof', 'EventRegistration')
er1_1 = EventRegistration.objects.create(user=u2, event=e1)
er1_2 = EventRegistration.objects.create(user=u3, event=e1)
EventCommentField = apps.get_model('cof', 'EventCommentField')
ecf1_1 = EventCommentField.objects.create(
name='Comment field 1',
event=e1,
)
ecf1_2 = EventCommentField.objects.create(
name='Comment field 2',
event=e1,
)
EventCommentValue = apps.get_model('cof', 'EventCommentValue')
EventCommentValue.objects.create(
commentfield=ecf1_1,
registration=er1_1,
content='',
)
EventCommentValue.objects.create(
commentfield=ecf1_2,
registration=er1_2,
content='',
)
print("DONE")
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0007_alter_club'), ('cof', '0007_alter_club'),
] ]
operations = [ operations = [
@ -250,4 +336,5 @@ class Migration(migrations.Migration):
field=models.CharField(verbose_name='Question', max_length=200), field=models.CharField(verbose_name='Question', max_length=200),
), ),
migrations.RunPython(forwards, migrations.RunPython.noop), migrations.RunPython(forwards, migrations.RunPython.noop),
migrations.RunPython(load_olddata),
] ]

View file

@ -7,7 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0008_py3'), ('cof', '0008_py3'),
] ]
operations = [ operations = [

View file

@ -6,7 +6,7 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0009_delete_clipper'), ('cof', '0009_delete_clipper'),
] ]
operations = [ operations = [

View file

@ -7,7 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0010_delete_custommail'), ('cof', '0010_delete_custommail'),
] ]
operations = [ operations = [

View file

@ -7,7 +7,7 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0010_delete_custommail'), ('cof', '0010_delete_custommail'),
] ]
operations = [ operations = [

View file

@ -7,8 +7,8 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0011_remove_cofprofile_num'), ('cof', '0011_remove_cofprofile_num'),
('gestioncof', '0011_longer_clippers'), ('cof', '0011_longer_clippers'),
] ]
operations = [ operations = [

View file

@ -7,7 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('gestioncof', '0012_merge'), ('cof', '0012_merge'),
] ]
operations = [ operations = [

View file

@ -0,0 +1,153 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.db.models import F
from utils.models import sqlsequencereset
def profiles_to_gestion(apps, schema_editor):
OldProfile = apps.get_model('cof', 'CofProfile')
NewProfile = apps.get_model('gestion', 'Profile')
connection = schema_editor.connection
# New profiles are massively imported from the old profiles.
# IDs are kept identical to ease the migration of models which were
# referencing the CofProfile model.
new_profiles = []
for old_p in OldProfile.objects.values().iterator():
new_profiles.append(
NewProfile(
id=old_p['id'],
user_id=old_p['user_id'],
login_clipper=old_p['login_clipper'],
phone=old_p['phone'],
occupation=old_p['occupation'],
departement=old_p['departement'],
comments=old_p['comments'],
)
)
NewProfile.objects.bulk_create(new_profiles)
sqlsequencereset([NewProfile], conn=connection)
OldProfile.objects.all().update(profile_id=F('id'))
def cof_status_to_gestion(apps, schema_editor):
Association = apps.get_model('gestion', 'Association')
CofProfile = apps.get_model('cof', 'CofProfile')
cof_assoc = Association.objects.get(name='COF')
cof_pks = (
CofProfile.objects
.select_related('profile')
.values_list('profile__user_id', flat=True)
)
cof_assoc.members_group.user_set.add(
*cof_pks.filter(is_cof=True)
)
cof_assoc.staff_group.user_set.add(
*cof_pks.filter(is_buro=True)
)
class Migration(migrations.Migration):
"""
BDS support changes how users data is organized.
Data is migrated to the new schema.
"""
dependencies = [
('cof', '0013_pei'),
('gestion', '0002_create_cof_bds'),
# Migrate the K-Fêt app up to the pre-BDS state before performing the
# BDS-related stuff
('kfet', '0061_add_perms_config'),
]
operations = [
# Temporarly authorize 'profile' as nullable to allow migrating data.
migrations.AddField(
model_name='cofprofile',
name='profile',
field=models.OneToOneField(
on_delete=models.CASCADE,
to='gestion.Profile',
null=True,
related_name='cof'
),
preserve_default=False,
),
migrations.RunPython(profiles_to_gestion),
# Data is migrated, unset nullable on 'profile'.
migrations.AlterField(
model_name='cofprofile',
name='profile',
field=models.OneToOneField(
on_delete=models.CASCADE,
to='gestion.Profile',
related_name='cof'
),
),
# Remove fields no longer used.
migrations.RemoveField(
model_name='cofprofile',
name='user',
),
migrations.RemoveField(
model_name='cofprofile',
name='comments',
),
migrations.RemoveField(
model_name='cofprofile',
name='departement',
),
migrations.RemoveField(
model_name='cofprofile',
name='login_clipper',
),
migrations.RemoveField(
model_name='cofprofile',
name='occupation',
),
migrations.RemoveField(
model_name='cofprofile',
name='phone',
),
# Keep cof member/staff status.
migrations.RunPython(cof_status_to_gestion),
# Remove the last no longer used fields.
migrations.RemoveField(
model_name='cofprofile',
name='is_cof',
),
migrations.RemoveField(
model_name='cofprofile',
name='is_buro',
),
# Now we are safe, let's do basic operations.
migrations.AlterModelOptions(
name='cofprofile',
options={
'permissions': (('member', 'Is a COF member'),
('buro', 'Is part of COF staff')),
'verbose_name': 'Profil COF',
'verbose_name_plural': 'Profils COF'},
),
migrations.RenameField(
model_name='cofprofile',
old_name='mailing_cof',
new_name='mailing',
),
]

View file

@ -0,0 +1,65 @@
from __future__ import unicode_literals
from django.db import migrations
def clubs_to_gestion(apps, schema_editor):
Association = apps.get_model('gestion', 'Association')
Membership = apps.get_model('gestion', 'ClubUser')
OldClub = apps.get_model('cof', 'Club')
NewClub = apps.get_model('gestion', 'Club')
cof_assoc = Association.objects.get(name='COF')
memberships = []
for oldclub in OldClub.objects.all():
newclub = NewClub.objects.create(
name=oldclub.name,
description=oldclub.description,
association=cof_assoc,
)
members = oldclub.membres.values_list('id', flat=True)
respos = oldclub.respos.values_list('id', flat=True)
for user in members:
memberships.append(
Membership(
club=newclub,
user_id=user,
has_paid=True,
is_respo=user in respos,
)
)
Membership.objects.bulk_create(memberships)
class Migration(migrations.Migration):
"""
This migration focus on migrating clubs data to the 'gestion' app.
"""
dependencies = [
('cof', '0014_move_profile'),
('gestion', '0002_create_cof_bds'),
]
operations = [
# Move clubs from cof to gestion.
migrations.RunPython(clubs_to_gestion),
# Delete legacy Club model.
migrations.RemoveField(
model_name='club',
name='membres',
),
migrations.RemoveField(
model_name='club',
name='respos',
),
migrations.DeleteModel(
name='Club',
),
]

View file

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
from utils.models import sqlsequencereset
def event_to_gestion(apps, schema_editor):
# Fetching the models that have be moved from cof to gestion
OldEvent = apps.get_model('cof', 'Event')
NewEvent = apps.get_model('gestion', 'Event')
Location = apps.get_model('gestion', 'Location')
Association = apps.get_model('gestion', 'Association')
connection = schema_editor.connection
# The old Event.location field becomes a table: we need to create an entry
# in this table for each value of the old `location` field.
locations = set() # A set to prevent duplicate entries
old_events = OldEvent.objects.values()
new_events = []
for event in old_events:
locations.add(event["location"])
new_events.append(event)
Location.objects.bulk_create([Location(name=name) for name in locations])
map_loc = {
loc.name: loc
for loc in Location.objects.all()
}
for event in new_events:
event["location"] = map_loc[event["location"]]
NewEvent.objects.bulk_create([
NewEvent(**event)
for event in new_events
])
sqlsequencereset([NewEvent], conn=connection)
# Do not forget to link all the existing event to the COF association
cof_assoc = Association.objects.get(name="COF")
cof_assoc.events.add(*NewEvent.objects.all())
# Migrating the other models is straightforward.
# Keep care to the ordering. A change can lead to DB error because of
# failed checks on foreignkey constraints. The dependencies between these
# models give the following constraints:
# - EventRegistration must precede EventCommentField and EventOption,
# - EventCommentField must precede EventCommentValue,
# - EventOption must precede EventOptionChoice.
model_names = [
'EventRegistration', 'EventCommentField', 'EventCommentValue',
'EventOption', 'EventOptionChoice',
]
cls_models = [
(apps.get_model('cof', name), apps.get_model('gestion', name))
for name in model_names
]
for FromModel, ToModel in cls_models:
ToModel.objects.bulk_create([
ToModel(**values)
for values in FromModel.objects.values()
])
sqlsequencereset([ToModel], conn=connection)
class Migration(migrations.Migration):
dependencies = [
('cof', '0015_move_club'),
('gestion', '0002_create_cof_bds'),
]
operations = [
migrations.RunPython(event_to_gestion),
migrations.RemoveField(
model_name='eventcommentfield',
name='event',
),
migrations.RemoveField(
model_name='eventcommentvalue',
name='commentfield',
),
migrations.RemoveField(
model_name='eventcommentvalue',
name='registration',
),
migrations.RemoveField(
model_name='eventoption',
name='event',
),
migrations.RemoveField(
model_name='eventoptionchoice',
name='event_option',
),
migrations.AlterUniqueTogether(
name='eventregistration',
unique_together=set([]),
),
migrations.RemoveField(
model_name='eventregistration',
name='event',
),
migrations.RemoveField(
model_name='eventregistration',
name='filledcomments',
),
migrations.RemoveField(
model_name='eventregistration',
name='options',
),
migrations.RemoveField(
model_name='eventregistration',
name='user',
),
migrations.DeleteModel(
name='Event',
),
migrations.DeleteModel(
name='EventCommentField',
),
migrations.DeleteModel(
name='EventCommentValue',
),
migrations.DeleteModel(
name='EventOption',
),
migrations.DeleteModel(
name='EventOptionChoice',
),
migrations.DeleteModel(
name='EventRegistration',
),
]

View file

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cof', '0016_move_event'),
]
operations = [
migrations.AlterField(
model_name='petitcoursattribution',
name='matiere',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cof.PetitCoursSubject', verbose_name='Matière'),
),
migrations.AlterField(
model_name='petitcoursattributioncounter',
name='matiere',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cof.PetitCoursSubject', verbose_name='Matiere'),
),
migrations.AlterField(
model_name='petitcoursattributioncounter',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='petitcoursdemande',
name='traitee_par',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

167
cof/models.py Normal file
View file

@ -0,0 +1,167 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import Group, User
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import python_2_unicode_compatible
import django.utils.six as six
from gestion.models import Association, Profile
from bda.models import Spectacle
from .petits_cours_models import choices_length
def get_cof_assoc():
return Association.objects.get(name='COF')
class CofProfile(models.Model):
COTIZ_ETUDIANT = "etudiant"
COTIZ_NORMALIEN = "normalien"
COTIZ_EXTE = "exterieur"
COTIZ_GRATIS = "gratis"
TYPE_COTIZ_CHOICES = (
(COTIZ_ETUDIANT, _("Normalien étudiant")),
(COTIZ_NORMALIEN, _("Normalien élève")),
(COTIZ_EXTE, _("Extérieur")),
(COTIZ_GRATIS, _("Gratuit")),
)
profile = models.OneToOneField(Profile,
on_delete=models.CASCADE,
related_name="cof")
type_cotiz = models.CharField(_("Type de cotisation"),
default="normalien",
choices=TYPE_COTIZ_CHOICES,
max_length=choices_length(
TYPE_COTIZ_CHOICES))
mailing = models.BooleanField("Recevoir les mails COF", default=False)
# XXX. remove the following and put in a BDA profile
mailing_bda = models.BooleanField("Recevoir les mails BdA", default=False)
mailing_bda_revente = models.BooleanField(
"Recevoir les mails de revente de places BdA", default=False)
petits_cours_accept = models.BooleanField(
"Recevoir des petits cours", default=False)
petits_cours_remarques = models.TextField(
_("Remarques et précisions pour les petits cours"),
blank=True, default="")
class Meta:
verbose_name = "Profil COF"
verbose_name_plural = "Profils COF"
permissions = (
('member', 'Is a COF member'),
('buro', 'Is part of COF staff'),
)
@property
def is_cof(self):
return self.profile.user.has_perm('cof.member')
@is_cof.setter
def is_cof(self, really):
if really:
g = Group.objects.get(name='cof_members')
self.profile.user.groups.add(g)
# XXX. remove the following and use django auth.
@property
def is_buro(self):
return self.profile.user.has_perm('cof.buro')
@is_buro.setter
def is_buro(self, really):
if really:
g = Group.objects.get(name='cof_buro')
self.profile.user.groups.add(g)
def __str__(self):
return self.profile.user.username
@python_2_unicode_compatible
class Survey(models.Model):
title = models.CharField("Titre", max_length=200)
details = models.TextField("Détails", blank=True)
survey_open = models.BooleanField("Sondage ouvert", default=True)
old = models.BooleanField("Archiver (sondage fini)", default=False)
class Meta:
verbose_name = "Sondage"
def __str__(self):
return six.text_type(self.title)
@python_2_unicode_compatible
class SurveyQuestion(models.Model):
survey = models.ForeignKey(
Survey,
on_delete=models.CASCADE,
related_name="questions"
)
question = models.CharField("Question", max_length=200)
multi_answers = models.BooleanField("Choix multiples", default=False)
class Meta:
verbose_name = "Question"
def __str__(self):
return six.text_type(self.question)
@python_2_unicode_compatible
class SurveyQuestionAnswer(models.Model):
survey_question = models.ForeignKey(
SurveyQuestion,
on_delete=models.CASCADE,
related_name="answers"
)
answer = models.CharField("Réponse", max_length=200)
class Meta:
verbose_name = "Réponse"
def __str__(self):
return six.text_type(self.answer)
@python_2_unicode_compatible
class SurveyAnswer(models.Model):
user = models.ForeignKey(
User,
on_delete=models.CASCADE
)
survey = models.ForeignKey(
Survey,
on_delete=models.CASCADE
)
answers = models.ManyToManyField(SurveyQuestionAnswer,
related_name="selected_by")
class Meta:
verbose_name = "Réponses"
unique_together = ("user", "survey")
def __str__(self):
return "Réponse de %s sondage %s" % (
self.user.get_full_name(),
self.survey.title)
@python_2_unicode_compatible
class CalendarSubscription(models.Model):
token = models.UUIDField()
user = models.OneToOneField(
User,
on_delete=models.CASCADE
)
other_shows = models.ManyToManyField(Spectacle)
subscribe_to_events = models.BooleanField(default=True)
subscribe_to_my_shows = models.BooleanField(default=True)
def __str__(self):
return "Calendrier de %s" % self.user.get_full_name()

View file

@ -7,7 +7,7 @@ from django.forms import ModelForm
from django.forms.models import inlineformset_factory, BaseInlineFormSet from django.forms.models import inlineformset_factory, BaseInlineFormSet
from django.contrib.auth.models import User from django.contrib.auth.models import User
from gestioncof.petits_cours_models import PetitCoursDemande, PetitCoursAbility from .petits_cours_models import PetitCoursDemande, PetitCoursAbility
class BaseMatieresFormSet(BaseInlineFormSet): class BaseMatieresFormSet(BaseInlineFormSet):

View file

@ -35,8 +35,15 @@ class PetitCoursSubject(models.Model):
class PetitCoursAbility(models.Model): class PetitCoursAbility(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière")) User,
on_delete=models.CASCADE
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matière")
)
niveau = models.CharField(_("Niveau"), niveau = models.CharField(_("Niveau"),
choices=LEVELS_CHOICES, choices=LEVELS_CHOICES,
max_length=choices_length(LEVELS_CHOICES)) max_length=choices_length(LEVELS_CHOICES))
@ -84,7 +91,11 @@ class PetitCoursDemande(models.Model):
remarques = models.TextField(_("Remarques et précisions"), blank=True) remarques = models.TextField(_("Remarques et précisions"), blank=True)
traitee = models.BooleanField(_("Traitée"), default=False) traitee = models.BooleanField(_("Traitée"), default=False)
traitee_par = models.ForeignKey(User, blank=True, null=True) traitee_par = models.ForeignKey(
User,
on_delete=models.CASCADE,
blank=True, null=True
)
processed = models.DateTimeField(_("Date de traitement"), processed = models.DateTimeField(_("Date de traitement"),
blank=True, null=True) blank=True, null=True)
created = models.DateTimeField(_("Date de création"), auto_now_add=True) created = models.DateTimeField(_("Date de création"), auto_now_add=True)
@ -126,9 +137,20 @@ class PetitCoursDemande(models.Model):
class PetitCoursAttribution(models.Model): class PetitCoursAttribution(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande")) User,
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière")) on_delete=models.CASCADE
)
demande = models.ForeignKey(
PetitCoursDemande,
on_delete=models.CASCADE,
verbose_name=_("Demande")
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matière")
)
date = models.DateTimeField(_("Date d'attribution"), auto_now_add=True) date = models.DateTimeField(_("Date d'attribution"), auto_now_add=True)
rank = models.IntegerField("Rang dans l'email") rank = models.IntegerField("Rang dans l'email")
selected = models.BooleanField(_("Sélectionné par le demandeur"), selected = models.BooleanField(_("Sélectionné par le demandeur"),
@ -145,8 +167,15 @@ class PetitCoursAttribution(models.Model):
class PetitCoursAttributionCounter(models.Model): class PetitCoursAttributionCounter(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere")) User,
on_delete=models.CASCADE
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matiere")
)
count = models.IntegerField("Nombre d'envois", default=0) count = models.IntegerField("Nombre d'envois", default=0)
@classmethod @classmethod

View file

@ -1,26 +1,25 @@
# -*- coding: utf-8 -*-
import json import json
from datetime import datetime
from custommail.shortcuts import render_custom_mail from custommail.shortcuts import render_custom_mail
from django.shortcuts import render, get_object_or_404, redirect from django.conf import settings
from django.core import mail from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import mail
from django.db import transaction
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.views.generic import ListView, DetailView from django.views.generic import ListView, DetailView
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db import transaction
from gestioncof.models import CofProfile from .decorators import buro_required
from gestioncof.petits_cours_models import ( from .models import CofProfile
from .petits_cours_models import (
PetitCoursDemande, PetitCoursAttribution, PetitCoursAttributionCounter, PetitCoursDemande, PetitCoursAttribution, PetitCoursAttributionCounter,
PetitCoursAbility PetitCoursAbility
) )
from gestioncof.petits_cours_forms import DemandeForm, MatieresFormSet from .petits_cours_forms import DemandeForm, MatieresFormSet
from gestioncof.decorators import buro_required
class DemandeListView(ListView): class DemandeListView(ListView):
@ -35,12 +34,12 @@ class DemandeListView(ListView):
class DemandeDetailView(DetailView): class DemandeDetailView(DetailView):
model = PetitCoursDemande model = PetitCoursDemande
template_name = "cof/details_demande_petit_cours.html"
queryset = ( queryset = (
PetitCoursDemande.objects PetitCoursDemande.objects
.prefetch_related('petitcoursattribution_set', .prefetch_related('petitcoursattribution_set',
'matieres') 'matieres')
) )
template_name = "gestioncof/details_demande_petit_cours.html"
context_object_name = "demande" context_object_name = "demande"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -111,7 +110,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
if errors is not None: if errors is not None:
for error in errors: for error in errors:
messages.error(request, error) messages.error(request, error)
return render(request, "gestioncof/traitement_demande_petit_cours.html", return render(request, "cof/traitement_demande_petit_cours.html",
{"demande": demande, {"demande": demande,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
"proposals": proposals, "proposals": proposals,
@ -221,7 +220,7 @@ def _traitement_other(request, demande, redo):
proposals = proposals.items() proposals = proposals.items()
proposed_for = proposed_for.items() proposed_for = proposed_for.items()
return render(request, return render(request,
"gestioncof/traitement_demande_petit_cours_autre_niveau.html", "cof/traitement_demande_petit_cours_autre_niveau.html",
{"demande": demande, {"demande": demande,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
"proposals": proposals, "proposals": proposals,
@ -287,10 +286,10 @@ def _traitement_post(request, demande):
attrib.save() attrib.save()
demande.traitee = True demande.traitee = True
demande.traitee_par = request.user demande.traitee_par = request.user
demande.processed = datetime.now() demande.processed = timezone.now()
demande.save() demande.save()
return render(request, return render(request,
"gestioncof/traitement_demande_petit_cours_success.html", "cof/traitement_demande_petit_cours_success.html",
{"demande": demande, {"demande": demande,
"redo": redo, "redo": redo,
}) })

View file

@ -333,8 +333,8 @@ fieldset legend {
padding: 20px; padding: 20px;
} }
#main-content a, #main-content a:not(.btn),
#main-content a:hover { #main-content a:hover:not(.btn) {
color : #D81138; color : #D81138;
} }
@ -354,7 +354,7 @@ fieldset legend {
#main-content h3.horizontal-title { #main-content h3.horizontal-title {
display : block; display : block;
padding : 12px; padding : 12px;
margin: -20px -20px 10px -20px ; margin: 0 -20px 10px -20px ;
font-family: 'Dosis', sans-serif; font-family: 'Dosis', sans-serif;
font-weight: 700; font-weight: 700;
color: white; color: white;
@ -368,11 +368,11 @@ fieldset legend {
border-width: 0px 0px 5px 0px; border-width: 0px 0px 5px 0px;
} }
#main-content h2 a { #main-content h2 a:not(.btn) {
color : #C9E5E1; color : #C9E5E1;
} }
#main-content h2 a:hover { #main-content h2 a:hover:not(.btn) {
color : #ABB8B6; color : #ABB8B6;
} }
@ -380,10 +380,46 @@ fieldset legend {
font-weight: 700; font-weight: 700;
font-size: large; font-size: large;
background-color:#EAA594; background-color:#EAA594;
border-width: 0px 0px 3px 0px; margin-top: 10px;
} }
#main-content > :first-child {
margin-top: -20px;
}
#main-content > div:first-of-type > h3.horizontal-title:first-child {
margin-top: -10px;
}
#main-content h2 .actions ,
#main-content h3 .actions {
float: right;
display: flex;
align-items: center;
margin: -12px;
padding-right: 10px;
}
#main-content h2 .actions {
min-height: 50px;
}
#main-content h3 .actions {
min-height: 44px;
}
#main-content h2 .actions > *,
#main-content h3 .actions > * {
height: 100%;
border-radius: 0;
vertical-align: middle;
}
#main-content h2 .actions > * + *,
#main-content h3 .actions > * + * {
margin-left: 10px;
}
/* /*
main-container { main-container {

View file

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View file

Before

Width:  |  Height:  |  Size: 438 B

After

Width:  |  Height:  |  Size: 438 B

View file

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 663 B

View file

Before

Width:  |  Height:  |  Size: 378 B

After

Width:  |  Height:  |  Size: 378 B

View file

@ -1,4 +1,4 @@
{% extends "gestioncof/base_header.html" %} {% extends "cof/base_header.html" %}
{% block interm_content %} {% block interm_content %}
<div class="container hidden-xs espace"></div> <div class="container hidden-xs espace"></div>

View file

@ -0,0 +1,57 @@
{% load utils %}
<ul>
{% if members %}
<li class="autocomplete-header">Membres du COF</li>
{% for member in members %}
{% if forloop.counter < 5 %}
<li class="autocomplete-value">
<a href="{% url 'user-registration' member.username %}">
{{ member|highlight_user:q }}
</a>
</li>
{% elif forloop.counter == 5 %}
<li class="autocomplete-more">...</li>
{% endif %}
{% endfor %}
{% endif %}
{% if users %}
<li class="autocomplete-header">Utilisateurs de GestioCOF</li>
{% for user in users %}
{% if forloop.counter < 5 %}
<li class="autocomplete-value">
<a href="{% url 'user-registration' user.username %}">
{{ user|highlight_user:q }}
</a>
</li>
{% elif forloop.counter == 5 %}
<li class="autocomplete-more">...</li>
{% endif %}
{% endfor %}
{% endif %}
{% if clippers %}
<li class="autocomplete-header">Utilisateurs <tt>clipper</tt></li>
{% for clipper in clippers %}
{% if forloop.counter < 5 %}
<li class="autocomplete-value">
<a href="{% url 'clipper-registration' clipper.clipper clipper.fullname %}">
{{ clipper|highlight_clipper:q }}
</a>
</li>
{% elif forloop.counter == 5 %}
<li class="autocomplete-more">...</li>
{% endif %}
{% endfor %}
{% endif %}
{% if not options %}
<li class="autocomplete-header">Aucune correspondance trouvée</li>
{% else %}
<li class="autocomplete-header">Pas dans la liste ?</li>
{% endif %}
<li><a href="{% url 'empty-registration' %}">Créer un compte</a></li>
</ul>

View file

@ -0,0 +1,36 @@
{% extends "base.html" %}
{% block content %}
<header>
<div class="container banner">
<a href="{% url "home" %}">
<h1>GestioCOF</h1>
{% block homelink %}
<span class="glyphicon glyphicon-home" aria-hidden=true></span>
{% endblock %}
</a>
<div class="secondary">
<span class="hidden-xxs">&nbsp;&nbsp;|&nbsp; </span>
<span><a href="{% url "gestion:logout" %}">
Se déconnecter&nbsp;<span class="glyphicon glyphicon-log-out"></span>
</a></span>
</div>
<h2 class="member-status">
<a href="{% url "gestion:profile" %}">
{% if user.first_name %}
{{ user.first_name }},
{% else %}
<tt>{{ user.username }}</tt>,
{% endif %}
</a>
{% if user.profile.is_cof %}
<tt class="user-is-cof">au COF</tt>
{% else %}
<tt class="user-is-not-cof">non-COF</tt>
{% endif %}
</h2>
</div><!-- /.container -->
</header>
{% block interm_content %}{% endblock %}
{% endblock %}

View file

@ -12,7 +12,7 @@ souscrire aux événements du COF et/ou aux spectacles BdA.
{% if token %} {% if token %}
<p>Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à <p>Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à
<a href="{% url 'gestioncof.views.calendar_ics' token %}">cette adresse</a>.</p> <a href="{% url 'calendar.ics' token %}">cette adresse</a>.</p>
<ul> <ul>
<li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller <li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller

View file

@ -2,10 +2,13 @@
{% block realcontent %} {% block realcontent %}
<h2>Événement: {{ event.title }}</h2> <h2>Événement: {{ event.title }}</h2>
{% if success %}
<p class="success">Votre inscription a bien été enregistrée ! Vous pouvez cependant la modifier jusqu'à la fin des inscriptions.</p>
{% endif %}
{% if event.details %} {% if event.details %}
<p>{{ event.details }}</p> <p>{{ event.details }}</p>
{% endif %} {% endif %}
<form method="post" action="{% url 'gestioncof.views.event' event.id %}"> <form method="post" action="{% url 'event' event.id %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<input type="submit" class="btn-submit" value="Enregistrer" /> <input type="submit" class="btn-submit" value="Enregistrer" />

View file

@ -7,7 +7,7 @@
{% else %} {% else %}
<h3>Inscription d'un nouveau compte (extérieur ?)</h3> <h3>Inscription d'un nouveau compte (extérieur ?)</h3>
{% endif %} {% endif %}
<form role="form" id="profile" method="post" action="{% url 'gestioncof.views.registration' %}"> <form role="form" id="profile" method="post" action="{% url 'registration' %}">
{% csrf_token %} {% csrf_token %}
<table> <table>
{{ user_form | bootstrap }} {{ user_form | bootstrap }}
@ -15,7 +15,7 @@
</table> </table>
<hr /> <hr />
<table> <table>
{{ clubs_form | bootstrap }} {{ cofprofile_form | bootstrap }}
</table> </table>
{{ event_formset.management_form }} {{ event_formset.management_form }}
{% for event_form in event_formset %} {% for event_form in event_formset %}

View file

@ -3,6 +3,6 @@
{% block realcontent %} {% block realcontent %}
<h2>Inscription d'un nouveau membre</h2> <h2>Inscription d'un nouveau membre</h2>
<div id="form-placeholder"> <div id="form-placeholder">
{% include "gestioncof/registration_form.html" %} {% include "cof/registration_form.html" %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -5,10 +5,17 @@
{% block realcontent %} {% block realcontent %}
<h2>Sondage: {{ survey.title }}</h2> <h2>Sondage: {{ survey.title }}</h2>
{% if success %}
{% if deleted %}
<p class="success">Votre réponse a bien été supprimée !</p>
{% else %}
<p class="success">Votre réponse a bien été enregistrée ! Vous pouvez cependant la modifier jusqu'à la fin du sondage.</p>
{% endif %}
{% endif %}
{% if survey.details %} {% if survey.details %}
<p>{{ survey.details }}</p> <p>{{ survey.details }}</p>
{% endif %} {% endif %}
<form class="form-horizontal" method="post" action="{% url 'gestioncof.views.survey' survey.id %}"> <form class="form-horizontal" method="post" action="{% url 'survey' survey.id %}">
{% csrf_token %} {% csrf_token %}
{{ form | bootstrap}} {{ form | bootstrap}}

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