mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	Creation of "Opener", Fix #117
This commit is contained in:
		@@ -1,9 +1,11 @@
 | 
			
		||||
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
from rest_framework.validators import UniqueTogetherValidator
 | 
			
		||||
 | 
			
		||||
from ..models import Activity, ActivityType, Entry, Guest, GuestTransaction
 | 
			
		||||
from ..models import Activity, ActivityType, Entry, Guest, GuestTransaction, Opener
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityTypeSerializer(serializers.ModelSerializer):
 | 
			
		||||
@@ -59,3 +61,17 @@ class GuestTransactionSerializer(serializers.ModelSerializer):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = GuestTransaction
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OpenerSerializer(serializers.ModelSerializer):
 | 
			
		||||
    """
 | 
			
		||||
    REST API Serializer for Openers.
 | 
			
		||||
    The djangorestframework plugin will analyse the model `Opener` and parse all fields in the API.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Opener
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
        validators = [UniqueTogetherValidator(
 | 
			
		||||
            queryset=Opener.objects.all(), fields=("opener", "activity"),
 | 
			
		||||
            message=_("This opener already exists"))]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from .views import ActivityTypeViewSet, ActivityViewSet, EntryViewSet, GuestViewSet
 | 
			
		||||
from .views import ActivityTypeViewSet, ActivityViewSet, EntryViewSet, GuestViewSet, OpenerViewSet
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def register_activity_urls(router, path):
 | 
			
		||||
@@ -12,3 +12,4 @@ def register_activity_urls(router, path):
 | 
			
		||||
    router.register(path + '/type', ActivityTypeViewSet)
 | 
			
		||||
    router.register(path + '/guest', GuestViewSet)
 | 
			
		||||
    router.register(path + '/entry', EntryViewSet)
 | 
			
		||||
    router.register(path + '/opener', OpenerViewSet)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,14 @@
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from api.viewsets import ReadProtectedModelViewSet
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django_filters.rest_framework import DjangoFilterBackend
 | 
			
		||||
from rest_framework.filters import SearchFilter
 | 
			
		||||
from rest_framework.response import Response
 | 
			
		||||
from rest_framework import status
 | 
			
		||||
 | 
			
		||||
from .serializers import ActivitySerializer, ActivityTypeSerializer, EntrySerializer, GuestSerializer
 | 
			
		||||
from ..models import Activity, ActivityType, Entry, Guest
 | 
			
		||||
from .serializers import ActivitySerializer, ActivityTypeSerializer, EntrySerializer, GuestSerializer, OpenerSerializer
 | 
			
		||||
from ..models import Activity, ActivityType, Entry, Guest, Opener
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityTypeViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
@@ -66,3 +69,32 @@ class EntryViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
    filterset_fields = ['activity', 'time', 'note', 'guest', ]
 | 
			
		||||
    search_fields = ['$activity__name', '$note__user__email', '$note__alias__name', '$note__alias__normalized_name',
 | 
			
		||||
                     '$guest__last_name', '$guest__first_name', ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OpenerViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
    """
 | 
			
		||||
    REST Opener View set.
 | 
			
		||||
    The djangorestframework plugin will get all `Opener` objects, serialize it to JSON with the given serializer,
 | 
			
		||||
    then render it on /api/activity/opener/
 | 
			
		||||
    """
 | 
			
		||||
    queryset = Opener.objects
 | 
			
		||||
    serializer_class = OpenerSerializer
 | 
			
		||||
    filter_backends = [SearchFilter, DjangoFilterBackend]
 | 
			
		||||
    search_fields = ['$opener__alias__name', '$opener__alias__normalized_name',
 | 
			
		||||
                     '$activity__name']
 | 
			
		||||
    filterset_fields = ['opener', 'opener__noteuser__user', 'activity']
 | 
			
		||||
 | 
			
		||||
    def get_serializer_class(self):
 | 
			
		||||
        serializer_class = self.serializer_class
 | 
			
		||||
        if self.request.method in ['PUT', 'PATCH']:
 | 
			
		||||
            # opener-activity can't change
 | 
			
		||||
            serializer_class.Meta.read_only_fields = ('opener', 'acitivity',)
 | 
			
		||||
        return serializer_class
 | 
			
		||||
 | 
			
		||||
    def destroy(self, request, *args, **kwargs):
 | 
			
		||||
        instance = self.get_object()
 | 
			
		||||
        try:
 | 
			
		||||
            self.perform_destroy(instance)
 | 
			
		||||
        except ValidationError as e:
 | 
			
		||||
            return Response({e.code: str(e)}, status.HTTP_400_BAD_REQUEST)
 | 
			
		||||
        return Response(status=status.HTTP_204_NO_CONTENT)
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ class ActivityForm(forms.ModelForm):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Activity
 | 
			
		||||
        exclude = ('creater', 'valid', 'open', )
 | 
			
		||||
        exclude = ('creater', 'valid', 'open', 'opener', )
 | 
			
		||||
        widgets = {
 | 
			
		||||
            "organizer": Autocomplete(
 | 
			
		||||
                model=Club,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								apps/activity/migrations/0004_opener.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								apps/activity/migrations/0004_opener.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
# Generated by Django 2.2.28 on 2024-08-01 12:36
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('note', '0006_trust'),
 | 
			
		||||
        ('activity', '0003_auto_20240323_1422'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='Opener',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('activity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opener', to='activity.Activity', verbose_name='activity')),
 | 
			
		||||
                ('opener', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activity_responsible', to='note.Note', verbose_name='opener')),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                'verbose_name': 'opener',
 | 
			
		||||
                'verbose_name_plural': 'openers',
 | 
			
		||||
                'unique_together': {('opener', 'activity')},
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -11,7 +11,7 @@ from django.db import models, transaction
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from note.models import NoteUser, Transaction
 | 
			
		||||
from note.models import NoteUser, Transaction, Note
 | 
			
		||||
from rest_framework.exceptions import ValidationError
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -310,3 +310,31 @@ class GuestTransaction(Transaction):
 | 
			
		||||
    @property
 | 
			
		||||
    def type(self):
 | 
			
		||||
        return _('Invitation')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Opener(models.Model):
 | 
			
		||||
    """
 | 
			
		||||
    Allow the user to make activity entries without more rights
 | 
			
		||||
    """
 | 
			
		||||
    activity = models.ForeignKey(
 | 
			
		||||
        Activity,
 | 
			
		||||
        on_delete=models.CASCADE,
 | 
			
		||||
        related_name='opener',
 | 
			
		||||
        verbose_name=_('activity')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    opener = models.ForeignKey(
 | 
			
		||||
        Note,
 | 
			
		||||
        on_delete=models.CASCADE,
 | 
			
		||||
        related_name='activity_responsible',
 | 
			
		||||
        verbose_name=_('Opener')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _("Opener")
 | 
			
		||||
        verbose_name_plural = _("Openers")
 | 
			
		||||
        unique_together = ("opener", "activity")
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return _("{opener} is opener of activity {acivity}").format(
 | 
			
		||||
            opener=str(self.opener), acivity=str(self.activity))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								apps/activity/static/activity/js/opener.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								apps/activity/static/activity/js/opener.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
/**
 | 
			
		||||
 * On form submit, create a new friendship
 | 
			
		||||
 */
 | 
			
		||||
function form_create_opener (e) {
 | 
			
		||||
  // Do not submit HTML form
 | 
			
		||||
  e.preventDefault()
 | 
			
		||||
 | 
			
		||||
  // Get data and send to API
 | 
			
		||||
  const formData = new FormData(e.target)
 | 
			
		||||
  $.getJSON('/api/note/alias/'+formData.get('opener') + '/',
 | 
			
		||||
    function (opener_alias) {
 | 
			
		||||
      create_opener(formData.get('activity'), opener_alias.note)
 | 
			
		||||
    }).fail(function (xhr, _textStatus, _error) {
 | 
			
		||||
        errMsg(xhr.responseJSON)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create a trust between users
 | 
			
		||||
 * @param trusting:Integer trusting note id
 | 
			
		||||
 * @param trusted:Integer trusted note id
 | 
			
		||||
 */
 | 
			
		||||
function create_opener(activity, opener) {
 | 
			
		||||
  $.post('/api/activity/opener/', {
 | 
			
		||||
      activity: activity,
 | 
			
		||||
      opener: opener,
 | 
			
		||||
      csrfmiddlewaretoken: CSRF_TOKEN
 | 
			
		||||
  }).done(function () {
 | 
			
		||||
  // Reload tables
 | 
			
		||||
  $('#opener_table').load(location.pathname + ' #opener_table')
 | 
			
		||||
    addMsg(gettext('Friendship successfully added'), 'success')
 | 
			
		||||
  }).fail(function (xhr, _textStatus, _error) {
 | 
			
		||||
    errMsg(xhr.responseJSON)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * On form submit, create a new friendship
 | 
			
		||||
function create_opener (e) {
 | 
			
		||||
  // Do not submit HTML form
 | 
			
		||||
  e.preventDefault()
 | 
			
		||||
 | 
			
		||||
  // Get data and send to API
 | 
			
		||||
  const formData = new FormData(e.target)
 | 
			
		||||
  $.post('/api/activity/opener/', {
 | 
			
		||||
    csrfmiddlewaretoken: formData.get('csrfmiddlewaretoken'),
 | 
			
		||||
    activity: formData.get('activity'),
 | 
			
		||||
    opener: formData.get('opener')
 | 
			
		||||
  }).done(function () {
 | 
			
		||||
    // Reload table
 | 
			
		||||
    $('#opener_table').load(location.pathname + ' #opener_table')
 | 
			
		||||
    addMsg(gettext('Alias successfully added'), 'success')
 | 
			
		||||
  }).fail(function (xhr, _textStatus, _error) {
 | 
			
		||||
    errMsg(xhr.responseJSON)
 | 
			
		||||
  })
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * On click of "delete", delete the trust
 | 
			
		||||
 * @param button_id:Integer Trust id to remove
 | 
			
		||||
 */
 | 
			
		||||
function delete_button (button_id) {
 | 
			
		||||
  $.ajax({
 | 
			
		||||
    url: '/api/activity/opener/' + button_id + '/',
 | 
			
		||||
    method: 'DELETE',
 | 
			
		||||
    headers: { 'X-CSRFTOKEN': CSRF_TOKEN }
 | 
			
		||||
  }).done(function () {
 | 
			
		||||
    addMsg(gettext('Friendship successfully deleted'), 'success')
 | 
			
		||||
    $('#opener_table').load(location.pathname + ' #opener_table')
 | 
			
		||||
  }).fail(function (xhr, _textStatus, _error) {
 | 
			
		||||
    errMsg(xhr.responseJSON)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
  // Attach event
 | 
			
		||||
  document.getElementById('form_opener').addEventListener('submit', form_create_opener)
 | 
			
		||||
})
 | 
			
		||||
@@ -5,11 +5,13 @@ from django.utils import timezone
 | 
			
		||||
from django.utils.html import escape
 | 
			
		||||
from django.utils.safestring import mark_safe
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from note_kfet.middlewares import get_current_request
 | 
			
		||||
import django_tables2 as tables
 | 
			
		||||
from django_tables2 import A
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
from note.templatetags.pretty_money import pretty_money
 | 
			
		||||
 | 
			
		||||
from .models import Activity, Entry, Guest
 | 
			
		||||
from .models import Activity, Entry, Guest, Opener
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityTable(tables.Table):
 | 
			
		||||
@@ -113,3 +115,34 @@ class EntryTable(tables.Table):
 | 
			
		||||
            'data-last-name': lambda record: record.last_name,
 | 
			
		||||
            'data-first-name': lambda record: record.first_name,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# function delete_button(id) provided in template file
 | 
			
		||||
DELETE_TEMPLATE = """
 | 
			
		||||
    <button id="{{ record.pk }}" class="btn btn-danger btn-sm" onclick="delete_button(this.id)"> {{ delete_trans }}</button>
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OpenerTable(tables.Table):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        attrs = {
 | 
			
		||||
            'class': 'table table condensed table-striped',
 | 
			
		||||
            'id': "opener_table"
 | 
			
		||||
        }
 | 
			
		||||
        model = Opener
 | 
			
		||||
        fields = ("opener",)
 | 
			
		||||
        template_name = 'django_tables2/bootstrap4.html'
 | 
			
		||||
 | 
			
		||||
    show_header = False
 | 
			
		||||
    opener = tables.Column(attrs={'td': {'class': 'text-center'}})
 | 
			
		||||
 | 
			
		||||
    delete_col = tables.TemplateColumn(
 | 
			
		||||
        template_code=DELETE_TEMPLATE,
 | 
			
		||||
        extra_context={"delete_trans": _('Delete')},
 | 
			
		||||
        attrs={
 | 
			
		||||
            'td': {
 | 
			
		||||
                'class': lambda record: 'col-sm-1'
 | 
			
		||||
                + (' d-none' if not PermissionBackend.check_perm(
 | 
			
		||||
                    get_current_request(), "activity.delete_opener", record)
 | 
			
		||||
                   else '')}},
 | 
			
		||||
        verbose_name=_("Delete"),)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,31 @@ SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% load i18n perms %}
 | 
			
		||||
{% load render_table from django_tables2 %}
 | 
			
		||||
{% load static django_tables2 i18n %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<h1 class="text-white">{{ title }}</h1>
 | 
			
		||||
{% include "activity/includes/activity_info.html" %}
 | 
			
		||||
 | 
			
		||||
{% if ".change__opener"|has_perm:activity %}
 | 
			
		||||
    <div class="card bg-white mb-3">
 | 
			
		||||
        <h3 class="card-header text-center">
 | 
			
		||||
            {% trans "Openers" %}
 | 
			
		||||
        </h3>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
            <form class="input-group" method="POST" id="form_opener">
 | 
			
		||||
                {% csrf_token %}
 | 
			
		||||
                <input type="hidden" name="activity" value="{{ object.pk }}">
 | 
			
		||||
                {%include "autocomplete_model.html" %}
 | 
			
		||||
                <div class="input-group-append">
 | 
			
		||||
                    <input type="submit" class="btn btn-success" value="{% trans "Add" %}">
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
        {% render_table opener %}
 | 
			
		||||
    </div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{% if guests.data %}
 | 
			
		||||
<div class="card bg-white mb-3">
 | 
			
		||||
    <h3 class="card-header text-center">
 | 
			
		||||
@@ -22,6 +42,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
<script src="{% static "activity/js/opener.js" %}"></script>
 | 
			
		||||
<script src="{% static "js/autocomplete_model.js" %}"></script>
 | 
			
		||||
<script>
 | 
			
		||||
    function remove_guest(guest_id) {
 | 
			
		||||
        $.ajax({
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,8 @@ from permission.backends import PermissionBackend
 | 
			
		||||
from permission.views import ProtectQuerysetMixin, ProtectedCreateView
 | 
			
		||||
 | 
			
		||||
from .forms import ActivityForm, GuestForm
 | 
			
		||||
from .models import Activity, Entry, Guest
 | 
			
		||||
from .tables import ActivityTable, EntryTable, GuestTable
 | 
			
		||||
from .models import Activity, Entry, Guest, Opener
 | 
			
		||||
from .tables import ActivityTable, EntryTable, GuestTable, OpenerTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityCreateView(ProtectQuerysetMixin, ProtectedCreateView):
 | 
			
		||||
@@ -114,8 +114,24 @@ class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
                           .filter(PermissionBackend.filter_queryset(self.request, Guest, "view")))
 | 
			
		||||
        context["guests"] = table
 | 
			
		||||
 | 
			
		||||
        table = OpenerTable(data=self.object.opener.filter(activity=self.object)
 | 
			
		||||
                            .filter(PermissionBackend.filter_queryset(self.request, Opener, "view")))
 | 
			
		||||
        context["opener"] = table
 | 
			
		||||
 | 
			
		||||
        context["activity_started"] = timezone.now() > timezone.localtime(self.object.date_start)
 | 
			
		||||
 | 
			
		||||
        context["widget"] = {
 | 
			
		||||
            "name": "opener",
 | 
			
		||||
            "resetable": True,
 | 
			
		||||
            "attrs": {
 | 
			
		||||
                "class": "autocomplete form-control",
 | 
			
		||||
                "id": "opener",
 | 
			
		||||
                "api_url": "/api/note/alias/?note__polymorphic_ctype__model=noteuser",
 | 
			
		||||
                "name_field": "name",
 | 
			
		||||
                "placeholder": ""
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								apps/member/migrations/0013_auto_20240801_1436.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								apps/member/migrations/0013_auto_20240801_1436.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Generated by Django 2.2.28 on 2024-08-01 12:36
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('member', '0012_club_add_registration_form'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='profile',
 | 
			
		||||
            name='promotion',
 | 
			
		||||
            field=models.PositiveSmallIntegerField(default=2024, help_text='Year of entry to the school (None if not ENS student)', null=True, verbose_name='promotion'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -18,6 +18,7 @@ def create_special_notes(apps, schema_editor):
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('note', '0001_initial'),
 | 
			
		||||
        ('logs', '0001_initial'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
 
 | 
			
		||||
@@ -3111,6 +3111,199 @@
 | 
			
		||||
			"description": "Voir ceux nous ayant pour ami, pour toujours"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 199,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"activity"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{\"opener__in\": [\"user\", \"note\", \"activity_responsible\", [\"all\"]], \"open\": true}",
 | 
			
		||||
			"type": "view",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Voir les activités ouvertes dont l'utilisateur⋅rice est ouvreur⋅se"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 200,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"activity"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{\"opener__in\": [\"user\", \"note\", \"activity_responsible\", [\"all\"]], \"open\": true}",
 | 
			
		||||
			"type": "change",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "open",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Fermer les activités ouvertes dont l'utilisateur⋅rice est ouvreur⋅se"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 201,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"entry"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{\"activity__opener__in\": [\"user\", \"note\", \"activity_responsible\", [\"all\"]], \"activity__open\": true}",
 | 
			
		||||
			"type": "add",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Faire les entrées des activités ouvertes dont l'utilisateur⋅rice est ouvreur⋅se"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 202,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"entry"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{\"activity__opener__in\": [\"user\", \"note\", \"activity_responsible\", [\"all\"]], \"activity__open\": true}",
 | 
			
		||||
			"type": "view",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Voir les entrées des activités ouvertes dont l'utilisateur⋅rice est ouvreur⋅se"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 203,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"guest"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{\"activity__pk__in\": [\"user\", \"note\", \"activity_responsible\", [\"all\"]], \"activity__open\": true}",
 | 
			
		||||
			"type": "view",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Voir les invité⋅es des activités ouvertes dont l'utilisateur⋅rice est ouvreur⋅se"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 204,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"guesttransaction"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "[\"NOT\", {\"pk__isnull\": [\"user\", \"note\", \"activity_responsible\", [\"filter\", {\"activity__open\": true}], [\"exists\"]]}]",
 | 
			
		||||
			"type": "add",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Créer une transaction d'invitation lorsque l'utilisateur⋅rice est ouvreur⋅se d'une activité ouverte"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 205,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"note",
 | 
			
		||||
				"specialtransaction"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "[\"NOT\", {\"pk__isnull\": [\"user\", \"note\", \"activity_responsible\", [\"filter\", {\"activity__open\": true}], [\"exists\"]]}]",
 | 
			
		||||
			"type": "add",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Créer un crédit ou un retrait quelconque lorsque l'utilisateur⋅rice est ouvreur⋅se d'une activité ouverte"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 206,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"note",
 | 
			
		||||
				"notespecial"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "[\"NOT\", {\"pk__isnull\": [\"user\", \"note\", \"activity_responsible\", [\"filter\", {\"activity__open\": true}], [\"exists\"]]}]",
 | 
			
		||||
			"type": "view",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Afficher l'interface crédit/retrait lorsque l'utilisateur⋅rice est ouvreur⋅se d'une activité ouverte"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 207,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"opener"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{}",
 | 
			
		||||
			"type": "view",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Voir les ouvreur⋅ses des activités"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 208,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"opener"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{}",
 | 
			
		||||
			"type": "add",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Ajouter des ouvreur⋅ses aux activités"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 209,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"opener"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{}",
 | 
			
		||||
			"type": "delete",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Supprimer des ouvreur⋅ses aux activités"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.permission",
 | 
			
		||||
		"pk": 210,
 | 
			
		||||
		"fields": {
 | 
			
		||||
			"model": [
 | 
			
		||||
				"activity",
 | 
			
		||||
				"activity"
 | 
			
		||||
			],
 | 
			
		||||
			"query": "{}",
 | 
			
		||||
			"type": "change",
 | 
			
		||||
			"mask": 2,
 | 
			
		||||
			"field": "opener",
 | 
			
		||||
			"permanent": false,
 | 
			
		||||
			"description": "Voir le tableau des ouvreur⋅ses"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"model": "permission.role",
 | 
			
		||||
		"pk": 1,
 | 
			
		||||
@@ -3148,11 +3341,19 @@
 | 
			
		||||
				187,
 | 
			
		||||
				188,
 | 
			
		||||
				189,
 | 
			
		||||
                190,
 | 
			
		||||
                191,
 | 
			
		||||
                195,
 | 
			
		||||
                196,
 | 
			
		||||
                198
 | 
			
		||||
				190,
 | 
			
		||||
				191,
 | 
			
		||||
				195,
 | 
			
		||||
				196,
 | 
			
		||||
				198,
 | 
			
		||||
				199,
 | 
			
		||||
				200,
 | 
			
		||||
				201,
 | 
			
		||||
				202,
 | 
			
		||||
				203,
 | 
			
		||||
				204,
 | 
			
		||||
				205,
 | 
			
		||||
				206
 | 
			
		||||
			]
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
@@ -3414,7 +3615,11 @@
 | 
			
		||||
				46,
 | 
			
		||||
				148,
 | 
			
		||||
				149,
 | 
			
		||||
				182
 | 
			
		||||
				182,
 | 
			
		||||
				207,
 | 
			
		||||
				208,
 | 
			
		||||
				209,
 | 
			
		||||
				210
 | 
			
		||||
			]
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user