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
*.swp
*.swo
cof/settings.py
gestioCOF/settings/settings.py
settings.py
*~
venv/

View file

@ -4,7 +4,7 @@ services:
variables:
# GestioCOF settings
DJANGO_SETTINGS_MODULE: "cof.settings.prod"
DJANGO_SETTINGS_MODULE: "gestioCOF.settings.prod"
DBHOST: "postgres"
REDIS_HOST: "redis"
REDIS_PASSWD: "dummy"
@ -29,8 +29,8 @@ cache:
before_script:
- mkdir -p vendor/{python,pip,apt}
- 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 -i.bak -E 's;^REDIS_PASSWD = .*$;REDIS_PASSWD = "";' 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 = "";' gestioCOF/settings/secret.py
# 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"
- 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 -r requirements-devel.txt
Pour terminer, copier le fichier `cof/settings/secret_example.py` vers
`cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique
pour profiter de façon transparente des mises à jour du fichier:
Pour terminer, copier le fichier `gestioCOF/settings/secret_example.py` vers
`gestioCOF/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien
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

View file

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import autocomplete_light
from datetime import timedelta
from custommail.shortcuts import send_mass_custom_mail
@ -180,8 +179,6 @@ class AttributionAdmin(ReadOnlyMixin, admin.ModelAdmin):
class ChoixSpectacleAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[])
def tirage(self, obj):
return obj.participant.tirage
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
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.views import do_tirage
@ -77,7 +77,8 @@ class Command(MyBaseCommand):
self.stdout.write("Inscription des utilisateurs aux tirages")
ChoixSpectacle.objects.all().delete()
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:
part, _ = Participant.objects.get_or_create(
user=user,

View file

@ -59,7 +59,9 @@ class Migration(migrations.Migration):
('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)),
('slots', models.IntegerField(verbose_name=b'Places')),
('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={
'ordering': ('priority', 'date', 'title'),
@ -79,27 +81,39 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='participant',
name='user',
field=models.OneToOneField(to=settings.AUTH_USER_MODEL),
field=models.OneToOneField(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='choixspectacle',
name='participant',
field=models.ForeignKey(to='bda.Participant'),
field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant'),
),
migrations.AddField(
model_name='choixspectacle',
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(
model_name='attribution',
name='participant',
field=models.ForeignKey(to='bda.Participant'),
field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant'),
),
migrations.AddField(
model_name='attribution',
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(
name='choixspectacle',

View file

@ -55,7 +55,9 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='participant',
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.
# These fields are not nullable, but we first create them as nullable
@ -63,12 +65,20 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='participant',
name='tirage',
field=models.ForeignKey(to='bda.Tirage', null=True),
field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Tirage',
null=True
),
),
migrations.AddField(
model_name='spectacle',
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.AlterField(

View file

@ -72,8 +72,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='spectacle',
name='category',
field=models.ForeignKey(blank=True, to='bda.CategorieSpectacle',
null=True),
field=models.ForeignKey(
on_delete=models.CASCADE,
blank=True,
to='bda.CategorieSpectacle',
null=True),
),
migrations.AddField(
model_name='spectacle',
@ -84,6 +87,8 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='quote',
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(
model_name='spectaclerevente',
name='attribution',
field=models.OneToOneField(to='bda.Attribution',
related_name='revente'),
field=models.OneToOneField(
to='bda.Attribution',
on_delete=models.CASCADE,
related_name='revente'),
),
migrations.AddField(
model_name='spectaclerevente',
name='seller',
field=models.ForeignKey(to='bda.Participant',
verbose_name='Vendeur',
related_name='original_shows'),
field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant',
verbose_name='Vendeur',
related_name='original_shows'),
),
migrations.AddField(
model_name='spectaclerevente',
name='soldTo',
field=models.ForeignKey(to='bda.Participant',
verbose_name='Vendue à', null=True,
blank=True),
field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant',
verbose_name='Vendue à',
null=True,
blank=True),
),
]

View file

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

View file

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

View file

@ -5,7 +5,7 @@ from __future__ import print_function
from __future__ import unicode_literals
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 import views

View file

@ -1,34 +1,36 @@
# -*- coding: utf-8 -*-
from collections import defaultdict
import random
import hashlib
import time
import json
from datetime import timedelta
from collections import defaultdict
from custommail.shortcuts import send_mass_custom_mail, send_custom_mail
from custommail.models import CustomMail
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from datetime import timedelta
from django.conf import settings
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.urlresolvers import reverse
from django.db import transaction
from django.db.models import Count, Q, Prefetch
from django.forms.models import inlineformset_factory
from django.http import (
HttpResponseBadRequest, HttpResponseRedirect, JsonResponse
)
from django.core.urlresolvers import reverse
from django.conf import settings
from django.shortcuts import render, get_object_or_404
from django.utils import timezone, formats
from django.views.generic.list import ListView
from gestioncof.decorators import cof_required, buro_required
from bda.models import (
Spectacle, Participant, ChoixSpectacle, Attribution, Tirage,
SpectacleRevente, Salle, CategorieSpectacle
from cof.decorators import cof_required, buro_required
from .models import (
Attribution, CategorieSpectacle, ChoixSpectacle, Participant, Salle,
Spectacle, SpectacleRevente, Tirage
)
from bda.algorithm import Algorithm
from bda.forms import (
from .algorithm import Algorithm
from .forms import (
TokenForm, ResellForm, AnnulForm, InscriptionReventeForm, SoldForm,
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 django import shortcuts
from django.http import Http404
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 gestioncof.models import CofProfile
from gestioncof.decorators import buro_required
class Clipper(object):
def __init__(self, clipper, fullname):
@ -27,22 +23,21 @@ def autocomplete(request):
if "q" not in request.GET:
raise Http404
q = request.GET['q']
data = {
'q': q,
}
data = {'q': q}
cof_members = Group.objects.get(name="cof_members")
queries = {}
bits = q.split()
# Fetching data from User and CofProfile tables
queries['members'] = CofProfile.objects.filter(is_cof=True)
queries['users'] = User.objects.filter(profile__is_cof=False)
# Fetching data from User and Profile tables
queries['members'] = User.objects.filter(groups=cof_members)
queries['users'] = User.objects.exclude(groups=cof_members)
for bit in bits:
queries['members'] = queries['members'].filter(
Q(user__first_name__icontains=bit)
| Q(user__last_name__icontains=bit)
| Q(user__username__icontains=bit)
| Q(login_clipper__icontains=bit))
Q(first_name__icontains=bit)
| Q(last_name__icontains=bit)
| Q(username__icontains=bit)
| Q(profile__login_clipper__icontains=bit))
queries['users'] = queries['users'].filter(
Q(first_name__icontains=bit)
| Q(last_name__icontains=bit)
@ -52,7 +47,8 @@ def autocomplete(request):
# Clearing redundancies
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',
flat='True'))
)
@ -83,6 +79,6 @@ def autocomplete(request):
# Resulting data
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,
"title": "Sort du barde"
},
"model": "gestioncof.survey",
"model": "cof.survey",
"pk": 1
},
{
@ -15,7 +15,7 @@
"survey": 1,
"multi_answers": true
},
"model": "gestioncof.surveyquestion",
"model": "cof.surveyquestion",
"pk": 1
},
{
@ -24,7 +24,7 @@
"survey": 1,
"multi_answers": false
},
"model": "gestioncof.surveyquestion",
"model": "cof.surveyquestion",
"pk": 2
},
{
@ -32,7 +32,7 @@
"answer": "On l'ernestise",
"survey_question": 1
},
"model": "gestioncof.surveyquestionanswer",
"model": "cof.surveyquestionanswer",
"pk": 1
},
{
@ -40,7 +40,7 @@
"answer": "On ligote",
"survey_question": 1
},
"model": "gestioncof.surveyquestionanswer",
"model": "cof.surveyquestionanswer",
"pk": 2
},
{
@ -48,7 +48,7 @@
"answer": "On le prive de banquet",
"survey_question": 1
},
"model": "gestioncof.surveyquestionanswer",
"model": "cof.surveyquestionanswer",
"pk": 3
},
{
@ -56,7 +56,7 @@
"answer": "Oui",
"survey_question": 2
},
"model": "gestioncof.surveyquestionanswer",
"model": "cof.surveyquestionanswer",
"pk": 4
},
{
@ -64,92 +64,35 @@
"answer": "Non",
"survey_question": 2
},
"model": "gestioncof.surveyquestionanswer",
"model": "cof.surveyquestionanswer",
"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": {
"name": "Bagarre"
},
"model": "gestioncof.petitcourssubject",
"model": "cof.petitcourssubject",
"pk": 1
},
{
"fields": {
"name": "Lancer de menhir"
},
"model": "gestioncof.petitcourssubject",
"model": "cof.petitcourssubject",
"pk": 2
},
{
"fields": {
"name": "Pr\u00e9paration de potions"
},
"model": "gestioncof.petitcourssubject",
"model": "cof.petitcourssubject",
"pk": 3
},
{
"fields": {
"name": "Chant"
},
"model": "gestioncof.petitcourssubject",
"model": "cof.petitcourssubject",
"pk": 4
},
{
@ -171,7 +114,7 @@
"email": "jules.cesar@polytechnique.edu",
"processed": null
},
"model": "gestioncof.petitcoursdemande",
"model": "cof.petitcoursdemande",
"pk": 1
},
{
@ -193,7 +136,7 @@
"email": "jules.cesar@polytechnique.edu",
"processed": null
},
"model": "gestioncof.petitcoursdemande",
"model": "cof.petitcoursdemande",
"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 gestioncof.models import CofProfile, EventCommentValue, \
CalendarSubscription, Club
from gestioncof.widgets import TriStateCheckbox
from django import forms
from django.contrib.auth.models import User
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 gestion.models import Profile, EventCommentValue
class EventForm(forms.Form):
def __init__(self, *args, **kwargs):
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)
from .models import CofProfile, CalendarSubscription
from .widgets import TriStateCheckbox
class SurveyForm(forms.Form):
@ -170,27 +128,6 @@ class EventStatusFilterForm(forms.Form):
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):
def __init__(self, *args, **kw):
super(RegistrationUserForm, self).__init__(*args, **kw)
@ -198,7 +135,7 @@ class RegistrationUserForm(forms.ModelForm):
class Meta:
model = User
fields = ("username", "first_name", "last_name", "email")
fields = ["username", "first_name", "last_name", "email"]
class RegistrationPassUserForm(RegistrationUserForm):
@ -227,31 +164,22 @@ class RegistrationPassUserForm(RegistrationUserForm):
return user
class RegistrationProfileForm(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 RegistrationCofProfileForm(forms.ModelForm):
class Meta:
model = CofProfile
fields = ("login_clipper", "phone", "occupation",
"departement", "is_cof", "type_cotiz", "mailing_cof",
"mailing_bda", "mailing_bda_revente", "comments")
fields = [
"type_cotiz",
"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'),
('wait', 'Oui mais attente paiement'),
@ -367,17 +295,6 @@ class CalendarForm(forms.ModelForm):
'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
# 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.core.management import call_command
from gestioncof.management.base import MyBaseCommand
from gestioncof.petits_cours_models import (
from cof.management.base import MyBaseCommand
from cof.petits_cours_models import (
PetitCoursAbility, PetitCoursSubject, LEVELS_CHOICES,
PetitCoursAttributionCounter
)
from cof.models import CofProfile
# Où sont stockés les fichiers json
DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
'data')
@ -47,8 +49,10 @@ class Command(MyBaseCommand):
# Gaulois
gaulois = self.from_json('gaulois.json', DATA_DIR, User)
for user in gaulois:
user.profile.is_cof = True
user.profile.save()
cofprofile = CofProfile.objects.create(
profile=user.profile,
)
cofprofile.is_cof = True
# Romains
self.from_json('romains.json', DATA_DIR, User)
@ -65,10 +69,12 @@ class Command(MyBaseCommand):
root.set_password('root')
root.is_staff = True
root.is_superuser = True
root.profile.is_cof = True
root.profile.is_buro = True
root.profile.save()
root.save()
CofProfile.objects.create(
profile=root.profile,
is_cof=True,
is_buro=True
)
# ---
# 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')),
('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)),
('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={
'verbose_name': 'Profil COF',
@ -91,7 +94,10 @@ class Migration(migrations.Migration):
('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')])),
('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={
'verbose_name': 'Champ',
@ -102,7 +108,10 @@ class Migration(migrations.Migration):
fields=[
('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)),
('commentfield', models.ForeignKey(related_name='values', to='gestioncof.EventCommentField')),
('commentfield', models.ForeignKey(
related_name='values',
on_delete=models.CASCADE,
to='cof.EventCommentField')),
],
),
migrations.CreateModel(
@ -111,7 +120,10 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=200, verbose_name=b'Option')),
('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={
'verbose_name': 'Option',
@ -122,7 +134,10 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('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={
'verbose_name': 'Choix',
@ -133,10 +148,14 @@ class Migration(migrations.Migration):
fields=[
('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')),
('event', models.ForeignKey(to='gestioncof.Event')),
('filledcomments', models.ManyToManyField(to='gestioncof.EventCommentField', through='gestioncof.EventCommentValue')),
('options', models.ManyToManyField(to='gestioncof.EventOptionChoice')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('event', models.ForeignKey(
on_delete=models.CASCADE,
to='cof.Event')),
('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={
'verbose_name': 'Inscription',
@ -205,7 +224,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('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={
'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)),
('question', models.CharField(max_length=200, verbose_name=b'Question')),
('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={
'verbose_name': 'Question',
@ -251,7 +273,10 @@ class Migration(migrations.Migration):
fields=[
('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')),
('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={
'verbose_name': 'R\xe9ponse',
@ -260,67 +285,96 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='surveyanswer',
name='answers',
field=models.ManyToManyField(related_name='selected_by', to='gestioncof.SurveyQuestionAnswer'),
field=models.ManyToManyField(related_name='selected_by', to='cof.SurveyQuestionAnswer'),
),
migrations.AddField(
model_name='surveyanswer',
name='survey',
field=models.ForeignKey(to='gestioncof.Survey'),
field=models.ForeignKey(
on_delete=models.CASCADE,
to='cof.Survey'),
),
migrations.AddField(
model_name='surveyanswer',
name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='petitcoursdemande',
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(
model_name='petitcoursdemande',
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(
model_name='petitcoursattributioncounter',
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(
model_name='petitcoursattributioncounter',
name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(
on_delete=models.PROTECT,
to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='petitcoursattribution',
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(
model_name='petitcoursattribution',
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(
model_name='petitcoursattribution',
name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='petitcoursability',
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(
model_name='petitcoursability',
name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='eventcommentvalue',
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(
name='surveyanswer',

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@ class Migration(migrations.Migration):
dependencies = [
('bda', '0004_mails-rappel'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('gestioncof', '0005_encoding'),
('cof', '0005_encoding'),
]
operations = [
@ -23,7 +23,9 @@ class Migration(migrations.Migration):
('subscribe_to_events', models.BooleanField(default=True)),
('subscribe_to_my_shows', models.BooleanField(default=True)),
('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(

View file

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

View file

@ -5,14 +5,100 @@ from django.db import models, migrations
def forwards(apps, schema_editor):
Profile = apps.get_model("gestioncof", "CofProfile")
Profile = apps.get_model("cof", "CofProfile")
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):
dependencies = [
('gestioncof', '0007_alter_club'),
('cof', '0007_alter_club'),
]
operations = [
@ -250,4 +336,5 @@ class Migration(migrations.Migration):
field=models.CharField(verbose_name='Question', max_length=200),
),
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):
dependencies = [
('gestioncof', '0008_py3'),
('cof', '0008_py3'),
]
operations = [

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestioncof', '0012_merge'),
('cof', '0012_merge'),
]
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.contrib.auth.models import User
from gestioncof.petits_cours_models import PetitCoursDemande, PetitCoursAbility
from .petits_cours_models import PetitCoursDemande, PetitCoursAbility
class BaseMatieresFormSet(BaseInlineFormSet):

View file

@ -35,8 +35,15 @@ class PetitCoursSubject(models.Model):
class PetitCoursAbility(models.Model):
user = models.ForeignKey(User)
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière"))
user = models.ForeignKey(
User,
on_delete=models.CASCADE
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matière")
)
niveau = models.CharField(_("Niveau"),
choices=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)
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"),
blank=True, null=True)
created = models.DateTimeField(_("Date de création"), auto_now_add=True)
@ -126,9 +137,20 @@ class PetitCoursDemande(models.Model):
class PetitCoursAttribution(models.Model):
user = models.ForeignKey(User)
demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande"))
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière"))
user = models.ForeignKey(
User,
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)
rank = models.IntegerField("Rang dans l'email")
selected = models.BooleanField(_("Sélectionné par le demandeur"),
@ -145,8 +167,15 @@ class PetitCoursAttribution(models.Model):
class PetitCoursAttributionCounter(models.Model):
user = models.ForeignKey(User)
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere"))
user = models.ForeignKey(
User,
on_delete=models.CASCADE
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matiere")
)
count = models.IntegerField("Nombre d'envois", default=0)
@classmethod

View file

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

View file

@ -333,8 +333,8 @@ fieldset legend {
padding: 20px;
}
#main-content a,
#main-content a:hover {
#main-content a:not(.btn),
#main-content a:hover:not(.btn) {
color : #D81138;
}
@ -354,7 +354,7 @@ fieldset legend {
#main-content h3.horizontal-title {
display : block;
padding : 12px;
margin: -20px -20px 10px -20px ;
margin: 0 -20px 10px -20px ;
font-family: 'Dosis', sans-serif;
font-weight: 700;
color: white;
@ -368,11 +368,11 @@ fieldset legend {
border-width: 0px 0px 5px 0px;
}
#main-content h2 a {
#main-content h2 a:not(.btn) {
color : #C9E5E1;
}
#main-content h2 a:hover {
#main-content h2 a:hover:not(.btn) {
color : #ABB8B6;
}
@ -380,10 +380,46 @@ fieldset legend {
font-weight: 700;
font-size: large;
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 {

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 %}
<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 %}
<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>
<li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller

View file

@ -2,10 +2,13 @@
{% block realcontent %}
<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 %}
<p>{{ event.details }}</p>
{% endif %}
<form method="post" action="{% url 'gestioncof.views.event' event.id %}">
<form method="post" action="{% url 'event' event.id %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn-submit" value="Enregistrer" />

View file

@ -7,7 +7,7 @@
{% else %}
<h3>Inscription d'un nouveau compte (extérieur ?)</h3>
{% 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 %}
<table>
{{ user_form | bootstrap }}
@ -15,7 +15,7 @@
</table>
<hr />
<table>
{{ clubs_form | bootstrap }}
{{ cofprofile_form | bootstrap }}
</table>
{{ event_formset.management_form }}
{% for event_form in event_formset %}

View file

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

View file

@ -5,10 +5,17 @@
{% block realcontent %}
<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 %}
<p>{{ survey.details }}</p>
{% 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 %}
{{ form | bootstrap}}

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