mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	Open and validate activities
This commit is contained in:
		@@ -4,7 +4,7 @@
 | 
				
			|||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from django.contrib.contenttypes.models import ContentType
 | 
					from django.contrib.contenttypes.models import ContentType
 | 
				
			||||||
from member.models import Club
 | 
					from member.models import Club
 | 
				
			||||||
from note.models import NoteUser
 | 
					from note.models import NoteUser, Note
 | 
				
			||||||
from note_kfet.inputs import DateTimePickerInput, AutocompleteModelSelect
 | 
					from note_kfet.inputs import DateTimePickerInput, AutocompleteModelSelect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Activity, Guest
 | 
					from .models import Activity, Guest
 | 
				
			||||||
@@ -13,12 +13,19 @@ from .models import Activity, Guest
 | 
				
			|||||||
class ActivityForm(forms.ModelForm):
 | 
					class ActivityForm(forms.ModelForm):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Activity
 | 
					        model = Activity
 | 
				
			||||||
        fields = '__all__'
 | 
					        exclude = ('valid', 'open', )
 | 
				
			||||||
        widgets = {
 | 
					        widgets = {
 | 
				
			||||||
            "organizer": AutocompleteModelSelect(
 | 
					            "organizer": AutocompleteModelSelect(
 | 
				
			||||||
                model=Club,
 | 
					                model=Club,
 | 
				
			||||||
                attrs={"api_url": "/api/members/club/"},
 | 
					                attrs={"api_url": "/api/members/club/"},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					            "note": AutocompleteModelSelect(
 | 
				
			||||||
 | 
					                model=Note,
 | 
				
			||||||
 | 
					                attrs={
 | 
				
			||||||
 | 
					                    "api_url": "/api/note/note/",
 | 
				
			||||||
 | 
					                    'placeholder': 'Note de l\'événement sur laquelle envoyer les crédits d\'invitation ...'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            "attendees_club": AutocompleteModelSelect(
 | 
					            "attendees_club": AutocompleteModelSelect(
 | 
				
			||||||
                model=Club,
 | 
					                model=Club,
 | 
				
			||||||
                attrs={"api_url": "/api/members/club/"},
 | 
					                attrs={"api_url": "/api/members/club/"},
 | 
				
			||||||
@@ -39,7 +46,7 @@ class GuestForm(forms.ModelForm):
 | 
				
			|||||||
                    'api_url': '/api/note/note/',
 | 
					                    'api_url': '/api/note/note/',
 | 
				
			||||||
                    # We don't evaluate the content type at launch because the DB might be not initialized
 | 
					                    # We don't evaluate the content type at launch because the DB might be not initialized
 | 
				
			||||||
                    'api_url_suffix':
 | 
					                    'api_url_suffix':
 | 
				
			||||||
                        lambda value: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteUser).pk),
 | 
					                        lambda: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteUser).pk),
 | 
				
			||||||
                    'placeholder': 'Note ...',
 | 
					                    'placeholder': 'Note ...',
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from note.models import NoteUser
 | 
					from note.models import NoteUser, Transaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityType(models.Model):
 | 
					class ActivityType(models.Model):
 | 
				
			||||||
@@ -44,34 +44,59 @@ class Activity(models.Model):
 | 
				
			|||||||
        verbose_name=_('name'),
 | 
					        verbose_name=_('name'),
 | 
				
			||||||
        max_length=255,
 | 
					        max_length=255,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    description = models.TextField(
 | 
					    description = models.TextField(
 | 
				
			||||||
        verbose_name=_('description'),
 | 
					        verbose_name=_('description'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    activity_type = models.ForeignKey(
 | 
					    activity_type = models.ForeignKey(
 | 
				
			||||||
        ActivityType,
 | 
					        ActivityType,
 | 
				
			||||||
        on_delete=models.PROTECT,
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
        related_name='+',
 | 
					        related_name='+',
 | 
				
			||||||
        verbose_name=_('type'),
 | 
					        verbose_name=_('type'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    organizer = models.ForeignKey(
 | 
					    organizer = models.ForeignKey(
 | 
				
			||||||
        'member.Club',
 | 
					        'member.Club',
 | 
				
			||||||
        on_delete=models.PROTECT,
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
        related_name='+',
 | 
					        related_name='+',
 | 
				
			||||||
        verbose_name=_('organizer'),
 | 
					        verbose_name=_('organizer'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    note = models.ForeignKey(
 | 
				
			||||||
 | 
					        'note.Note',
 | 
				
			||||||
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
 | 
					        related_name='+',
 | 
				
			||||||
 | 
					        null=True,
 | 
				
			||||||
 | 
					        blank=True,
 | 
				
			||||||
 | 
					        verbose_name=_('note'),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    attendees_club = models.ForeignKey(
 | 
					    attendees_club = models.ForeignKey(
 | 
				
			||||||
        'member.Club',
 | 
					        'member.Club',
 | 
				
			||||||
        on_delete=models.PROTECT,
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
        related_name='+',
 | 
					        related_name='+',
 | 
				
			||||||
        verbose_name=_('attendees club'),
 | 
					        verbose_name=_('attendees club'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    date_start = models.DateTimeField(
 | 
					    date_start = models.DateTimeField(
 | 
				
			||||||
        verbose_name=_('start date'),
 | 
					        verbose_name=_('start date'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    date_end = models.DateTimeField(
 | 
					    date_end = models.DateTimeField(
 | 
				
			||||||
        verbose_name=_('end date'),
 | 
					        verbose_name=_('end date'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    valid = models.BooleanField(
 | 
				
			||||||
 | 
					        default=False,
 | 
				
			||||||
 | 
					        verbose_name=_('valid'),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    open = models.BooleanField(
 | 
				
			||||||
 | 
					        default=False,
 | 
				
			||||||
 | 
					        verbose_name=_('open'),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        verbose_name = _("activity")
 | 
					        verbose_name = _("activity")
 | 
				
			||||||
        verbose_name_plural = _("activities")
 | 
					        verbose_name_plural = _("activities")
 | 
				
			||||||
@@ -122,13 +147,17 @@ class Guest(models.Model):
 | 
				
			|||||||
        null=True,
 | 
					        null=True,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    entry_transaction = models.ForeignKey(
 | 
					 | 
				
			||||||
        'note.Transaction',
 | 
					 | 
				
			||||||
        on_delete=models.PROTECT,
 | 
					 | 
				
			||||||
        blank=True,
 | 
					 | 
				
			||||||
        null=True,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        verbose_name = _("guest")
 | 
					        verbose_name = _("guest")
 | 
				
			||||||
        verbose_name_plural = _("guests")
 | 
					        verbose_name_plural = _("guests")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GuestTransaction(Transaction):
 | 
				
			||||||
 | 
					    guest = models.OneToOneField(
 | 
				
			||||||
 | 
					        Guest,
 | 
				
			||||||
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def type(self):
 | 
				
			||||||
 | 
					        return _('Invitation')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@ class TransactionTemplateForm(forms.ModelForm):
 | 
				
			|||||||
                        'api_url': '/api/note/note/',
 | 
					                        'api_url': '/api/note/note/',
 | 
				
			||||||
                        # We don't evaluate the content type at launch because the DB might be not initialized
 | 
					                        # We don't evaluate the content type at launch because the DB might be not initialized
 | 
				
			||||||
                        'api_url_suffix':
 | 
					                        'api_url_suffix':
 | 
				
			||||||
                            lambda value: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteClub).pk),
 | 
					                            lambda: '&polymorphic_ctype=' + str(ContentType.objects.get_for_model(NoteClub).pk),
 | 
				
			||||||
                        'placeholder': 'Note ...',
 | 
					                        'placeholder': 'Note ...',
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,9 +48,7 @@ def not_empty_model_change_list(model_name):
 | 
				
			|||||||
    return session.get("not_empty_model_change_list_" + model_name) == 1
 | 
					    return session.get("not_empty_model_change_list_" + model_name) == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def has_perm(t, obj, field=None):
 | 
					def has_perm(perm, obj):
 | 
				
			||||||
    print(t)
 | 
					 | 
				
			||||||
    perm = "." + t + ("__" + field if field else "_")
 | 
					 | 
				
			||||||
    return PermissionBackend().has_perm(get_current_authenticated_user(), perm, obj)
 | 
					    return PermissionBackend().has_perm(get_current_authenticated_user(), perm, obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,15 +28,35 @@ function addMsg(msg, alert_type) {
 | 
				
			|||||||
        + msg + "</div>\n";
 | 
					        + msg + "</div>\n";
 | 
				
			||||||
    msgDiv.html(html);
 | 
					    msgDiv.html(html);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * add Muliple error message from err_obj
 | 
					 * add Muliple error message from err_obj
 | 
				
			||||||
 * @param err_obj {error_code:erro_message}
 | 
					 * @param errs_obj [{error_code:erro_message}]
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function errMsg(errs_obj){
 | 
					function errMsg(errs_obj){
 | 
				
			||||||
    for (const err_msg of Object.values(errs_obj)) {
 | 
					    for (const err_msg of Object.values(errs_obj)) {
 | 
				
			||||||
              addMsg(err_msg,'danger');
 | 
					              addMsg(err_msg,'danger');
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var reloadWithTurbolinks = (function () {
 | 
				
			||||||
 | 
					  var scrollPosition;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function reload () {
 | 
				
			||||||
 | 
					    scrollPosition = [window.scrollX, window.scrollY];
 | 
				
			||||||
 | 
					    Turbolinks.visit(window.location.toString(), { action: 'replace' })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  document.addEventListener('turbolinks:load', function () {
 | 
				
			||||||
 | 
					    if (scrollPosition) {
 | 
				
			||||||
 | 
					      window.scrollTo.apply(window, scrollPosition);
 | 
				
			||||||
 | 
					      scrollPosition = null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return reload;
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Reload the balance of the user on the right top corner
 | 
					 * Reload the balance of the user on the right top corner
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="card bg-light shadow">
 | 
					    <div id="activity_info" class="card bg-light shadow">
 | 
				
			||||||
        <div class="card-header text-center">
 | 
					        <div class="card-header text-center">
 | 
				
			||||||
            <h4>{{ activity.name }}</h4>
 | 
					            <h4>{{ activity.name }}</h4>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
@@ -38,11 +38,23 @@
 | 
				
			|||||||
                    <dt class="col-xl-6">{% trans 'guest entry fee'|capfirst %}</dt>
 | 
					                    <dt class="col-xl-6">{% trans 'guest entry fee'|capfirst %}</dt>
 | 
				
			||||||
                    <dd class="col-xl-6">{{ activity.activity_type.guest_entry_fee|pretty_money }}</dd>
 | 
					                    <dd class="col-xl-6">{{ activity.activity_type.guest_entry_fee|pretty_money }}</dd>
 | 
				
			||||||
                {% endif %}
 | 
					                {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <dt class="col-xl-6">{% trans 'valid'|capfirst %}</dt>
 | 
				
			||||||
 | 
					                <dd class="col-xl-6">{{ activity.valid|yesno }}</dd>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <dt class="col-xl-6">{% trans 'opened'|capfirst %}</dt>
 | 
				
			||||||
 | 
					                <dd class="col-xl-6">{{ activity.open|yesno }}</dd>
 | 
				
			||||||
            </dl>
 | 
					            </dl>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="card-footer text-center">
 | 
					        <div class="card-footer text-center">
 | 
				
			||||||
            {% if "view"|has_perm:activity %}
 | 
					            {% if activity.valid and "change__open"|has_perm:activity %}
 | 
				
			||||||
 | 
					                <a class="btn btn-warning btn-sm my-1" id="open_activity"> {% if activity.open %}{% trans "close"|capfirst %}{% else %}{% trans "open"|capfirst %}{% endif %}</a>
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					            {% if not activity.open and "change__valid"|has_perm:activity %}
 | 
				
			||||||
 | 
					                <a class="btn btn-success btn-sm my-1" id="validate_activity"> {% if activity.valid %}{% trans "invalidate"|capfirst %}{% else %}{% trans "validate"|capfirst %}{% endif %}</a>
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					            {% if "view_"|has_perm:activity %}
 | 
				
			||||||
                <a class="btn btn-primary btn-sm my-1" href="{% url 'activity:activity_update' pk=activity.pk %}"> {% trans "edit"|capfirst %}</a>
 | 
					                <a class="btn btn-primary btn-sm my-1" href="{% url 'activity:activity_update' pk=activity.pk %}"> {% trans "edit"|capfirst %}</a>
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
            {% if activity.activity_type.can_invite %}
 | 
					            {% if activity.activity_type.can_invite %}
 | 
				
			||||||
@@ -77,5 +89,42 @@
 | 
				
			|||||||
          errMsg(xhr.responseJSON);
 | 
					          errMsg(xhr.responseJSON);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $("#open_activity").click(function() {
 | 
				
			||||||
 | 
					        $.ajax({
 | 
				
			||||||
 | 
					            url: "/api/activity/activity/{{ activity.pk }}/",
 | 
				
			||||||
 | 
					            type: "PATCH",
 | 
				
			||||||
 | 
					            dataType: "json",
 | 
				
			||||||
 | 
					            headers: {
 | 
				
			||||||
 | 
					                "X-CSRFTOKEN": CSRF_TOKEN
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            data: {
 | 
				
			||||||
 | 
					                open: {{ activity.open|yesno:'false,true' }}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }).done(function () {
 | 
				
			||||||
 | 
					            reloadWithTurbolinks();
 | 
				
			||||||
 | 
					        }).fail(function (xhr) {
 | 
				
			||||||
 | 
					            errMsg(xhr.responseJSON);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $("#validate_activity").click(function () {
 | 
				
			||||||
 | 
					        console.log(42);
 | 
				
			||||||
 | 
					        $.ajax({
 | 
				
			||||||
 | 
					            url: "/api/activity/activity/{{ activity.pk }}/",
 | 
				
			||||||
 | 
					            type: "PATCH",
 | 
				
			||||||
 | 
					            dataType: "json",
 | 
				
			||||||
 | 
					            headers: {
 | 
				
			||||||
 | 
					                "X-CSRFTOKEN": CSRF_TOKEN
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            data: {
 | 
				
			||||||
 | 
					                valid: {{ activity.valid|yesno:'false,true' }}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }).done(function () {
 | 
				
			||||||
 | 
					            reloadWithTurbolinks();
 | 
				
			||||||
 | 
					        }).fail(function (xhr) {
 | 
				
			||||||
 | 
					            errMsg(xhr.responseJSON);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user