diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3fb22574..97110ecd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,7 @@ stages: - test - quality-assurance + - docs # Also fetch submodules variables: @@ -62,3 +63,17 @@ linters: # Be nice to new contributors, but please use `tox` allow_failure: true + +# Compile documentation +documentation: + stage: docs + image: sphinxdoc/sphinx + before_script: + - pip install sphinx-rtd-theme + - cd docs + script: + - make dirhtml + artifacts: + paths: + - docs/_build + expire_in: 1 day diff --git a/ansible/base.yml b/ansible/base.yml index a2fca768..83b20cbb 100755 --- a/ansible/base.yml +++ b/ansible/base.yml @@ -16,3 +16,4 @@ - 5-nginx - 6-psql - 7-postinstall + - 8-docs diff --git a/ansible/roles/5-nginx/templates/nginx_note.conf b/ansible/roles/5-nginx/templates/nginx_note.conf index 218d6537..567c4789 100644 --- a/ansible/roles/5-nginx/templates/nginx_note.conf +++ b/ansible/roles/5-nginx/templates/nginx_note.conf @@ -1,5 +1,5 @@ # the upstream component nginx needs to connect to -upstream note{ +upstream note { server unix:///var/www/note_kfet/note_kfet.sock; # file socket } @@ -50,6 +50,10 @@ server { alias /var/www/note_kfet/static; # your Django project's static files - amend as required } + location /doc { + alias /var/www/documentation; # The documentation of the project + } + # Finally, send all non-media requests to the Django server. location / { uwsgi_pass note; diff --git a/ansible/roles/8-docs/tasks/main.yml b/ansible/roles/8-docs/tasks/main.yml new file mode 100644 index 00000000..be8c9607 --- /dev/null +++ b/ansible/roles/8-docs/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- name: Install Sphinx and RTD theme + pip: + requirements: /var/www/note_kfet/docs/requirements.txt + virtualenv: /var/www/note_kfet/env + virtualenv_command: /usr/bin/python3 -m venv + virtualenv_site_packages: true + become_user: www-data + +- name: Create documentation directory with good permissions + file: + path: /var/www/documentation + state: directory + owner: www-data + group: www-data + mode: u=rwx,g=rwxs,o=rx + +- name: Build HTML documentation + command: /var/www/note_kfet/env/bin/sphinx-build -b dirhtml /var/www/note_kfet/docs/ /var/www/documentation/ + become_user: www-data diff --git a/apps/permission/api/views.py b/apps/permission/api/views.py index 10fd19e3..e6cb0d5d 100644 --- a/apps/permission/api/views.py +++ b/apps/permission/api/views.py @@ -32,4 +32,4 @@ class RoleViewSet(ReadOnlyProtectedModelViewSet): serializer_class = RoleSerializer filter_backends = [DjangoFilterBackend, SearchFilter] filterset_fields = ['name', 'permissions', 'for_club', 'memberships__user', ] - SearchFilter = ['$name', '$for_club__name', ] + search_fields = ['$name', '$for_club__name', ] diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/img/graphs/activity.svg b/docs/_static/img/graphs/activity.svg new file mode 100644 index 00000000..22971f1e --- /dev/null +++ b/docs/_static/img/graphs/activity.svg @@ -0,0 +1,344 @@ + + + + + + +model_graph + + + +activity_models_ActivityType + + +     +    ActivityType     +     +id +     +     +AutoField +     +     +can_invite +     +     +BooleanField +     +     +guest_entry_fee +     +     +PositiveIntegerField +     +     +manage_entries +     +     +BooleanField +     +     +name +     +     +CharField +     + + + + +activity_models_Activity + + +     +    Activity     +     +id +     +     +AutoField +     +     +activity_type +     +     +ForeignKey (id) +     +     +attendees_club +     +     +ForeignKey (id) +     +     +creater +     +     +ForeignKey (id) +     +     +organizer +     +     +ForeignKey (id) +     +     +date_end +     +     +DateTimeField +     +     +date_start +     +     +DateTimeField +     +     +description +     +     +TextField +     +     +location +     +     +CharField +     +     +name +     +     +CharField +     +     +open +     +     +BooleanField +     +     +valid +     +     +BooleanField +     + + + + +activity_models_Activity->activity_models_ActivityType + + + activity_type (+) + + + +django_contrib_auth_models_User + + +   +User +   + + + +activity_models_Activity->django_contrib_auth_models_User + + + creater (activity) + + + +member_models_Club + + +   +Club +   + + + +activity_models_Activity->member_models_Club + + + organizer (+) + + + +activity_models_Activity->member_models_Club + + + attendees_club (+) + + + +activity_models_Entry + + +     +    Entry     +     +id +     +     +AutoField +     +     +activity +     +     +ForeignKey (id) +     +     +guest +     +     +OneToOneField (id) +     +     +note +     +     +ForeignKey (note_ptr) +     +     +time +     +     +DateTimeField +     + + + + +activity_models_Entry->activity_models_Activity + + + activity (entries) + + + +activity_models_Guest + + +     +    Guest     +     +id +     +     +AutoField +     +     +activity +     +     +ForeignKey (id) +     +     +inviter +     +     +ForeignKey (note_ptr) +     +     +first_name +     +     +CharField +     +     +last_name +     +     +CharField +     + + + + +activity_models_Entry->activity_models_Guest + + guest (entry) + + + +note_models_notes_NoteUser + + +   +NoteUser +   + + + +activity_models_Entry->note_models_notes_NoteUser + + + note (entry) + + + +activity_models_Guest->activity_models_Activity + + + activity (+) + + + +activity_models_Guest->note_models_notes_NoteUser + + + inviter (guests) + + + +activity_models_GuestTransaction + + +     +    GuestTransaction     +     +transaction_ptr +     +     +OneToOneField (id) +     +     +entry +     +     +OneToOneField (id) +     + + + + +activity_models_GuestTransaction->activity_models_Entry + + entry (guesttransaction) + + + +note_models_transactions_Transaction + + +   +Transaction +   + + + +activity_models_GuestTransaction->note_models_transactions_Transaction + + + multi-table +inheritance + + + diff --git a/docs/_static/img/graphs/logs.svg b/docs/_static/img/graphs/logs.svg new file mode 100644 index 00000000..e451eda4 --- /dev/null +++ b/docs/_static/img/graphs/logs.svg @@ -0,0 +1,108 @@ + + + + + + +model_graph + + + +logs_models_Changelog + + +     +    Changelog     +     +id +     +     +AutoField +     +     +model +     +     +ForeignKey (id) +     +     +user +     +     +ForeignKey (id) +     +     +action +     +     +CharField +     +     +data +     +     +TextField +     +     +instance_pk +     +     +CharField +     +     +ip +     +     +GenericIPAddressField +     +     +previous +     +     +TextField +     +     +timestamp +     +     +DateTimeField +     + + + + +django_contrib_auth_models_User + + +   +User +   + + + +logs_models_Changelog->django_contrib_auth_models_User + + + user (changelog) + + + +django_contrib_contenttypes_models_ContentType + + +   +ContentType +   + + + +logs_models_Changelog->django_contrib_contenttypes_models_ContentType + + + model (changelog) + + + diff --git a/docs/_static/img/graphs/member.svg b/docs/_static/img/graphs/member.svg new file mode 100644 index 00000000..9057b40c --- /dev/null +++ b/docs/_static/img/graphs/member.svg @@ -0,0 +1,279 @@ + + + + + + +model_graph + + + +member_models_Profile + + +     +    Profile     +     +id +     +     +AutoField +     +     +user +     +     +OneToOneField (id) +     +     +address +     +     +CharField +     +     +department +     +     +CharField +     +     +email_confirmed +     +     +BooleanField +     +     +last_report +     +     +DateTimeField +     +     +ml_art_registration +     +     +BooleanField +     +     +ml_events_registration +     +     +CharField +     +     +ml_sport_registration +     +     +BooleanField +     +     +paid +     +     +BooleanField +     +     +phone_number +     +     +PhoneNumberField +     +     +promotion +     +     +PositiveSmallIntegerField +     +     +registration_valid +     +     +BooleanField +     +     +report_frequency +     +     +PositiveSmallIntegerField +     +     +section +     +     +CharField +     + + + + +django_contrib_auth_models_User + + +   +User +   + + + +member_models_Profile->django_contrib_auth_models_User + + user (profile) + + + +member_models_Club + + +     +    Club     +     +id +     +     +AutoField +     +     +parent_club +     +     +ForeignKey (id) +     +     +email +     +     +EmailField +     +     +membership_duration +     +     +PositiveIntegerField +     +     +membership_end +     +     +DateField +     +     +membership_fee_paid +     +     +PositiveIntegerField +     +     +membership_fee_unpaid +     +     +PositiveIntegerField +     +     +membership_start +     +     +DateField +     +     +name +     +     +CharField +     +     +require_memberships +     +     +BooleanField +     + + + + +member_models_Club->member_models_Club + + + parent_club (club) + + + +member_models_Membership + + +     +    Membership     +     +id +     +     +AutoField +     +     +club +     +     +ForeignKey (id) +     +     +user +     +     +ForeignKey (id) +     +     +date_end +     +     +DateField +     +     +date_start +     +     +DateField +     +     +fee +     +     +PositiveIntegerField +     + + + + +member_models_Membership->member_models_Club + + + club (membership) + + + +member_models_Membership->django_contrib_auth_models_User + + + user (memberships) + + + +permission_models_Role + + +   +Role +   + + + +member_models_Membership->permission_models_Role + + + + roles (membership) + + + diff --git a/docs/_static/img/graphs/note.svg b/docs/_static/img/graphs/note.svg new file mode 100644 index 00000000..ac066243 --- /dev/null +++ b/docs/_static/img/graphs/note.svg @@ -0,0 +1,588 @@ + + + + + + +model_graph + + + +polymorphic_models_PolymorphicModel + + +     +    PolymorphicModel     +     +polymorphic_ctype +     +     +ForeignKey (id) +     + + + + +django_contrib_contenttypes_models_ContentType + + +   +ContentType +   + + + +polymorphic_models_PolymorphicModel->django_contrib_contenttypes_models_ContentType + + + polymorphic_ctype (polymorphic_%(app_label)s.%(class)s_set+) + + + +note_models_notes_Note + + +     +    Note +< +PolymorphicModel +>     +     +id +     +     +AutoField +     +     +polymorphic_ctype +     +     +ForeignKey (id) +     +     +balance +     +     +BigIntegerField +     +     +created_at +     +     +DateTimeField +     +     +display_image +     +     +ImageField +     +     +inactivity_reason +     +     +CharField +     +     +is_active +     +     +BooleanField +     +     +last_negative +     +     +DateTimeField +     + + + + +note_models_notes_Note->polymorphic_models_PolymorphicModel + + + abstract +inheritance + + + +note_models_notes_NoteUser + + +     +    NoteUser     +     +note_ptr +     +     +OneToOneField (id) +     +     +user +     +     +OneToOneField (id) +     + + + + +note_models_notes_NoteUser->note_models_notes_Note + + + multi-table +inheritance + + + +django_contrib_auth_models_User + + +   +User +   + + + +note_models_notes_NoteUser->django_contrib_auth_models_User + + user (note) + + + +note_models_notes_NoteClub + + +     +    NoteClub     +     +note_ptr +     +     +OneToOneField (id) +     +     +club +     +     +OneToOneField (id) +     + + + + +note_models_notes_NoteClub->note_models_notes_Note + + + multi-table +inheritance + + + +member_models_Club + + +   +Club +   + + + +note_models_notes_NoteClub->member_models_Club + + club (note) + + + +note_models_notes_NoteSpecial + + +     +    NoteSpecial     +     +note_ptr +     +     +OneToOneField (id) +     +     +special_type +     +     +CharField +     + + + + +note_models_notes_NoteSpecial->note_models_notes_Note + + + multi-table +inheritance + + + +note_models_notes_Alias + + +     +    Alias     +     +id +     +     +AutoField +     +     +note +     +     +ForeignKey (id) +     +     +name +     +     +CharField +     +     +normalized_name +     +     +CharField +     + + + + +note_models_notes_Alias->note_models_notes_Note + + + note (alias) + + + +note_models_transactions_TemplateCategory + + +     +    TemplateCategory     +     +id +     +     +AutoField +     +     +name +     +     +CharField +     + + + + +note_models_transactions_TransactionTemplate + + +     +    TransactionTemplate     +     +id +     +     +AutoField +     +     +category +     +     +ForeignKey (id) +     +     +destination +     +     +ForeignKey (note_ptr) +     +     +amount +     +     +PositiveIntegerField +     +     +description +     +     +CharField +     +     +display +     +     +BooleanField +     +     +highlighted +     +     +BooleanField +     +     +name +     +     +CharField +     + + + + +note_models_transactions_TransactionTemplate->note_models_notes_NoteClub + + + destination (+) + + + +note_models_transactions_TransactionTemplate->note_models_transactions_TemplateCategory + + + category (templates) + + + +note_models_transactions_Transaction + + +     +    Transaction +< +PolymorphicModel +>     +     +id +     +     +AutoField +     +     +destination +     +     +ForeignKey (id) +     +     +polymorphic_ctype +     +     +ForeignKey (id) +     +     +source +     +     +ForeignKey (id) +     +     +amount +     +     +PositiveIntegerField +     +     +created_at +     +     +DateTimeField +     +     +destination_alias +     +     +CharField +     +     +invalidity_reason +     +     +CharField +     +     +quantity +     +     +PositiveIntegerField +     +     +reason +     +     +CharField +     +     +source_alias +     +     +CharField +     +     +valid +     +     +BooleanField +     + + + + +note_models_transactions_Transaction->polymorphic_models_PolymorphicModel + + + abstract +inheritance + + + +note_models_transactions_Transaction->note_models_notes_Note + + + source (+) + + + +note_models_transactions_Transaction->note_models_notes_Note + + + destination (+) + + + +note_models_transactions_RecurrentTransaction + + +     +    RecurrentTransaction     +     +transaction_ptr +     +     +OneToOneField (id) +     +     +template +     +     +ForeignKey (id) +     + + + + +note_models_transactions_RecurrentTransaction->note_models_transactions_TransactionTemplate + + + template (recurrenttransaction) + + + +note_models_transactions_RecurrentTransaction->note_models_transactions_Transaction + + + multi-table +inheritance + + + +note_models_transactions_SpecialTransaction + + +     +    SpecialTransaction     +     +transaction_ptr +     +     +OneToOneField (id) +     +     +bank +     +     +CharField +     +     +first_name +     +     +CharField +     +     +last_name +     +     +CharField +     + + + + +note_models_transactions_SpecialTransaction->note_models_transactions_Transaction + + + multi-table +inheritance + + + +note_models_transactions_MembershipTransaction + + +     +    MembershipTransaction     +     +transaction_ptr +     +     +OneToOneField (id) +     +     +membership +     +     +OneToOneField (id) +     + + + + +note_models_transactions_MembershipTransaction->note_models_transactions_Transaction + + + multi-table +inheritance + + + +member_models_Membership + + +   +Membership +   + + + +note_models_transactions_MembershipTransaction->member_models_Membership + + membership (transaction) + + + diff --git a/docs/_static/img/graphs/permission.svg b/docs/_static/img/graphs/permission.svg new file mode 100644 index 00000000..e7fd7350 --- /dev/null +++ b/docs/_static/img/graphs/permission.svg @@ -0,0 +1,171 @@ + + + + + + +model_graph + + + +permission_models_PermissionMask + + +     +    PermissionMask     +     +id +     +     +AutoField +     +     +description +     +     +CharField +     +     +rank +     +     +PositiveSmallIntegerField +     + + + + +permission_models_Permission + + +     +    Permission     +     +id +     +     +AutoField +     +     +mask +     +     +ForeignKey (id) +     +     +model +     +     +ForeignKey (id) +     +     +description +     +     +CharField +     +     +field +     +     +CharField +     +     +permanent +     +     +BooleanField +     +     +query +     +     +TextField +     +     +type +     +     +CharField +     + + + + +permission_models_Permission->permission_models_PermissionMask + + + mask (permissions) + + + +django_contrib_contenttypes_models_ContentType + + +   +ContentType +   + + + +permission_models_Permission->django_contrib_contenttypes_models_ContentType + + + model (+) + + + +permission_models_Role + + +     +    Role     +     +id +     +     +AutoField +     +     +for_club +     +     +ForeignKey (id) +     +     +name +     +     +CharField +     + + + + +permission_models_Role->permission_models_Permission + + + + permissions (role) + + + +member_models_Club + + +   +Club +   + + + +permission_models_Role->member_models_Club + + + for_club (role) + + + diff --git a/docs/_static/img/graphs/treasury.svg b/docs/_static/img/graphs/treasury.svg new file mode 100644 index 00000000..c2fca750 --- /dev/null +++ b/docs/_static/img/graphs/treasury.svg @@ -0,0 +1,324 @@ + + + + + + +model_graph + + + +treasury_models_Invoice + + +     +    Invoice     +     +id +     +     +PositiveIntegerField +     +     +acquitted +     +     +BooleanField +     +     +address +     +     +TextField +     +     +bde +     +     +CharField +     +     +date +     +     +DateField +     +     +description +     +     +TextField +     +     +locked +     +     +BooleanField +     +     +name +     +     +CharField +     +     +object +     +     +CharField +     +     +tex +     +     +TextField +     + + + + +treasury_models_Product + + +     +    Product     +     +id +     +     +AutoField +     +     +invoice +     +     +ForeignKey (id) +     +     +amount +     +     +IntegerField +     +     +designation +     +     +CharField +     +     +quantity +     +     +PositiveIntegerField +     + + + + +treasury_models_Product->treasury_models_Invoice + + + invoice (products) + + + +treasury_models_RemittanceType + + +     +    RemittanceType     +     +id +     +     +AutoField +     +     +note +     +     +OneToOneField (note_ptr) +     + + + + +note_models_notes_NoteSpecial + + +   +NoteSpecial +   + + + +treasury_models_RemittanceType->note_models_notes_NoteSpecial + + note (remittancetype) + + + +treasury_models_Remittance + + +     +    Remittance     +     +id +     +     +AutoField +     +     +remittance_type +     +     +ForeignKey (id) +     +     +closed +     +     +BooleanField +     +     +comment +     +     +CharField +     +     +date +     +     +DateTimeField +     + + + + +treasury_models_Remittance->treasury_models_RemittanceType + + + remittance_type (remittance) + + + +treasury_models_SpecialTransactionProxy + + +     +    SpecialTransactionProxy     +     +id +     +     +AutoField +     +     +remittance +     +     +ForeignKey (id) +     +     +transaction +     +     +OneToOneField (transaction_ptr) +     + + + + +treasury_models_SpecialTransactionProxy->treasury_models_Remittance + + + remittance (specialtransactionproxy) + + + +note_models_transactions_SpecialTransaction + + +   +SpecialTransaction +   + + + +treasury_models_SpecialTransactionProxy->note_models_transactions_SpecialTransaction + + transaction (specialtransactionproxy) + + + +treasury_models_SogeCredit + + +     +    SogeCredit     +     +id +     +     +AutoField +     +     +credit_transaction +     +     +OneToOneField (transaction_ptr) +     +     +user +     +     +OneToOneField (id) +     + + + + +treasury_models_SogeCredit->note_models_transactions_SpecialTransaction + + credit_transaction (sogecredit) + + + +django_contrib_auth_models_User + + +   +User +   + + + +treasury_models_SogeCredit->django_contrib_auth_models_User + + user (sogecredit) + + + +note_models_transactions_MembershipTransaction + + +   +MembershipTransaction +   + + + +treasury_models_SogeCredit->note_models_transactions_MembershipTransaction + + + + transactions (_sogecredit_transactions_+) + + + diff --git a/docs/_static/img/graphs/wei.svg b/docs/_static/img/graphs/wei.svg new file mode 100644 index 00000000..8167b426 --- /dev/null +++ b/docs/_static/img/graphs/wei.svg @@ -0,0 +1,603 @@ + + + + + + +model_graph + + + +wei_models_WEIClub + + +     +    WEIClub     +     +club_ptr +     +     +OneToOneField (id) +     +     +date_end +     +     +DateField +     +     +date_start +     +     +DateField +     +     +year +     +     +PositiveIntegerField +     + + + + +member_models_Club + + +     +    Club     +     +id +     +     +AutoField +     +     +parent_club +     +     +ForeignKey (id) +     +     +email +     +     +EmailField +     +     +membership_duration +     +     +PositiveIntegerField +     +     +membership_end +     +     +DateField +     +     +membership_fee_paid +     +     +PositiveIntegerField +     +     +membership_fee_unpaid +     +     +PositiveIntegerField +     +     +membership_start +     +     +DateField +     +     +name +     +     +CharField +     +     +require_memberships +     +     +BooleanField +     + + + + +wei_models_WEIClub->member_models_Club + + + multi-table +inheritance + + + +wei_models_Bus + + +     +    Bus     +     +id +     +     +AutoField +     +     +wei +     +     +ForeignKey (club_ptr) +     +     +description +     +     +TextField +     +     +information_json +     +     +TextField +     +     +name +     +     +CharField +     + + + + +wei_models_Bus->wei_models_WEIClub + + + wei (buses) + + + +wei_models_BusTeam + + +     +    BusTeam     +     +id +     +     +AutoField +     +     +bus +     +     +ForeignKey (id) +     +     +color +     +     +PositiveIntegerField +     +     +description +     +     +TextField +     +     +name +     +     +CharField +     + + + + +wei_models_BusTeam->wei_models_Bus + + + bus (teams) + + + +wei_models_WEIRole + + +     +    WEIRole     +     +role_ptr +     +     +OneToOneField (id) +     + + + + +permission_models_Role + + +   +Role +   + + + +wei_models_WEIRole->permission_models_Role + + + multi-table +inheritance + + + +wei_models_WEIRegistration + + +     +    WEIRegistration     +     +id +     +     +AutoField +     +     +user +     +     +ForeignKey (id) +     +     +wei +     +     +ForeignKey (club_ptr) +     +     +birth_date +     +     +DateField +     +     +caution_check +     +     +BooleanField +     +     +clothing_cut +     +     +CharField +     +     +clothing_size +     +     +CharField +     +     +emergency_contact_name +     +     +CharField +     +     +emergency_contact_phone +     +     +PhoneNumberField +     +     +first_year +     +     +BooleanField +     +     +gender +     +     +CharField +     +     +health_issues +     +     +TextField +     +     +information_json +     +     +TextField +     +     +soge_credit +     +     +BooleanField +     + + + + +wei_models_WEIRegistration->wei_models_WEIClub + + + wei (users) + + + +django_contrib_auth_models_User + + +   +User +   + + + +wei_models_WEIRegistration->django_contrib_auth_models_User + + + user (wei) + + + +wei_models_WEIMembership + + +     +    WEIMembership     +     +membership_ptr +     +     +OneToOneField (id) +     +     +bus +     +     +ForeignKey (id) +     +     +registration +     +     +OneToOneField (id) +     +     +team +     +     +ForeignKey (id) +     + + + + +wei_models_WEIMembership->wei_models_Bus + + + bus (memberships) + + + +wei_models_WEIMembership->wei_models_BusTeam + + + team (memberships) + + + +wei_models_WEIMembership->wei_models_WEIRegistration + + registration (membership) + + + +member_models_Membership + + +     +    Membership     +     +id +     +     +AutoField +     +     +club +     +     +ForeignKey (id) +     +     +user +     +     +ForeignKey (id) +     +     +date_end +     +     +DateField +     +     +date_start +     +     +DateField +     +     +fee +     +     +PositiveIntegerField +     + + + + +wei_models_WEIMembership->member_models_Membership + + + multi-table +inheritance + + + +member_models_Profile + + +     +    Profile     +     +id +     +     +AutoField +     +     +user +     +     +OneToOneField (id) +     +     +address +     +     +CharField +     +     +department +     +     +CharField +     +     +email_confirmed +     +     +BooleanField +     +     +last_report +     +     +DateTimeField +     +     +ml_art_registration +     +     +BooleanField +     +     +ml_events_registration +     +     +CharField +     +     +ml_sport_registration +     +     +BooleanField +     +     +paid +     +     +BooleanField +     +     +phone_number +     +     +PhoneNumberField +     +     +promotion +     +     +PositiveSmallIntegerField +     +     +registration_valid +     +     +BooleanField +     +     +report_frequency +     +     +PositiveSmallIntegerField +     +     +section +     +     +CharField +     + + + + +member_models_Profile->django_contrib_auth_models_User + + user (profile) + + + +member_models_Club->member_models_Club + + + parent_club (club) + + + +member_models_Membership->member_models_Club + + + club (membership) + + + +member_models_Membership->permission_models_Role + + + + roles (membership) + + + +member_models_Membership->django_contrib_auth_models_User + + + user (memberships) + + + diff --git a/docs/_static/img/treasury_validate_sogecredit.png b/docs/_static/img/treasury_validate_sogecredit.png new file mode 100644 index 00000000..2902c870 Binary files /dev/null and b/docs/_static/img/treasury_validate_sogecredit.png differ diff --git a/docs/api/activity.rst b/docs/api/activity.rst new file mode 100644 index 00000000..99e730e5 --- /dev/null +++ b/docs/api/activity.rst @@ -0,0 +1,370 @@ +API Activités +============= + +Activité +-------- + +**Chemin :** `/api/activity/activity/ `_ + +Options +~~~~~~~ + +.. code:: json + + { + "name": "Activity List", + "description": "REST API View set.\nThe djangorestframework plugin will get all `Activity` objects, serialize it to JSON with the given serializer,\nthen render it on /api/activity/activity/", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "actions": { + "POST": { + "id": { + "type": "integer", + "required": false, + "read_only": true, + "label": "ID" + }, + "name": { + "type": "string", + "required": true, + "read_only": false, + "label": "Nom", + "max_length": 255 + }, + "description": { + "type": "string", + "required": true, + "read_only": false, + "label": "Description" + }, + "location": { + "type": "string", + "required": false, + "read_only": false, + "label": "Lieu", + "help_text": "Lieu o\u00f9 l'activit\u00e9 est organis\u00e9e, par exemple la Kfet.", + "max_length": 255 + }, + "date_start": { + "type": "datetime", + "required": true, + "read_only": false, + "label": "Date de d\u00e9but" + }, + "date_end": { + "type": "datetime", + "required": true, + "read_only": false, + "label": "Date de fin" + }, + "valid": { + "type": "boolean", + "required": false, + "read_only": false, + "label": "Valide" + }, + "open": { + "type": "boolean", + "required": false, + "read_only": false, + "label": "Ouvrir" + }, + "activity_type": { + "type": "field", + "required": true, + "read_only": false, + "label": "Type" + }, + "creater": { + "type": "field", + "required": true, + "read_only": false, + "label": "Utilisateur" + }, + "organizer": { + "type": "field", + "required": true, + "read_only": false, + "label": "Organisateur", + "help_text": "Le club qui organise l'activit\u00e9. Les co\u00fbts d'invitation iront pour ce club." + }, + "attendees_club": { + "type": "field", + "required": true, + "read_only": false, + "label": "Club attendu", + "help_text": "Club qui est autoris\u00e9 \u00e0 rejoindre l'activit\u00e9. Tr\u00e8s souvent le club Kfet." + } + } + } + } + +Filtres Django +~~~~~~~~~~~~~~ + +* ``name`` +* ``description`` +* ``activity_type`` +* ``location`` +* ``creater`` +* ``organizer`` +* ``attendees_club`` +* ``date_start`` +* ``date_end`` +* ``valid`` +* ``open`` + +Filtres de recherche +~~~~~~~~~~~~~~~~~~~~ + +* ``name`` (expression régulière) +* ``description`` (expression régulière) +* ``location`` (expression régulière) +* ``creater__last_name`` (expression régulière) +* ``creater__first_name`` (expression régulière) +* ``creater__email`` (expression régulière) +* ``creater__note__alias__name`` (expression régulière) +* ``creater__note__alias__normalized_name`` (expression régulière) +* ``organizer__name`` (expression régulière) +* ``organizer__email`` (expression régulière) +* ``organizer__note__alias__name`` (expression régulière) +* ``organizer__note__alias__normalized_name`` (expression régulière) +* ``attendees_club__name`` (expression régulière) +* ``attendees_club__email`` (expression régulière) +* ``attendees_club__note__alias__name`` (expression régulière) +* ``attendees_club__note__alias__normalized_name`` (expression régulière) + +Type d'activité +--------------- + +**Chemin :** `/api/activity/type/ `_ + +Options +~~~~~~~ + +.. code:: json + + { + "name": "Activity Type List", + "description": "REST API View set.\nThe djangorestframework plugin will get all `ActivityType` objects, serialize it to JSON with the given serializer,\nthen render it on /api/activity/type/", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "actions": { + "POST": { + "id": { + "type": "integer", + "required": false, + "read_only": true, + "label": "ID" + }, + "name": { + "type": "string", + "required": true, + "read_only": false, + "label": "Nom", + "max_length": 255 + }, + "manage_entries": { + "type": "boolean", + "required": false, + "read_only": false, + "label": "G\u00e9rer les entr\u00e9es", + "help_text": "Activer le support des entr\u00e9es pour cette activit\u00e9." + }, + "can_invite": { + "type": "boolean", + "required": false, + "read_only": false, + "label": "Peut inviter" + }, + "guest_entry_fee": { + "type": "integer", + "required": false, + "read_only": false, + "label": "Cotisation de l'entr\u00e9e invit\u00e9", + "min_value": 0, + "max_value": 2147483647 + } + } + } + } + +Filtres Django +~~~~~~~~~~~~~~ + +* ``name`` +* ``manage_entries`` +* ``can_invite`` +* ``guest_entry_fee`` + +Invité +------ + +**Chemin :** `/api/activity/guest/ `_ + +Options +~~~~~~~ + +.. code:: json + + { + "name": "Guest List", + "description": "REST API View set.\nThe djangorestframework plugin will get all `Guest` objects, serialize it to JSON with the given serializer,\nthen render it on /api/activity/guest/", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "actions": { + "POST": { + "id": { + "type": "integer", + "required": false, + "read_only": true, + "label": "ID" + }, + "last_name": { + "type": "string", + "required": true, + "read_only": false, + "label": "Nom de famille", + "max_length": 255 + }, + "first_name": { + "type": "string", + "required": true, + "read_only": false, + "label": "Pr\u00e9nom", + "max_length": 255 + }, + "activity": { + "type": "field", + "required": true, + "read_only": false, + "label": "Activity" + }, + "inviter": { + "type": "field", + "required": true, + "read_only": false, + "label": "H\u00f4te" + } + } + } + } + +Filtres Django +~~~~~~~~~~~~~~ + +* ``activity`` +* ``activity__name`` +* ``last_name`` +* ``first_name`` +* ``inviter`` +* ``inviter__alias__name`` +* ``inviter__alias__normalized_name`` + +Filtres de recherche +~~~~~~~~~~~~~~~~~~~~ + +* ``activity__name`` (expression régulière) +* ``last_name`` (expression régulière) +* ``first_name`` (expression régulière) +* ``inviter__user__email`` (expression régulière) +* ``inviter__alias__name`` (expression régulière) +* ``inviter__alias__normalized_name`` (expression régulière) + +Entrée +------ + +**Chemin :** `/api/activity/entry/ `_ + +Options +~~~~~~~ + +.. code:: json + + { + "name": "Entry List", + "description": "REST API View set.\nThe djangorestframework plugin will get all `Entry` objects, serialize it to JSON with the given serializer,\nthen render it on /api/activity/entry/", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "actions": { + "POST": { + "id": { + "type": "integer", + "required": false, + "read_only": true, + "label": "ID" + }, + "time": { + "type": "datetime", + "required": false, + "read_only": false, + "label": "Heure d'entr\u00e9e" + }, + "activity": { + "type": "field", + "required": true, + "read_only": false, + "label": "Activit\u00e9" + }, + "note": { + "type": "field", + "required": true, + "read_only": false, + "label": "Note" + }, + "guest": { + "type": "field", + "required": true, + "read_only": false, + "label": "Guest" + } + } + } + } + +Filtres Django +~~~~~~~~~~~~~~ + +* ``activity`` +* ``time`` +* ``note`` +* ``guest`` + +Filtres de recherche +~~~~~~~~~~~~~~~~~~~~ + +* ``activity__name`` (expression régulière) +* ``note__user__email`` (expression régulière) +* ``note__alias__name`` (expression régulière) +* ``note__alias__normalized_name`` (expression régulière) +* ``guest__last_name`` (expression régulière) +* ``guest__first_name`` (expression régulière) + diff --git a/docs/api/basic.rst b/docs/api/basic.rst new file mode 100644 index 00000000..6e5ced76 --- /dev/null +++ b/docs/api/basic.rst @@ -0,0 +1,157 @@ +API générale +============ + +Utilisateur +----------- + +**Chemin :** `/api/user/ `_ + +Options +~~~~~~~ + +.. code:: json + + { + "name": "User List", + "description": "REST API View set.\nThe djangorestframework plugin will get all `User` objects, serialize it to JSON with the given serializer,\nthen render it on /api/user/", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "actions": { + "POST": { + "id": { + "type": "integer", + "required": false, + "read_only": true, + "label": "ID" + }, + "last_login": { + "type": "datetime", + "required": false, + "read_only": false, + "label": "Derni\u00e8re connexion" + }, + "is_superuser": { + "type": "boolean", + "required": false, + "read_only": false, + "label": "Statut super-utilisateur", + "help_text": "Pr\u00e9cise que l'utilisateur poss\u00e8de toutes les permissions sans les assigner explicitement." + }, + "username": { + "type": "string", + "required": true, + "read_only": false, + "label": "Pseudo", + "help_text": "Requis. 150 caract\u00e8res maximum. Uniquement des lettres, nombres et les caract\u00e8res \u00ab\u00a0@\u00a0\u00bb, \u00ab\u00a0.\u00a0\u00bb, \u00ab\u00a0+\u00a0\u00bb, \u00ab\u00a0-\u00a0\u00bb et \u00ab\u00a0_\u00a0\u00bb.", + "max_length": 150 + }, + "first_name": { + "type": "string", + "required": false, + "read_only": false, + "label": "Pr\u00e9nom", + "max_length": 30 + }, + "last_name": { + "type": "string", + "required": false, + "read_only": false, + "label": "Nom de famille", + "max_length": 150 + }, + "email": { + "type": "email", + "required": false, + "read_only": false, + "label": "Adresse \u00e9lectronique", + "max_length": 254 + }, + "is_staff": { + "type": "boolean", + "required": false, + "read_only": false, + "label": "Statut \u00e9quipe", + "help_text": "Pr\u00e9cise si l'utilisateur peut se connecter \u00e0 ce site d'administration." + }, + "is_active": { + "type": "boolean", + "required": false, + "read_only": false, + "label": "Actif", + "help_text": "Pr\u00e9cise si l'utilisateur doit \u00eatre consid\u00e9r\u00e9 comme actif. D\u00e9cochez ceci plut\u00f4t que de supprimer le compte." + }, + "date_joined": { + "type": "datetime", + "required": false, + "read_only": false, + "label": "Date d'inscription" + } + } + } + } + +Filtres Django +~~~~~~~~~~~~~~ + +* ``id`` +* ``username`` +* ``first_name`` +* ``last_name`` +* ``email`` +* ``is_superuser`` +* ``is_staff`` +* ``is_active`` +* ``note__alias__name`` +* ``note__alias__normalized_name`` + +Filtres de recherche +~~~~~~~~~~~~~~~~~~~~ + +* ``note__alias`` (expression régulière, cherche en priorité les alias les plus proches, puis cherche les alias normalisés) +* ``last_name`` (expression régulière) +* ``first_name`` (expression régulière) + +Type de contenu +--------------- + +**Chemin :** `/api/models/ `_ + +Options +~~~~~~~ + +.. code:: json + + { + "name": "Content Type List", + "description": "REST API View set.\nThe djangorestframework plugin will get all `User` objects, serialize it to JSON with the given serializer,\nthen render it on /api/models/", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ] + } + +Filtres Django +~~~~~~~~~~~~~~ + +* ``id`` +* ``app_label`` +* ``model`` + +Filtres de recherche +~~~~~~~~~~~~~~~~~~~~ + +* ``app_label`` (expression régulière) +* ``model`` (expression régulière) + diff --git a/docs/api/index.rst b/docs/api/index.rst new file mode 100644 index 00000000..32068d88 --- /dev/null +++ b/docs/api/index.rst @@ -0,0 +1,214 @@ +API +=== + +.. toctree:: + :maxdepth: 2 + :caption: Applications + + activity + basic + logs + member + note + permission + treasury + wei + +La NoteKfet2020 dispose d'une API REST. Elle est accessible sur `/api/ `_. +Elle supporte les requêtes GET, POST, HEAD, PUT, PATCH et DELETE (peut varier selon les pages). + +Pages de l'API +-------------- + +Il suffit d'ajouter le préfixe ``/api/`` pour arriver sur ces pages. + +* `models `_ : liste des différents modèles enregistrés en base de données +* `user `_ : liste des différents utilisateurs enregistrés +* `members/profile `_ : liste des différents profils associés à des utilisateurs +* `members/club `_ : liste des différents clubs enregistrés +* `members/membership `_ : liste des adhésions enregistrées +* `activity/activity `_ : liste des activités recensées +* `activity/type `_ : liste des différents types d'activités : pots, soirées de club, ... +* `activity/guest `_ : liste des personnes invitées lors d'une activité +* `activity/entry `_ : liste des entrées effectuées lors des activités +* `note/note `_ : liste des notes enregistrées +* `note/alias `_ : liste des alias enregistrés +* `note/consumer `_ : liste des alias enregistrés avec leur note associée +* `note/transaction/category `_ : liste des différentes catégories de boutons : soft, alcool, ... +* `note/transaction/transaction `_ : liste des transactions effectuées +* `note/transaction/template `_ : liste des boutons enregistrés +* `treasury/invoice `_ : liste des factures générées +* `treasury/product `_ : liste des produits associés à des factures +* `treasury/remittance_type `_ : liste des types de remises supportés : chèque +* `treasury/remittance `_ : liste des différentes remises enregistrées +* `treasury/remittance `_ : liste des crédits de la Société générale enregistrés +* `permission/permission `_ : liste de toutes les permissions enregistrées +* `permission/roles `_ : liste des permissions octroyées pour chacun des rôles +* `logs `_ : liste des modifications enregistrées en base de données +* `wei/club `_ : liste des WEI +* `wei/bus `_ : liste des bus de tous les WEI +* `wei/team `_ : liste des équipes de tous les WEI +* `wei/role `_ : liste des rôles possibles pour le WEI +* `wei/registration `_ : liste de toutes les inscriptions à un WEI +* `wei/membership `_ : liste des adhésions compètes à un WEI + +Utilisation de l'API +-------------------- + +La page ``/api//`` affiche la liste de tous les éléments enregistrés. La page ``/api///`` affiche +les attributs d'un objet uniquement. + +L'affichage des données peut se faire sous deux formes : via une interface HTML propre ou directement en affichant +le JSON brut. Le changement peut se faire en ajoutant en paramètre de l'URL ``format=json`` ou ``format=api``, ou bien +en plaçant en en-tête de la requête ``Accept: application/json`` ou ``Accept: text/html``. + +L'API Web propose des formulaires facilitant l'ajout et la modification d'éléments. + +S'authentifier +~~~~~~~~~~~~~~ + +L'authentification peut se faire soit par session en se connectant via la page de connexion classique, +soit via un jeton d'authentification. Le jeton peut se récupérer via la page de son propre compte, en cliquant +sur le bouton « `Accès API `_ ». Il peut être révoqué et regénéré +en un clic. + +Pour s'authentifier via ce jeton, il faut ajouter l'en-tête ``Authorization: Token `` aux paramètres HTTP. + +En s'authentifiant par cette méthode, les masques de droit sont ignorés, les droits maximaux sont accordés. + +GET +~~~ + +Une requête GET affiche un ou des éléments. Si on veut la liste de tous les éléments d'un modèle, la réponse +est de cette forme : + +.. code:: json + + { + "count": "", + "next": "/api//?page=", + "previous": "/api//?page=", + "results": [ ] + } + +Où ```` est le nombre d'éléments trouvés. La page n'affiche les informations que 20 par 20 pour ne pas +augmenter inutilement la taille de la réponse. Les champs ``next`` et ``previous`` contiennent les URL des pages +suivantes et précédentes (``null`` si première ou dernière page). Le champ ``results`` contient enfin l'ensemble des +objets trouvés, au format JSON. + +Certaines pages disposent de filtres, permettant de sélectionner les objets recherchés. Par exemple, il est possible +de chercher une note d'un certain type matchant avec un certain alias. + +Trois types de filtres sont implémentés : + +* Les filtres Django, permettant d'ajouter ``?key=value`` dans l'URL pour filtrer les objets ayant ``value`` comme + valeur pour la clé ``key`` ; +* Les filtres de recherche, permettant une recherche plus souple notamment par expressions régulières ou contenance, + et permet aussi de chercher parmi plusieurs clés à partir d'un champ ``search`` dans l'URL ; +* Les filtres de tri, qui ne filtrent pas réellement mais changent l'ordre. En ajoutant ``?ordering=key`` dans l'URL, + on trie les résultats selon la clé ``key`` dans l'ordre croissant, et ``?ordering=-key`` trie dans l'ordre + décroissant. + +Les filtres disponibles sont indiqués sur chacune des pages de documentation. + +Le résultat est déjà par défaut filtré par droits : seuls les éléments que l'utilisateur à le droit de voir sont affichés. +Cela est possible grâce à la structure des permissions, générant justement des filtres de requêtes de base de données. + +Une requête à l'adresse ``/api//pk/`` affiche directement les informations du modèle demandé au format JSON. + +POST +~~~~ + +Une requête POST permet d'ajouter des éléments. Cette requête n'est possible que sur la page ``/api//``, +la requête POST n'est pas supportée sur les pages de détails (car cette requête permet ... l'ajout). + +Des exceptions sont faites sur certaines pages : les pages de logs et de contenttypes sont en lecture uniquement. + +Les formats supportés sont multiples : ``application/json``, ``application/x-www-url-encoded``, ``multipart/form-data``. +Cela facilite l'envoi de requêtes. Le module construit ensuite l'instance du modèle et le sauvegarde dans la base de +données. L'application ``permission`` s'assure que l'utilisateur à le droit de faire ce type de modification. La réponse +renvoyée est l'objet enregistré au format JSON si l'ajout s'est bien déroulé, sinon un message d'erreur au format JSON. + +PATCH +~~~~~ + +Une requête PATCH permet de modifier un élément. Ce type de requête n'est disponible que sur la page de détails d'un +élément : ``/api//pk/``. + +Comme pour la requête POST, les formats supportés sont multiples : ``application/json``, +``application/x-www-url-encoded``, ``multipart/form-data``. + +Il n'est pas utile d'indiquer tous les champs du modèle : seuls ceux qui sont à modifier suffisent. + +Attention : pour les modèles polymorphiques (``Note``, ``Transaction``), il faut toujours spécifier le type de modèle +pour que l'API arrive à s'y retrouver. Par exemple, si on veut rendre la transaction n°42 non valide, on effectue une +requête ``PATCH`` sur ``/api/note/transaction/transaction/42/`` avec les données suivantes : + +.. code:: json + + { + "valid": false, + "resourcetype": "RecurrentTransaction" + } + +PUT +~~~ + +Une requête PUT permet de remplacer un élément. Ce type de requête n'est disponible que sur la page de détails d'un +élément : ``/api//pk/``. + +Comme pour les requêtes POST ou PATCH, les formats supportés sont multiples : ``application/json``, +``application/x-www-url-encoded``, ``multipart/form-data``. + +Contrairement à la requête PATCH, l'intégralité du modèle est remplacé. L'ancien modèle est détruit, on en recrée un +nouveau avec la même clé primaire. Le fonctionnement est similaire à une requête POST. + +DELETE +~~~~~~ + +Une requête de type DELETE permet de supprimer un élément. Ce type de requête n'est disponible que sur la page de +détails d'un élément : ``/api//pk/``. + +Aucune donnée n'est nécessaire. Le module de permissions vérifiera que la suppression est possible. Une erreur +est sinon renvoyée. + +OPTIONS +~~~~~~~ + +Une reqête OPTIONS affiche l'ensemble des opérations possibles sur un modèle ou une instance. Prototype d'une réponse : + +.. code:: json + + { + "name": "", + "description": "", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "actions": { + "": { + "": { + "type": "", + "required": "", + "read_only": "", + "label": "