Compare commits
2 commits
master
...
Qwann/base
Author | SHA1 | Date | |
---|---|---|---|
|
6cc773ae1e | ||
|
2e1d98487c |
148 changed files with 861 additions and 9527 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,8 +1,7 @@
|
|||
.vagrant/
|
||||
__pycache__
|
||||
venv
|
||||
poulpe/settings.py
|
||||
evenementiel/settings.py
|
||||
.*.swp
|
||||
*.pyc
|
||||
*.sqlite3
|
||||
*.scssc
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
default_app_config = 'api.apps.APIConfig'
|
|
@ -1,7 +0,0 @@
|
|||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class APIConfig(AppConfig):
|
||||
name = 'api'
|
||||
verbose_name = _("API")
|
|
@ -1 +0,0 @@
|
|||
default_app_config = 'communication.apps.CommunicationConfig'
|
|
@ -1,7 +1,4 @@
|
|||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class CommunicationConfig(AppConfig):
|
||||
name = 'communication'
|
||||
verbose_name = _("Communication")
|
||||
|
|
|
@ -20,10 +20,7 @@ class Subscription(models.Model):
|
|||
|
||||
|
||||
class UserSubscription(Subscription):
|
||||
user = models.ForeignKey(
|
||||
User,
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
user = models.ForeignKey(User)
|
||||
is_unsub = models.BooleanField(
|
||||
_("désinscription"),
|
||||
default=False
|
||||
|
@ -35,10 +32,7 @@ class UserSubscription(Subscription):
|
|||
|
||||
|
||||
class GroupSubscription(Subscription):
|
||||
group = models.ForeignKey(
|
||||
Group,
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
group = models.ForeignKey(Group)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("souscription en groupe")
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
default_app_config = 'equipment.apps.EquipmentConfig'
|
|
@ -1,133 +0,0 @@
|
|||
from django.contrib import admin
|
||||
from django import forms
|
||||
|
||||
from .models import Equipment, EquipmentDefault, EquipmentRevision, EquipmentCategory, EquipmentLost, EquipmentAttributeValue, EquipmentAttribute, EquipmentStorage
|
||||
from .fields import IdField, IdWidget
|
||||
|
||||
|
||||
class IdForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'min_value' in kwargs:
|
||||
kwargs.pop('min_value')
|
||||
if 'num_choices' in kwargs:
|
||||
num_choices = kwargs.pop('num_choices')
|
||||
else:
|
||||
num_choices = None
|
||||
super(IdForm, self).__init__(*args, **kwargs)
|
||||
|
||||
for field in self.instance._meta.fields:
|
||||
if isinstance(field, IdField):
|
||||
if num_choices is None:
|
||||
choices = []
|
||||
else:
|
||||
choices = [(k, str(k)) for k in range(1, num_choices+1)]
|
||||
self.fields[field.name].choices = choices
|
||||
self.fields[field.name].widget = IdWidget(choices=self.fields[field.name].choices)
|
||||
|
||||
|
||||
class IdFormset(forms.models.BaseInlineFormSet):
|
||||
def get_form_kwargs(self, index):
|
||||
kwargs = super().get_form_kwargs(index)
|
||||
if self.instance:
|
||||
kwargs["num_choices"] = self.instance.stock
|
||||
return kwargs
|
||||
|
||||
|
||||
class EquipmentRevisionExtraInline(admin.TabularInline):
|
||||
model = EquipmentRevision
|
||||
extra = 0
|
||||
form = IdForm
|
||||
formset = IdFormset
|
||||
classes = ['collapse']
|
||||
|
||||
|
||||
class EquipmentDefaultExtraInline(admin.TabularInline):
|
||||
model = EquipmentDefault
|
||||
extra = 0
|
||||
form = IdForm
|
||||
formset = IdFormset
|
||||
classes = ['collapse']
|
||||
|
||||
|
||||
class EquipmentLostExtraInline(admin.TabularInline):
|
||||
model = EquipmentLost
|
||||
extra = 0
|
||||
form = IdForm
|
||||
formset = IdFormset
|
||||
classes = ['collapse']
|
||||
|
||||
|
||||
class EquipmentAttributeValueInline(admin.TabularInline):
|
||||
model = EquipmentAttributeValue
|
||||
extra = 0
|
||||
|
||||
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
readonly_fields = ['full_name_p']
|
||||
list_display = ['name', 'parent', "full_name_p"]
|
||||
ordering = ['name', 'parent']
|
||||
search_fields = ['name',]
|
||||
autocomplete_fields = ['parent', ]
|
||||
|
||||
class StorageAdmin(admin.ModelAdmin):
|
||||
list_display = ['name']
|
||||
ordering = ['name']
|
||||
search_fields = ['name']
|
||||
|
||||
|
||||
class EquipmentAttributeAdmin(admin.ModelAdmin):
|
||||
list_display = ['name']
|
||||
ordering = ['name']
|
||||
search_fields = ['name',]
|
||||
|
||||
|
||||
class EquipmentAdmin(admin.ModelAdmin):
|
||||
save_as_continue = True
|
||||
save_on_top = True
|
||||
autocomplete_fields = ['category', 'storage', ]
|
||||
readonly_fields = ['full_category_p',
|
||||
'added_at',
|
||||
'modified_at',
|
||||
'stock_aviable_p',
|
||||
'ids_aviable_p',
|
||||
'stock_lost_p',
|
||||
'ids_lost_p',
|
||||
]
|
||||
list_display = ['name', 'stock', 'owner', 'category', 'storage', 'modified_at']
|
||||
fieldsets = (
|
||||
('Général', {
|
||||
'fields': ('name', 'owner', 'stock', )
|
||||
}),
|
||||
('Info stock',
|
||||
{
|
||||
'fields': (
|
||||
'stock_aviable_p',
|
||||
'ids_aviable_p',
|
||||
'stock_lost_p',
|
||||
'ids_lost_p',
|
||||
),
|
||||
}),
|
||||
('Attributs', {
|
||||
'fields': ('category', 'full_category_p', 'storage'),
|
||||
}),
|
||||
('Description', {
|
||||
'fields': ('description', 'added_at', 'modified_at',),
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
ordering = ['name', 'owner', 'category']
|
||||
inlines = [EquipmentAttributeValueInline,
|
||||
EquipmentDefaultExtraInline,
|
||||
EquipmentLostExtraInline,
|
||||
EquipmentRevisionExtraInline]
|
||||
search_fields = ['name', 'description',]
|
||||
list_filter = ['owner', 'category', 'storage', ]
|
||||
|
||||
|
||||
admin.site.register(Equipment, EquipmentAdmin)
|
||||
admin.site.register(EquipmentCategory, CategoryAdmin)
|
||||
admin.site.register(EquipmentStorage, StorageAdmin)
|
||||
admin.site.register(EquipmentAttribute, EquipmentAttributeAdmin)
|
|
@ -1,7 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class EquipmentConfig(AppConfig):
|
||||
name = 'equipment'
|
||||
verbose_name = _("Équipement")
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
from django.db import models
|
||||
from django import forms
|
||||
|
||||
|
||||
#class IdWidget(AdminMultipleChoiceFieldWidget):
|
||||
class IdWidget(forms.widgets.CheckboxSelectMultiple):
|
||||
template_name = 'equipment/widgets/checkbox_select.html'
|
||||
option_template_name = 'equipment/widgets/checkbox_option.html'
|
||||
def __init__(self, *args, **kwargs):
|
||||
# nb_items = kwargs.pop('nb_items')
|
||||
# kwargs['choices'] = list(range(1, nb_items+1))
|
||||
super(IdWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('css/idwidget.css',)
|
||||
}
|
||||
|
||||
class IdFormField(forms.MultipleChoiceField):
|
||||
#widget = IdWidget
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if 'min_value' in kwargs:
|
||||
kwargs.pop('min_value')
|
||||
if 'max_value' in kwargs:
|
||||
kwargs.pop('max_value')
|
||||
super(IdFormField, self).__init__(*args, **kwargs)
|
||||
|
||||
class IdField(models.BigIntegerField):
|
||||
def parse_integer(self, n):
|
||||
res = []
|
||||
k = 1
|
||||
while(n > 0):
|
||||
if n & 1:
|
||||
res.append(k)
|
||||
n >>= 1
|
||||
k += 1
|
||||
return res
|
||||
|
||||
def from_db_value(self, value, expression, connection):
|
||||
if value is None:
|
||||
return value
|
||||
return self.parse_integer(value)
|
||||
|
||||
def to_python(self, value):
|
||||
if isinstance(value, list):
|
||||
return value
|
||||
|
||||
if value is None:
|
||||
return value
|
||||
|
||||
return self.parse_integer(value)
|
||||
|
||||
def get_prep_value(self, value):
|
||||
res = 0
|
||||
for b in value:
|
||||
res |= 1 << (int(b)-1)
|
||||
return res
|
||||
|
||||
def __init__(self, separator=",", *args, **kwargs):
|
||||
self.separator = separator
|
||||
super(IdField, self).__init__(*args, **kwargs)
|
||||
self.validators = [] # TODO : validateurs pertinents
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(IdField, self).deconstruct()
|
||||
# Only include kwarg if it's not the default
|
||||
if self.separator != ",":
|
||||
kwargs['separator'] = self.separator
|
||||
return name, path, args, kwargs
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
# This is a fairly standard way to set up some defaults
|
||||
# while letting the caller override them.
|
||||
defaults = {'form_class': IdFormField}
|
||||
defaults.update(kwargs)
|
||||
return super(IdField, self).formfield(**defaults)
|
|
@ -1,11 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-06 17:29
|
||||
# Generated by Django 1.11.4 on 2017-08-12 12:47
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import equipment.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -34,7 +32,7 @@ class Migration(migrations.Migration):
|
|||
name='EquipmentAttribution',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('amount', models.BigIntegerField(verbose_name='quantité attribuée')),
|
||||
('amount', models.PositiveSmallIntegerField(verbose_name='quantité attribuée')),
|
||||
('remarks', models.TextField(verbose_name="remarques concernant l'attribution")),
|
||||
('activity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='event.Activity')),
|
||||
('equipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.Equipment')),
|
||||
|
@ -44,45 +42,12 @@ class Migration(migrations.Migration):
|
|||
'verbose_name_plural': 'attributions de matériel',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EquipmentCategory',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, verbose_name='nom')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'catégories',
|
||||
'verbose_name_plural': 'catégories',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EquipmentOwner',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, verbose_name='nom')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'propriétaire de matériel',
|
||||
'verbose_name_plural': 'propriétaires de matériel',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EquipmentPole',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, verbose_name='nom')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'pôle',
|
||||
'verbose_name_plural': 'pôle',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EquipmentRemark',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('remark', models.TextField(verbose_name='remarque sur le matériel')),
|
||||
('ids', equipment.fields.IdField()),
|
||||
('amount', models.PositiveSmallIntegerField(verbose_name='quantité concernée')),
|
||||
('is_broken', models.BooleanField()),
|
||||
('is_lost', models.BooleanField()),
|
||||
('equipment', models.ForeignKey(help_text='Matériel concerné par la remarque', on_delete=django.db.models.deletion.CASCADE, related_name='remarks', to='equipment.Equipment')),
|
||||
|
@ -92,43 +57,14 @@ class Migration(migrations.Migration):
|
|||
'verbose_name_plural': 'remarques sur le matériel',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EquipmentRevision',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date', models.DateField(default=datetime.date.today, verbose_name='date')),
|
||||
('remark', models.TextField(verbose_name='remarque sur la révision')),
|
||||
('ids', equipment.fields.IdField()),
|
||||
('equipment', models.ForeignKey(help_text='Matériel concerné par les révisions', on_delete=django.db.models.deletion.CASCADE, related_name='revisions', to='equipment.Equipment')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'révision de matériel',
|
||||
'verbose_name_plural': 'révisions de matériel',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='activities',
|
||||
field=models.ManyToManyField(related_name='equipment', through='equipment.EquipmentAttribution', to='event.Activity'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='category',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.EquipmentCategory'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='event',
|
||||
field=models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèle est spécifique à l'évènement en question.", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='owner',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='equipment.EquipmentOwner'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='pole',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.EquipmentPole'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-07 16:58
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import equipment.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EquipmentDefault',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('remark', models.TextField(verbose_name='remarque sur le défaut')),
|
||||
('ids', equipment.fields.IdField()),
|
||||
('is_unusable', models.BooleanField(verbose_name='inutilisable')),
|
||||
('send_repare', models.BooleanField(verbose_name='à envoyer réparareur')),
|
||||
('equipment', models.ForeignKey(help_text='Matériel concerné par le defaut', on_delete=django.db.models.deletion.CASCADE, related_name='remarks', to='equipment.Equipment')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'defaut matériel',
|
||||
'verbose_name_plural': 'défauts sur le matériel',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EquipmentLost',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('lost_at', models.DateField(default=datetime.date.today, verbose_name='perdu le')),
|
||||
('ids', equipment.fields.IdField()),
|
||||
('equipment', models.ForeignKey(help_text='Matériel concerné par la perte', on_delete=django.db.models.deletion.CASCADE, related_name='losts', to='equipment.Equipment')),
|
||||
],
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='equipmentremark',
|
||||
name='equipment',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='EquipmentRemark',
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-07 18:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0002_auto_20180807_1658'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='equipment',
|
||||
name='owner',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='EquipmentOwner',
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-07 18:44
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0008_alter_user_username_max_length'),
|
||||
('equipment', '0003_auto_20180807_1843'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='owner',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='auth.Group'),
|
||||
),
|
||||
]
|
|
@ -1,28 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-08 10:13
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0004_equipment_owner'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='equipment',
|
||||
name='pole',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipmentcategory',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='equipment.EquipmentCategory'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='EquipmentPole',
|
||||
),
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-08 13:54
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0005_auto_20180808_1013'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipmentcategory',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, default=None, help_text='merci de ne pas faire de référence cyclique', null=True, on_delete=django.db.models.deletion.CASCADE, to='equipment.EquipmentCategory'),
|
||||
),
|
||||
]
|
|
@ -1,40 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-08 14:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0006_auto_20180808_1354'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EquipmentAttribute',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, unique=True, verbose_name='nom')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'attribut',
|
||||
'verbose_name_plural': 'attributs',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EquipmentAttributeValue',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('value', models.CharField(max_length=200, verbose_name='valeur')),
|
||||
('attribute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.EquipmentAttribute')),
|
||||
('equipment', models.ForeignKey(help_text='Matériel concerné par le defaut', on_delete=django.db.models.deletion.CASCADE, related_name='attributes', to='equipment.Equipment')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'attribut de matériel',
|
||||
'verbose_name_plural': 'attributs de matériel',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-08 14:54
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0007_equipmentattribute_equipmentattributevalue'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='category',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='equipment.EquipmentCategory'),
|
||||
),
|
||||
]
|
|
@ -1,28 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-09 12:00
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
from django.utils.timezone import utc
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0008_auto_20180808_1454'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='added_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2018, 8, 9, 12, 0, 50, 140250, tzinfo=utc), verbose_name='ajouté le'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='modified_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='dernière modification'),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-09 12:11
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0009_auto_20180809_1200'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='stock',
|
||||
field=models.PositiveSmallIntegerField(verbose_name='quantité totale'),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-09 14:05
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0010_auto_20180809_1211'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='description',
|
||||
field=models.TextField(blank=True, verbose_name='description'),
|
||||
),
|
||||
]
|
|
@ -1,61 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-20 11:24
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0011_auto_20180809_1405'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='category',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='equipment.EquipmentCategory', verbose_name='catégorie'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='owner',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='auth.Group', verbose_name='propriétaire'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentattributevalue',
|
||||
name='attribute',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.EquipmentAttribute', verbose_name='attribut'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentattributevalue',
|
||||
name='equipment',
|
||||
field=models.ForeignKey(help_text='Matériel concerné par le defaut', on_delete=django.db.models.deletion.CASCADE, related_name='attributes', to='equipment.Equipment', verbose_name='matériel'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentattribution',
|
||||
name='equipment',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.Equipment', verbose_name='matériel'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentcategory',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, default=None, help_text='merci de ne pas faire de référence cyclique', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='equipment.EquipmentCategory', verbose_name='parent'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentdefault',
|
||||
name='equipment',
|
||||
field=models.ForeignKey(help_text='Matériel concerné par le defaut', on_delete=django.db.models.deletion.CASCADE, related_name='remarks', to='equipment.Equipment', verbose_name='matériel'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentlost',
|
||||
name='equipment',
|
||||
field=models.ForeignKey(help_text='Matériel concerné par la perte', on_delete=django.db.models.deletion.CASCADE, related_name='losts', to='equipment.Equipment', verbose_name='matériel'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentrevision',
|
||||
name='equipment',
|
||||
field=models.ForeignKey(help_text='Matériel concerné par les révisions', on_delete=django.db.models.deletion.CASCADE, related_name='revisions', to='equipment.Equipment', verbose_name='matériel'),
|
||||
),
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-26 17:49
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0012_auto_20180820_1124'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipmentattribution',
|
||||
name='remarks',
|
||||
field=models.TextField(blank=True, verbose_name="remarques concernant l'attribution"),
|
||||
),
|
||||
]
|
|
@ -1,26 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-26 22:05
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0013_auto_20180826_1949'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='owner',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='auth.Group', verbose_name='propriétaire'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipmentcategory',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, default=None, help_text='merci de ne pas faire de référence cyclique', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='equipment.EquipmentCategory', verbose_name='parent'),
|
||||
),
|
||||
]
|
|
@ -1,26 +0,0 @@
|
|||
# Generated by Django 2.1.5 on 2019-03-18 11:45
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0014_auto_20180827_0005'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EquipmentStorage',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, verbose_name='nom')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='storage',
|
||||
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='equipment.EquipmentStorage', verbose_name='stockage'),
|
||||
),
|
||||
]
|
|
@ -1,17 +0,0 @@
|
|||
# Generated by Django 2.1.5 on 2019-03-18 11:47
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('equipment', '0015_auto_20190318_1245'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='equipmentstorage',
|
||||
options={'verbose_name': 'stockage', 'verbose_name_plural': 'stockages'},
|
||||
),
|
||||
]
|
|
@ -1,98 +1,7 @@
|
|||
from django.db import models
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.auth.models import Group
|
||||
from event.models import Activity, EventSpecificMixin
|
||||
from django.db.models import Q
|
||||
|
||||
from .fields import IdField
|
||||
|
||||
from datetime import date
|
||||
|
||||
|
||||
class EquipmentStorage(models.Model):
|
||||
name = models.CharField(
|
||||
_("nom"),
|
||||
max_length=200,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("stockage")
|
||||
verbose_name_plural = _("stockages")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class EquipmentCategory(models.Model):
|
||||
name = models.CharField(
|
||||
_("nom"),
|
||||
max_length=200,
|
||||
)
|
||||
parent = models.ForeignKey(
|
||||
'self',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="children",
|
||||
help_text=_("merci de ne pas faire de référence cyclique"),
|
||||
verbose_name=_("parent"),
|
||||
)
|
||||
|
||||
def has_parent(self, cat):
|
||||
current = self
|
||||
for k in range(100):
|
||||
if current is None:
|
||||
return False
|
||||
if current == cat:
|
||||
return True
|
||||
current = current.parent
|
||||
|
||||
def full_name(self):
|
||||
current = self
|
||||
res = ""
|
||||
for k in range(100):
|
||||
res = "/{current}{old}".format(
|
||||
current=current.name,
|
||||
old=res)
|
||||
if current.parent is None:
|
||||
break
|
||||
current = current.parent
|
||||
return res
|
||||
|
||||
full_name.short_description = _("Chemin complet")
|
||||
full_name_p = property(full_name)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("catégories")
|
||||
verbose_name_plural = _("catégories")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.pk:
|
||||
done = False
|
||||
current = self
|
||||
while not done:
|
||||
if current.parent == self:
|
||||
self.parent = None
|
||||
done = True
|
||||
elif current.parent is None:
|
||||
done = True
|
||||
current = current.parent
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class EquipmentQuerySet(models.QuerySet):
|
||||
def in_category(self, cat):
|
||||
filtre = Q(id__lt=0)
|
||||
childs_id = [c.id for c in EquipmentCategory.objects.all()
|
||||
if c.has_parent(cat)]
|
||||
for pk in childs_id:
|
||||
filtre |= Q(category__id=pk)
|
||||
return self.filter(filtre)
|
||||
|
||||
|
||||
class Equipment(EventSpecificMixin, models.Model):
|
||||
|
@ -100,98 +9,13 @@ class Equipment(EventSpecificMixin, models.Model):
|
|||
_("nom du matériel"),
|
||||
max_length=200,
|
||||
)
|
||||
stock = models.PositiveSmallIntegerField(_("quantité totale"))
|
||||
description = models.TextField(
|
||||
_("description"),
|
||||
blank=True,
|
||||
)
|
||||
stock = models.PositiveSmallIntegerField(_("quantité disponible"))
|
||||
description = models.TextField(_("description"))
|
||||
activities = models.ManyToManyField(
|
||||
Activity,
|
||||
related_name="equipment",
|
||||
through="EquipmentAttribution",
|
||||
)
|
||||
owner = models.ForeignKey(
|
||||
Group,
|
||||
verbose_name=_("propriétaire"),
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
category = models.ForeignKey(
|
||||
EquipmentCategory,
|
||||
verbose_name=_("catégorie"),
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
storage = models.ForeignKey(
|
||||
EquipmentStorage,
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
verbose_name=_("stockage"),
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
|
||||
added_at = models.DateTimeField(
|
||||
_("ajouté le"),
|
||||
auto_now_add=True,
|
||||
)
|
||||
modified_at = models.DateTimeField(
|
||||
_("dernière modification"),
|
||||
auto_now=True,
|
||||
)
|
||||
|
||||
objects = EquipmentQuerySet.as_manager()
|
||||
|
||||
def is_in_category(self, cat):
|
||||
current = self.category
|
||||
for k in range(100):
|
||||
if current is None:
|
||||
return False
|
||||
if current == cat:
|
||||
return True
|
||||
current = current.parent
|
||||
|
||||
def ids_aviable(self):
|
||||
if self.stock is None:
|
||||
return []
|
||||
res = list(map(lambda x: x+1, range(self.stock)))
|
||||
for lost in self.losts.all():
|
||||
res = [x
|
||||
for x in res
|
||||
if x not in lost.ids]
|
||||
# TODO cassé
|
||||
# TODO utilisés
|
||||
return res
|
||||
|
||||
def ids_lost(self):
|
||||
res = []
|
||||
for lost in self.losts.all():
|
||||
res = res + [x
|
||||
for x in lost.ids
|
||||
if x not in res]
|
||||
return res
|
||||
|
||||
def stock_aviable(self):
|
||||
aviable = self.ids_aviable()
|
||||
return len(aviable)
|
||||
|
||||
def stock_lost(self):
|
||||
return len(self.ids_lost())
|
||||
|
||||
def full_category(self):
|
||||
return self.category.full_name()
|
||||
|
||||
full_category.short_description = _("Chemin complet")
|
||||
ids_aviable.short_description = _("disponibles")
|
||||
ids_lost.short_description = _("perdus")
|
||||
stock_aviable.short_description = _("quantité disponible")
|
||||
stock_lost.short_description = _("quantité perdue")
|
||||
|
||||
full_category_p = property(full_category)
|
||||
ids_aviable_p = property(ids_aviable)
|
||||
ids_lost_p = property(ids_lost)
|
||||
stock_aviable_p = property(stock_aviable)
|
||||
stock_lost_p = property(stock_lost)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("matériel")
|
||||
|
@ -201,63 +25,11 @@ class Equipment(EventSpecificMixin, models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
class EquipmentAttribute(models.Model):
|
||||
name = models.CharField(
|
||||
_("nom"),
|
||||
max_length=200,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("attribut")
|
||||
verbose_name_plural = _("attributs")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class EquipmentAttributeValue(models.Model):
|
||||
equipment = models.ForeignKey(
|
||||
Equipment,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="attributes",
|
||||
verbose_name=_("matériel"),
|
||||
help_text=_("Matériel concerné par le defaut"),
|
||||
)
|
||||
attribute = models.ForeignKey(
|
||||
EquipmentAttribute,
|
||||
verbose_name=_("attribut"),
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
value = models.CharField(
|
||||
_("valeur"),
|
||||
max_length=200,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("attribut de matériel")
|
||||
verbose_name_plural = _("attributs de matériel")
|
||||
|
||||
def __str__(self):
|
||||
return "{attr}={value}".format(attr=self.attribute.name,
|
||||
value=self.value)
|
||||
|
||||
|
||||
class EquipmentAttribution(models.Model):
|
||||
equipment = models.ForeignKey(
|
||||
Equipment,
|
||||
verbose_name=_("matériel"),
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
activity = models.ForeignKey(
|
||||
Activity,
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
amount = models.BigIntegerField(_("quantité attribuée"))
|
||||
remarks = models.TextField(
|
||||
_("remarques concernant l'attribution"),
|
||||
blank=True,
|
||||
)
|
||||
equipment = models.ForeignKey(Equipment)
|
||||
activity = models.ForeignKey(Activity)
|
||||
amount = models.PositiveSmallIntegerField(_("quantité attribuée"))
|
||||
remarks = models.TextField(_("remarques concernant l'attribution"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("attribution de matériel")
|
||||
|
@ -265,72 +37,30 @@ class EquipmentAttribution(models.Model):
|
|||
|
||||
def __str__(self):
|
||||
return "%s (%d) -> %s" % (self.equipment.name,
|
||||
self.amount,
|
||||
self.amout,
|
||||
self.activity.get_herited('title'))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if (self.equipment.event
|
||||
and self.equipment.event != self.activity.event):
|
||||
if self.equipment.event and self.equipment.event != self.activity.event:
|
||||
raise ValidationError
|
||||
|
||||
super(EquipmentAttribution, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class EquipmentDefault(models.Model):
|
||||
remark = models.TextField(_("remarque sur le défaut"))
|
||||
class EquipmentRemark(models.Model):
|
||||
remark = models.TextField(_("remarque sur le matériel"))
|
||||
equipment = models.ForeignKey(
|
||||
Equipment,
|
||||
verbose_name=_("matériel"),
|
||||
on_delete=models.CASCADE,
|
||||
related_name="remarks",
|
||||
help_text=_("Matériel concerné par le defaut"),
|
||||
help_text=_("Matériel concerné par la remarque"),
|
||||
)
|
||||
ids = IdField()
|
||||
is_unusable = models.BooleanField(_("inutilisable"))
|
||||
send_repare = models.BooleanField(_("à envoyer réparareur"))
|
||||
amount = models.PositiveSmallIntegerField(_("quantité concernée"))
|
||||
is_broken = models.BooleanField()
|
||||
is_lost = models.BooleanField()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("defaut matériel")
|
||||
verbose_name_plural = _("défauts sur le matériel")
|
||||
|
||||
def __str__(self):
|
||||
return "%s : %s" % (self.equipment.name,
|
||||
self.remark)
|
||||
|
||||
|
||||
class EquipmentLost(models.Model):
|
||||
lost_at = models.DateField(
|
||||
_("perdu le"),
|
||||
default=date.today,
|
||||
)
|
||||
equipment = models.ForeignKey(
|
||||
Equipment,
|
||||
verbose_name=_("matériel"),
|
||||
on_delete=models.CASCADE,
|
||||
related_name="losts",
|
||||
help_text=_("Matériel concerné par la perte"),
|
||||
)
|
||||
ids = IdField()
|
||||
|
||||
|
||||
class EquipmentRevision(models.Model):
|
||||
date = models.DateField(
|
||||
_("date"),
|
||||
default=date.today,
|
||||
)
|
||||
equipment = models.ForeignKey(
|
||||
Equipment,
|
||||
verbose_name=_("matériel"),
|
||||
on_delete=models.CASCADE,
|
||||
related_name="revisions",
|
||||
help_text=_("Matériel concerné par les révisions"),
|
||||
)
|
||||
remark = models.TextField(_("remarque sur la révision"))
|
||||
ids = IdField()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("révision de matériel")
|
||||
verbose_name_plural = _("révisions de matériel")
|
||||
verbose_name = _("remarque sur matériel")
|
||||
verbose_name_plural = _("remarques sur le matériel")
|
||||
|
||||
def __str__(self):
|
||||
return "%s : %s" % (self.equipment.name,
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
.nice_select input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nice_select input[type="checkbox"]:checked + label {
|
||||
background: red;
|
||||
color:white;
|
||||
}
|
||||
|
||||
.nice_select ul {
|
||||
display: inline-block;
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db.models import Q
|
||||
from django.http.request import QueryDict
|
||||
|
||||
import django_filters
|
||||
from django_filters.widgets import LinkWidget
|
||||
from django_tables2.utils import A
|
||||
import django_tables2 as tables
|
||||
|
||||
from .models import Equipment, EquipmentCategory
|
||||
|
||||
|
||||
class EquipmentFilter(django_filters.FilterSet):
|
||||
owner = django_filters.ModelChoiceFilter(
|
||||
field_name='owner',
|
||||
queryset=Group.objects.all(),
|
||||
widget=LinkWidget(),
|
||||
)
|
||||
category = django_filters.ModelChoiceFilter(
|
||||
field_name='category',
|
||||
queryset=EquipmentCategory.objects.all(),
|
||||
widget=LinkWidget(),
|
||||
method='filter_category',
|
||||
)
|
||||
|
||||
def filter_category(self, queryset, name, value):
|
||||
return queryset.in_category(value)
|
||||
|
||||
def get_categories(self, qs):
|
||||
"""
|
||||
rend les catégories qui servent à filtrer les Equipments de qs
|
||||
ie les catégories des equipments et tous leurs parents
|
||||
"""
|
||||
filtre = Q(id__lt=0)
|
||||
for eq in qs:
|
||||
current = eq.category
|
||||
for k in range(100):
|
||||
if current is None:
|
||||
break
|
||||
filtre |= Q(id=current.id)
|
||||
current = current.parent
|
||||
return EquipmentCategory.objects.filter(filtre)
|
||||
|
||||
def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
|
||||
# On que les requêtes vides rendent quelque chose
|
||||
if data is None:
|
||||
data = QueryDict('category&owner')
|
||||
super().__init__(data=data, queryset=queryset,
|
||||
request=request, prefix=prefix)
|
||||
if self.queryset is not None:
|
||||
for filter_ in self.filters.values():
|
||||
if filter_.queryset.model == Group:
|
||||
own_ids = [eq.owner.id for eq in self.queryset
|
||||
if eq.owner is not None]
|
||||
filtre = Q(id__lt=0)
|
||||
for own_id in own_ids:
|
||||
filtre |= Q(id=own_id)
|
||||
filter_.queryset = Group.objects.filter(filtre)
|
||||
if filter_.queryset.model == EquipmentCategory:
|
||||
filter_.queryset = self.get_categories(self.queryset)
|
||||
|
||||
class Meta:
|
||||
model = Equipment
|
||||
fields = ['category', 'owner']
|
||||
|
||||
|
||||
class AbstractEquipmentTable(tables.Table):
|
||||
stock_aviable_p = tables.Column(
|
||||
accessor=A('stock_aviable_p'),
|
||||
orderable=False, # TODO le rendre ordorable
|
||||
verbose_name=_("Quantité disponible"),
|
||||
)
|
||||
full_category_p = tables.Column(
|
||||
accessor=A('full_category_p'),
|
||||
order_by=('category'),
|
||||
verbose_name=_("Catégorie"),
|
||||
)
|
||||
name = tables.LinkColumn(
|
||||
'equipment:detail',
|
||||
args=[A('pk')],
|
||||
verbose_name=_("Matériel"),
|
||||
)
|
||||
admin = tables.LinkColumn(
|
||||
'admin:equipment_equipment_change',
|
||||
attrs={
|
||||
'a': {'class': 'glyphicon glyphicon-cog'}
|
||||
},
|
||||
text="",
|
||||
orderable=False,
|
||||
args=[A('pk')],
|
||||
verbose_name=_(""),
|
||||
)
|
||||
|
||||
def before_render(self, request):
|
||||
if (request.user.is_staff and
|
||||
request.user.has_perm('equipment_change_equipment')):
|
||||
self.columns.show('admin')
|
||||
else:
|
||||
self.columns.hide('admin')
|
||||
|
||||
|
||||
class EquipmentTable(AbstractEquipmentTable):
|
||||
class Meta:
|
||||
model = Equipment
|
||||
template_name = 'equipment/tables/bootstrap-responsive.html'
|
||||
fields = ['name', 'stock', 'owner', ]
|
||||
sequence = ['admin', 'name', 'stock', 'stock_aviable_p',
|
||||
'full_category_p', 'owner', ]
|
|
@ -1,13 +0,0 @@
|
|||
{% extends "shared/base.html" %}
|
||||
{% load i18n staticfiles %}
|
||||
|
||||
{% block title %}{% trans "Matériel" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ equipment.name }}<a class="pull-right glyphicon glyphicon-cog" href="{% url 'admin:equipment_equipment_change' equipment.id %}"></a></h2>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block aside %}
|
||||
Coucou :)
|
||||
{% endblock %}
|
|
@ -1,50 +0,0 @@
|
|||
{% extends "shared/base.html" %}
|
||||
{% load i18n staticfiles %}
|
||||
|
||||
{% block title %}{% trans "Matériel" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="equipment">{% trans "Inventaire" %}</h1>
|
||||
<div class="module-list">
|
||||
<a href="{% url 'equipment:list' %}" class="module equipment">
|
||||
<span class="glyphicon glyphicon-list-alt"></span>
|
||||
{% trans "Tout le matériel" %}
|
||||
</a>
|
||||
<a href="#TODO" class="module equipment">
|
||||
<span class="glyphicon glyphicon-list-alt"></span>
|
||||
{% trans "Disponible" %}
|
||||
</a>
|
||||
</div>
|
||||
<h2 class="staff">{% trans "Liste par Propriétaire" %}</h2>
|
||||
<div class="module-list">
|
||||
{% for owner in owners %}
|
||||
<a href="{% url 'equipment:list_by_owner' owner.id %}" class="module staff">
|
||||
<span class="glyphicon glyphicon-user"></span>
|
||||
{{ owner.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h2 class="equipment">{% trans "Liste par Catégorie" %}</h2>
|
||||
<div class="tree">
|
||||
<ul>
|
||||
{% for node in root_cat %}
|
||||
{% include "equipment/tree_cat.html" %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block aside %}
|
||||
<div class="heading">
|
||||
{{ nb_type }} <span class="sub">{% trans "référence" %}{{ nb_type|pluralize}}</span>
|
||||
</div>
|
||||
<div class="heading separator">
|
||||
{{ stock }} <span class="sub">{% trans "item" %}{{ stock|pluralize}}</span>
|
||||
</div>
|
||||
<div class="heading inverted small">
|
||||
{{ categories.count }} <span class="sub">{% trans "catégorie" %}{{ categories.count|pluralize}}</span>
|
||||
</div>
|
||||
<div class="heading inverted small ">
|
||||
{{ owners.count }} <span class="sub">{% trans "propriéaire" %}{{ owners.count|pluralize}}</span>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,30 +0,0 @@
|
|||
{% extends "shared/base.html" %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load bootstrap3 %}
|
||||
{% load i18n staticfiles %}
|
||||
|
||||
{% block title %}{% trans "Matériel" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="equipment">Inventaire</h1>
|
||||
{% if subtitle %}
|
||||
<h2 class="equipment">{{ subtitle }}</h2>
|
||||
{% endif %}
|
||||
{% render_table table %}
|
||||
{% endblock %}
|
||||
|
||||
{% block aside %}
|
||||
<div class="heading">
|
||||
{{ nb_type }} <span class="sub">{% trans "référence" %}{{ nb_type|pluralize}}</span>
|
||||
</div>
|
||||
<div class="heading separator">
|
||||
{{ stock }} <span class="sub">{% trans "item" %}{{ stock|pluralize}}</span>
|
||||
</div>
|
||||
{% if filter %}
|
||||
<div class="text inverted">
|
||||
<form id="filter_form" action="" method="get" class="form form-inline">
|
||||
{% bootstrap_form filter.form layout='horizontal' size='lg' %}
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -1,16 +0,0 @@
|
|||
{% extends 'equipment/tables/bootstrap.html' %}
|
||||
|
||||
{% block table-wrapper %}
|
||||
<div class="table-container table-responsive">
|
||||
{% block table %}
|
||||
{{ block.super }}
|
||||
{% endblock table %}
|
||||
|
||||
{% if table.page and table.paginator.num_pages > 1 %}
|
||||
{% block pagination %}
|
||||
{{ block.super }}
|
||||
{% endblock pagination %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock table-wrapper %}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
{% load django_tables2 %}
|
||||
{% load i18n %}
|
||||
{% block table-wrapper %}
|
||||
<div class="table-container">
|
||||
{% block table %}
|
||||
<table {% render_attrs table.attrs class="table table-striped" %}>
|
||||
{% block table.thead %}
|
||||
{% if table.show_header %}
|
||||
<thead>
|
||||
<tr>
|
||||
{% for column in table.columns %}
|
||||
<th {{ column.attrs.th.as_html }}>
|
||||
{% if column.orderable %}
|
||||
<a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header }}</a>
|
||||
{% else %}
|
||||
{{ column.header }}
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
{% endblock table.thead %}
|
||||
{% block table.tbody %}
|
||||
<tbody>
|
||||
{% for row in table.paginated_rows %}
|
||||
{% block table.tbody.row %}
|
||||
<tr {{ row.attrs.as_html }}>
|
||||
{% for column, cell in row.items %}
|
||||
<td {{ column.attrs.td.as_html }}>{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endblock table.tbody.row %}
|
||||
{% empty %}
|
||||
{% if table.empty_text %}
|
||||
{% block table.tbody.empty_text %}
|
||||
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
|
||||
{% endblock table.tbody.empty_text %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endblock table.tbody %}
|
||||
{% block table.tfoot %}
|
||||
{% if table.has_footer %}
|
||||
<tfoot>
|
||||
<tr>
|
||||
{% for column in table.columns %}
|
||||
<td {{ column.attrs.tf.as_html }}>{{ column.footer }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tfoot>
|
||||
{% endif %}
|
||||
{% endblock table.tfoot %}
|
||||
</table>
|
||||
{% endblock table %}
|
||||
|
||||
{% if table.page and table.paginator.num_pages > 1 %}
|
||||
{% block pagination %}
|
||||
<nav aria-label="Table navigation">
|
||||
<ul class="pagination">
|
||||
{% if table.page.has_previous %}
|
||||
{% block pagination.previous %}
|
||||
<li class="previous">
|
||||
<a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}">
|
||||
<span aria-hidden="true">«</span>
|
||||
{% trans 'previous' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endblock pagination.previous %}
|
||||
{% endif %}
|
||||
{% if table.page.has_previous or table.page.has_next %}
|
||||
{% block pagination.range %}
|
||||
{% for p in table.page|table_page_range:table.paginator %}
|
||||
<li {% if p == table.page.number %}class="active"{% endif %}>
|
||||
{% if p == '...' %}
|
||||
<a href="#">{{ p }}</a>
|
||||
{% else %}
|
||||
<a href="{% querystring table.prefixed_page_field=p %}">
|
||||
{{ p }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endblock pagination.range %}
|
||||
{% endif %}
|
||||
|
||||
{% if table.page.has_next %}
|
||||
{% block pagination.next %}
|
||||
<li class="next">
|
||||
<a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}">
|
||||
{% trans 'next' %}
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endblock pagination.next %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock pagination %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock table-wrapper %}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<li> <a href="{% url "equipment:list_by_category" node.id %}"><span class="category_node">{{node.name}}</span></a>
|
||||
{%if node.children %}
|
||||
<ul>
|
||||
{%for ch in node.children.all %}
|
||||
{%with node=ch template_name="equipment/tree_cat.html" %}
|
||||
{%include template_name%}
|
||||
{%endwith%}
|
||||
{%endfor%}
|
||||
</ul>
|
||||
{%endif%}
|
||||
</li>
|
|
@ -1 +0,0 @@
|
|||
{% include "django/forms/widgets/input.html" %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{{ widget.label }}</label>
|
|
@ -1,5 +0,0 @@
|
|||
{% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }} nice_select"{% endif %} style="display: inline-block">{% for group, options, index in widget.optgroups %}{% if group %}
|
||||
<li>{{ group }}<ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>{% endif %}{% for option in options %}
|
||||
<li style="list-style-type: none;">{% include option.template_name with widget=option %}</li>{% endfor %}{% if group %}
|
||||
</ul></li>{% endif %}{% endfor %}
|
||||
</ul>{% endwith %}
|
|
@ -1,11 +0,0 @@
|
|||
from django.conf.urls import url
|
||||
from .views import EquipmentList, EquipmentView, EquipmentListByCategory, EquipmentListByOwner, EquipmentHome
|
||||
|
||||
app_name = 'equipment'
|
||||
urlpatterns = [
|
||||
url(r'^$', EquipmentHome.as_view(), name='home'),
|
||||
url(r'^all/$', EquipmentList.as_view(), name='list'),
|
||||
url(r'^(?P<pk>[0-9]+)/$', EquipmentView.as_view(), name='detail'),
|
||||
url(r'^c/(?P<pk>[0-9]+)/$', EquipmentListByCategory.as_view(), name='list_by_category'),
|
||||
url(r'^o/(?P<pk>[0-9]+)/$', EquipmentListByOwner.as_view(), name='list_by_owner'),
|
||||
]
|
|
@ -1,97 +0,0 @@
|
|||
from .models import Equipment, EquipmentCategory
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db.models import Sum
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
||||
from django_filters.views import FilterView
|
||||
from django_tables2.views import SingleTableMixin
|
||||
|
||||
from .tables import EquipmentTable, EquipmentFilter
|
||||
|
||||
|
||||
class EquipmentHome(LoginRequiredMixin, ListView):
|
||||
template_name = 'equipment/home.html'
|
||||
context_object_name = 'categories'
|
||||
model = EquipmentCategory
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
# TODO remplacer par les vrais owners
|
||||
context['owners'] = Group.objects.all()
|
||||
categories = (EquipmentCategory.objects.order_by('name')
|
||||
.prefetch_related('children'))
|
||||
context['root_cat'] = categories.filter(parent=None)
|
||||
queryset = Equipment.objects.all()
|
||||
context['stock'] = queryset.aggregate(Sum('stock'))['stock__sum']
|
||||
context['nb_type'] = queryset.count()
|
||||
return context
|
||||
|
||||
|
||||
class EquipmentListAbstract(LoginRequiredMixin, SingleTableMixin,FilterView):
|
||||
table_class = EquipmentTable
|
||||
filterset_class = EquipmentFilter
|
||||
template_name = 'equipment/list.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['stock'] = self.queryset.aggregate(Sum('stock'))['stock__sum']
|
||||
context['nb_type'] = self.queryset.count()
|
||||
return context
|
||||
|
||||
|
||||
class EquipmentList(EquipmentListAbstract):
|
||||
def get_queryset(self):
|
||||
self.queryset = Equipment.objects.all()
|
||||
return self.queryset
|
||||
|
||||
|
||||
class EquipmentListByCategory(EquipmentListAbstract):
|
||||
def get_category(self):
|
||||
try:
|
||||
pk = self.kwargs.get('pk')
|
||||
except KeyError:
|
||||
raise AttributeError(
|
||||
"View %s must be called with an object "
|
||||
"pk in the URLconf." % self.__class__.__name__
|
||||
)
|
||||
return EquipmentCategory.objects.get(id=pk)
|
||||
|
||||
def get_queryset(self):
|
||||
cat = self.get_category()
|
||||
self.queryset = Equipment.objects.all().in_category(cat)
|
||||
return self.queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
cat = self.get_category()
|
||||
context['subtitle'] = "Dans {cat}".format(cat=cat.full_name())
|
||||
return context
|
||||
|
||||
|
||||
class EquipmentListByOwner(EquipmentListAbstract):
|
||||
def get_owner(self):
|
||||
try:
|
||||
pk = self.kwargs.get('pk')
|
||||
except KeyError:
|
||||
raise AttributeError(
|
||||
"View %s must be called with an object "
|
||||
"pk in the URLconf." % self.__class__.__name__
|
||||
)
|
||||
return Group.objects.get(id=pk)
|
||||
|
||||
def get_queryset(self):
|
||||
owner = self.get_owner()
|
||||
self.queryset = Equipment.objects.filter(owner=owner)
|
||||
return self.queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
owner = self.get_owner()
|
||||
context['subtitle'] = "Matériel de {owner}".format(owner=owner)
|
||||
return context
|
||||
|
||||
|
||||
class EquipmentView(LoginRequiredMixin, DetailView):
|
||||
model = Equipment
|
||||
template_name = 'equipment/detail.html'
|
|
@ -2,6 +2,6 @@ import os
|
|||
from channels.asgi import get_channel_layer
|
||||
|
||||
if "DJANGO_SETTINGS_MODULE" not in os.environ:
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "poulpe.settings")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evenementiel.settings")
|
||||
|
||||
channel_layer = get_channel_layer()
|
|
@ -10,8 +10,6 @@ We also load the secrets in this file.
|
|||
|
||||
import os
|
||||
from . import secret
|
||||
from django.urls import reverse_lazy
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
def import_secret(name):
|
||||
|
@ -27,7 +25,6 @@ def import_secret(name):
|
|||
|
||||
SECRET_KEY = import_secret("SECRET_KEY")
|
||||
ADMINS = import_secret("ADMINS")
|
||||
SERVER_EMAIL = import_secret("SERVER_EMAIL")
|
||||
|
||||
DBNAME = import_secret("DBNAME")
|
||||
DBUSER = import_secret("DBUSER")
|
||||
|
@ -47,46 +44,31 @@ BASE_DIR = os.path.dirname(
|
|||
|
||||
|
||||
INSTALLED_APPS = [
|
||||
# 'shared.apps.CustomAdminConfig',
|
||||
'communication.apps.CommunicationConfig',
|
||||
'equipment.apps.EquipmentConfig',
|
||||
'event.apps.EventConfig',
|
||||
'users.apps.UsersConfig',
|
||||
'shared.apps.SharedConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.sites',
|
||||
|
||||
# 'channels',
|
||||
# 'rest_framework',
|
||||
'channels',
|
||||
'rest_framework',
|
||||
'bootstrapform',
|
||||
'widget_tweaks',
|
||||
'taggit',
|
||||
'django_tables2',
|
||||
'django_filters',
|
||||
'bootstrap3',
|
||||
|
||||
'allauth_ens',
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
'allauth_cas',
|
||||
'allauth_ens.providers.clipper',
|
||||
|
||||
# 'api',
|
||||
'communication',
|
||||
'equipment',
|
||||
'event',
|
||||
'shared',
|
||||
'users',
|
||||
'api',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
MIDDLEWARE_CLASSES = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
# 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
@ -99,7 +81,7 @@ REST_FRAMEWORK = {
|
|||
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
|
||||
}
|
||||
|
||||
ROOT_URLCONF = 'poulpe.urls'
|
||||
ROOT_URLCONF = 'evenementiel.urls'
|
||||
|
||||
STATIC_URL = "/static/"
|
||||
MEDIA_URL = "/media/"
|
||||
|
@ -137,19 +119,19 @@ DATABASES = {
|
|||
}
|
||||
}
|
||||
|
||||
# CHANNEL_LAYERS = {
|
||||
# "default": {
|
||||
# "BACKEND": "asgi_redis.RedisChannelLayer",
|
||||
# "CONFIG": {
|
||||
# "hosts": [(
|
||||
# "redis://:{passwd}@{host}:{port}/{db}"
|
||||
# .format(passwd=REDIS_PASSWD, host=REDIS_HOST,
|
||||
# port=REDIS_PORT, db=REDIS_DB)
|
||||
# )],
|
||||
# },
|
||||
# "ROUTING": "poulpe.routing.channel_routing",
|
||||
# }
|
||||
# }
|
||||
CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "asgi_redis.RedisChannelLayer",
|
||||
"CONFIG": {
|
||||
"hosts": [(
|
||||
"redis://:{passwd}@{host}:{port}/{db}"
|
||||
.format(passwd=REDIS_PASSWD, host=REDIS_HOST,
|
||||
port=REDIS_PORT, db=REDIS_DB)
|
||||
)],
|
||||
},
|
||||
"ROUTING": "evenementiel.routing.channel_routing",
|
||||
}
|
||||
}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
|
||||
|
@ -166,55 +148,12 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'fr-fr'
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'Europe/Paris'
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
)
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
|
||||
CAS_SERVER_URL = "https://cas.eleves.ens.fr/" # SPI CAS
|
||||
CAS_VERIFY_URL = "https://cas.eleves.ens.fr/"
|
||||
CAS_VERSION = "2"
|
||||
CAS_IGNORE_REFERER = True
|
||||
CAS_LOGIN_MSG = None
|
||||
CAS_REDIRECT_URL = reverse_lazy('shared:home')
|
||||
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
|
||||
CAS_FORCE_CHANGE_USERNAME_CASE = "lower"
|
||||
|
||||
LOGIN_URL = reverse_lazy('account_login')
|
||||
LOGOUT_URL = reverse_lazy('account_logout')
|
||||
LOGIN_REDIRECT_URL = reverse_lazy('shared:home')
|
||||
ACCOUNT_HOME_URL = reverse_lazy('shared:home')
|
||||
ACCOUNT_DETAILS_URL = reverse_lazy('shared:home')
|
||||
|
||||
|
||||
SOCIALACCOUNT_PROVIDERS = {
|
||||
# …
|
||||
|
||||
'clipper': {
|
||||
|
||||
# These settings control whether a message containing a link to
|
||||
# disconnect from the CAS server is added when users log out.
|
||||
'MESSAGE_SUGGEST_LOGOUT_ON_LOGOUT': True,
|
||||
'MESSAGE_SUGGEST_LOGOUT_ON_LOGOUT_LEVEL': messages.INFO,
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
ACCOUNT_ADAPTER = 'shared.allauth_adapter.AccountAdapter'
|
||||
#SOCIALACCOUNT_ADAPTER='allauth_ens.adapter.LongTermClipperAccountAdapter'
|
||||
SOCIALACCOUNT_ADAPTER= 'shared.allauth_adapter.SocialAccountAdapter'
|
||||
|
|
@ -11,12 +11,10 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
|||
DEBUG = True
|
||||
|
||||
# Add some debugging tools
|
||||
INSTALLED_APPS += ["debug_toolbar", ] # NOQA
|
||||
MIDDLEWARE = (
|
||||
[
|
||||
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
||||
]
|
||||
+ MIDDLEWARE # NOQA
|
||||
INSTALLED_APPS += ["debug_toolbar", "debug_panel"] # NOQA
|
||||
MIDDLEWARE_CLASSES = (
|
||||
["debug_panel.middleware.DebugPanelMiddleware"]
|
||||
+ MIDDLEWARE_CLASSES # NOQA
|
||||
)
|
||||
|
||||
|
|
@ -18,6 +18,6 @@ DATABASES = {
|
|||
CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "asgiref.inmemory.ChannelLayer",
|
||||
"ROUTING": "poulpe.routing.channel_routing",
|
||||
"ROUTING": "evenementiel.routing.channel_routing",
|
||||
},
|
||||
}
|
|
@ -5,23 +5,11 @@ from django.conf import settings
|
|||
from django.conf.urls import url, include
|
||||
from django.contrib import admin
|
||||
|
||||
#from django_cas_ng import views as django_cas_views
|
||||
from allauth_ens.views import capture_login, capture_logout
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/login/$', capture_login),
|
||||
url(r'^admin/logout/$', capture_logout),
|
||||
url(r'^compte/', include('allauth.urls')),
|
||||
# Admin
|
||||
url(r'^admin/', admin.site.urls),
|
||||
# Apps
|
||||
url(r'^equipment/', include('equipment.urls')),
|
||||
url(r'^event/', include('event.urls')),
|
||||
#url(r'^user/', include('users.urls')),
|
||||
# REST
|
||||
url(r'^user/', include('users.urls')),
|
||||
url(r'^api/', include('api.urls')),
|
||||
# Reste
|
||||
url(r'^', include('shared.urls')),
|
||||
]
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
WSGI config for GestionEvenementiel project.
|
||||
WSGI config for evenementiel project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
|
@ -11,6 +11,6 @@ import os
|
|||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "poulpe.settings")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evenementiel.settings")
|
||||
|
||||
application = get_wsgi_application()
|
|
@ -1 +0,0 @@
|
|||
default_app_config = 'event.apps.EventConfig'
|
|
@ -1,97 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Event, Place, ActivityTag, Activity, ActivityTemplate # TODO add me
|
||||
from equipment.models import EquipmentAttribution
|
||||
|
||||
|
||||
class EquipmentAttributionExtraInline(admin.TabularInline):
|
||||
autocomplete_fields = ['equipment', ]
|
||||
model = EquipmentAttribution
|
||||
extra = 0
|
||||
classes = ['collapse']
|
||||
|
||||
|
||||
class EventAdmin(admin.ModelAdmin):
|
||||
list_display = ['title', 'slug', 'beginning_date', 'ending_date']
|
||||
readonly_fields = ['created_by', 'created_at', ]
|
||||
ordering = ['title', 'beginning_date', 'ending_date', ]
|
||||
search_fields = ['title', 'decription', ]
|
||||
list_filter = ['beginning_date', 'ending_date', ]
|
||||
date_hierarchy = 'beginning_date'
|
||||
|
||||
|
||||
class PlaceAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'event', ]
|
||||
ordering = ['name', 'event', ]
|
||||
search_fields = ['name', ]
|
||||
list_filter = ['event', ]
|
||||
|
||||
|
||||
class ActivityTagAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'event', 'is_public', ]
|
||||
ordering = ['name', 'event', 'is_public', ]
|
||||
search_fields = ['name', ]
|
||||
list_filter = ['event', 'is_public', ]
|
||||
|
||||
|
||||
class ActivityTemplateAdmin(admin.ModelAdmin):
|
||||
save_as_continue = True
|
||||
save_on_top = True
|
||||
list_display = ['name', 'title', 'event', 'is_public', ]
|
||||
ordering = ['name', 'title', 'event', 'has_perm', ]
|
||||
search_fields = ['name', 'title', 'description', 'remark', ]
|
||||
list_filter = ['event', 'is_public', 'has_perm', 'tags', ]
|
||||
filter_horizontal = ['tags', 'places', ]
|
||||
fieldsets = (
|
||||
('Identifiant', {
|
||||
'fields': ('name', ),
|
||||
}),
|
||||
('Général', {
|
||||
'fields': ('event', 'title', 'is_public', 'places', ),
|
||||
'description': "Tous ces champs sont héritables (Sauf Évènement)",
|
||||
}),
|
||||
('Permanences', {
|
||||
'fields': ('has_perm', ('min_perm', 'max_perm', ), ),
|
||||
'classes': ('collapse',),
|
||||
'description': "Tous ces champs sont héritables",
|
||||
}),
|
||||
('Descriptions', {
|
||||
'fields': ('description', 'tags', 'remarks', ),
|
||||
'classes': ('collapse',),
|
||||
'description': "Tous ces champs sont héritables",
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
class ActivityAdmin(admin.ModelAdmin):
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_display = ['title', 'event', 'is_public', 'parent', ]
|
||||
ordering = ['title', 'event', 'has_perm', 'parent', ]
|
||||
search_fields = ['title', 'description', 'remark', ]
|
||||
list_filter = ['event', 'is_public', 'has_perm', 'tags', ]
|
||||
filter_horizontal = ['tags', 'places', 'staff', ]
|
||||
inlines = [EquipmentAttributionExtraInline, ]
|
||||
fieldsets = (
|
||||
('Général', {
|
||||
'fields': ('event', 'parent', 'title', 'is_public', 'beginning', 'end', 'places', ),
|
||||
'description': "Tous ces champs sont héritables (sauf parent et Évènement)",
|
||||
}),
|
||||
('Permanences', {
|
||||
'fields': ('has_perm', ('min_perm', 'max_perm', ), 'staff', ),
|
||||
'classes': ('wide',),
|
||||
'description': "Tous ces champs sont héritables (sauf les gens en perm)",
|
||||
}),
|
||||
('Descriptions', {
|
||||
'fields': ('description', 'tags', 'remarks', ),
|
||||
'classes': ('collapse',),
|
||||
'description': "Tous ces champs sont héritables",
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
admin.site.register(Event, EventAdmin)
|
||||
admin.site.register(Place, PlaceAdmin)
|
||||
admin.site.register(ActivityTag, ActivityTagAdmin)
|
||||
admin.site.register(ActivityTemplate, ActivityTemplateAdmin)
|
||||
admin.site.register(Activity, ActivityAdmin)
|
||||
# Register your models here.
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class EventConfig(AppConfig):
|
||||
name = 'event'
|
||||
verbose_name = _("Évènement")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.15 on 2018-08-06 07:51
|
||||
# Generated by Django 1.11.4 on 2017-08-12 12:47
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -74,8 +74,8 @@ class Migration(migrations.Migration):
|
|||
('slug', models.SlugField(help_text="Seulement des lettres, des chiffres ou les caractères '_' ou '-'.", unique=True, verbose_name='identificateur')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='date de création')),
|
||||
('description', models.TextField(verbose_name='description')),
|
||||
('beginning_date', models.DateTimeField(help_text="date publique de l'évènement", verbose_name='date de début')),
|
||||
('ending_date', models.DateTimeField(help_text="date publique de l'évènement", verbose_name='date de fin')),
|
||||
('beginning_date', models.DateTimeField(verbose_name='date de début')),
|
||||
('ending_date', models.DateTimeField(verbose_name='date de fin')),
|
||||
('created_by', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_events', to=settings.AUTH_USER_MODEL, verbose_name='créé par')),
|
||||
],
|
||||
options={
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.11 on 2018-08-20 15:29
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('event', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='activitytemplate',
|
||||
name='name',
|
||||
field=models.CharField(default='change_me!', help_text='Ne sera pas affiché', max_length=200, verbose_name='Nom du template'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='activity',
|
||||
name='event',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='activitytemplate',
|
||||
name='event',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'),
|
||||
),
|
||||
]
|
111
event/models.py
111
event/models.py
|
@ -1,5 +1,5 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import FieldDoesNotExist, FieldError, ValidationError
|
||||
from django.core.exceptions import FieldDoesNotExist, FieldError
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -123,6 +123,7 @@ class AbstractActivityTemplate(SubscriptionMixin, models.Model):
|
|||
Event,
|
||||
verbose_name=_("évènement"),
|
||||
on_delete=models.CASCADE,
|
||||
editable=False,
|
||||
)
|
||||
is_public = models.NullBooleanField(
|
||||
_("est public"),
|
||||
|
@ -166,34 +167,12 @@ class AbstractActivityTemplate(SubscriptionMixin, models.Model):
|
|||
|
||||
|
||||
class ActivityTemplate(AbstractActivityTemplate):
|
||||
name = models.CharField(
|
||||
_("Nom du template"),
|
||||
max_length=200,
|
||||
help_text=_("Ne sera pas affiché"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("template activité")
|
||||
verbose_name_plural = _("templates activité")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def clean(self):
|
||||
errors = []
|
||||
|
||||
# On clean les nombre de permanents
|
||||
if not self.has_perm:
|
||||
self.max_perm = None
|
||||
self.min_perm = None
|
||||
else:
|
||||
if self.min_perm > self.max_perm:
|
||||
errors.append(ValidationError(
|
||||
_("Nombres de permanents incompatibles"),
|
||||
code='wrong-nb-perm',
|
||||
))
|
||||
if errors != []:
|
||||
raise ValidationError(errors)
|
||||
return self.title
|
||||
|
||||
|
||||
class Activity(AbstractActivityTemplate):
|
||||
|
@ -214,86 +193,6 @@ class Activity(AbstractActivityTemplate):
|
|||
beginning = models.DateTimeField(_("heure de début"))
|
||||
end = models.DateTimeField(_("heure de fin"))
|
||||
|
||||
def clean(self):
|
||||
errors = []
|
||||
|
||||
# On clean les nombre de permanents
|
||||
if not self.get_herited('has_perm'):
|
||||
self.max_perm = None
|
||||
self.min_perm = None
|
||||
else:
|
||||
if self.get_herited('min_perm') > self.get_herited('max_perm'):
|
||||
errors.append(ValidationError(
|
||||
_("Nombres de permanents incompatibles"),
|
||||
code='wrong-nb-perm',
|
||||
))
|
||||
|
||||
# On valide l'héritage
|
||||
for f in self._meta.get_fields():
|
||||
try:
|
||||
# On réccupère le field du parent
|
||||
attrname = f.name
|
||||
tpl_field = ActivityTemplate._meta.get_field(attrname)
|
||||
# Peut-être que ce n'est pas un field
|
||||
# concerné par l'héritage
|
||||
except FieldDoesNotExist:
|
||||
continue
|
||||
|
||||
# Y'a certains champs dont on se moque
|
||||
if attrname in ['id', 'staff', 'tags', ]:
|
||||
continue
|
||||
|
||||
# C'est plus compliqué que ça pour les nb_perm
|
||||
if attrname in ['max_perm', 'min_perm', ]:
|
||||
if not self.get_herited('has_perm'):
|
||||
continue
|
||||
|
||||
|
||||
# On a un Many to Many, on lit différement
|
||||
if tpl_field.many_to_many:
|
||||
pass
|
||||
# # On a pas spécifié
|
||||
# if not value.exists():
|
||||
# # On a pas de parent
|
||||
# if self.parent is None:
|
||||
# errors.append(ValidationError(
|
||||
# _("N'hérite pas d'un template, spécifier le champs : %(attr)s"),
|
||||
# code='bad-overriding',
|
||||
# params={'attr': f.verbose_name},
|
||||
# ))
|
||||
# else:
|
||||
# pvalue = getattr(self.parent, attrname)
|
||||
# # On a un parent qui ne dit rien
|
||||
# if not pvalue.exists():
|
||||
# errors.append(ValidationError(
|
||||
# _("Champs non précisé chez le parent, spécifier : %(attr)s"),
|
||||
# code='bad-overriding',
|
||||
# params={'attr': f.verbose_name},
|
||||
# ))
|
||||
else:
|
||||
value = getattr(self, attrname)
|
||||
# On a pas spécifié
|
||||
if value is None:
|
||||
# On a pas de parent
|
||||
if self.parent is None:
|
||||
errors.append(ValidationError(
|
||||
_("N'hérite pas d'un template, spécifier le champs : %(attr)s"),
|
||||
code='bad-overriding',
|
||||
params={'attr': f.verbose_name},
|
||||
))
|
||||
else:
|
||||
pvalue = getattr(self.parent, attrname)
|
||||
# On a un parent qui ne dit rien
|
||||
if pvalue is None:
|
||||
errors.append(ValidationError(
|
||||
_("Champs non précisé chez le parent, spécifier : %(attr)s"),
|
||||
code='bad-overriding',
|
||||
params={'attr': f.verbose_name},
|
||||
))
|
||||
if errors != []:
|
||||
raise ValidationError(errors)
|
||||
|
||||
|
||||
def get_herited(self, attrname):
|
||||
try:
|
||||
tpl_field = ActivityTemplate._meta.get_field(attrname)
|
||||
|
@ -308,9 +207,9 @@ class Activity(AbstractActivityTemplate):
|
|||
if tpl_field.many_to_many:
|
||||
if value.exists():
|
||||
return value
|
||||
elif self.parent is not None:
|
||||
else:
|
||||
return getattr(self.parent, attrname)
|
||||
elif value is None and self.parent is not None:
|
||||
elif value is None:
|
||||
return getattr(self.parent, attrname)
|
||||
else:
|
||||
return value
|
||||
|
|
|
@ -1,373 +0,0 @@
|
|||
/* Calendar */
|
||||
|
||||
#cal-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
|
||||
min-height: 80vh;
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
#cal-container,
|
||||
#cal-container * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Time slots */
|
||||
|
||||
#cal-container .cal-time-slot-container {
|
||||
display: grid;
|
||||
grid-template-rows: 30px auto;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(100% + 30px + 10px);
|
||||
padding: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot {
|
||||
border-right: 1px solid #EEE;
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot:nth-child(even) {
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot-hour {
|
||||
padding: 0 0 0 calc(100% - 1.4rem + 7px);
|
||||
background-color: #F9F9F9;/* #3D3D3D; */
|
||||
border-bottom: 1px solid #AAA;
|
||||
color: #333;
|
||||
font-size: 1.4rem;
|
||||
line-height: 30px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot-hour:nth-child(even) {
|
||||
background-color: #FCFCFC;/* #464646; */
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot-hour:first-child {
|
||||
color: transparent;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot-hour.cal-last-hour {
|
||||
padding: 0;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot.cal-last-hour,
|
||||
#cal-container .cal-time-slot-hour.cal-last-hour {
|
||||
border-right: 1px solid #AAA;
|
||||
}
|
||||
|
||||
#cal-container .cal-time-slot.cal-first-hour,
|
||||
#cal-container .cal-time-slot-hour.cal-first-hour {
|
||||
border-left: 1px solid #AAA;
|
||||
}
|
||||
|
||||
/* Events */
|
||||
|
||||
#cal-container .cal-event-container {
|
||||
display: grid;
|
||||
/* grid-template-columns: repeat(24, 1fr); */
|
||||
/* grid-template-rows: repeat(12, auto); */
|
||||
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#cal-container .cal-event {
|
||||
position: relative;
|
||||
height: 80px;
|
||||
margin: 2px 0;
|
||||
/* padding: 5px; */
|
||||
/* background-color: #EFEFEF; */
|
||||
border-radius: 3px;
|
||||
/* border: 1px solid #CCC; */
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
/* z-index: 500; */
|
||||
transition: 50ms ease-in;
|
||||
}
|
||||
|
||||
#cal-container .cal-event:hover {
|
||||
/* background-color: #FEDDDD; */
|
||||
}
|
||||
|
||||
#cal-container .cal-event > * {
|
||||
display: none;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#cal-container .cal-event > .cal-event-name,
|
||||
#cal-container .cal-event > .cal-event-location,
|
||||
#cal-container .cal-event > .cal-event-perm-count {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#cal-container .cal-event > .cal-event-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#cal-container .cal-event > .cal-event-location {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#cal-container .cal-event > .cal-event-perm-count {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#cal-container .cal-event:not(.cal-event-subscribed) > .cal-event-perm-count.cal-perms-missing {
|
||||
width: calc(100% - 10px);
|
||||
right: auto;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
background-color: #FFF;
|
||||
border: 2px solid #E44;
|
||||
color: #E44;
|
||||
font-weight: bold;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#cal-container .cal-event.cal-event-subscribed {
|
||||
border-width: 3px;
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
#cal-container .cal-event.cal-event-subscribed::after {
|
||||
content: "✔";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 1px;
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
/* Event details popup */
|
||||
|
||||
#cal-container .cal-event-details {
|
||||
position: absolute;
|
||||
min-height: 100px;
|
||||
/* min-width: 40%; */
|
||||
max-width: 80%;
|
||||
padding: 20px;
|
||||
background-color: #333;
|
||||
color: #FFF;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 15px 50px rgba(0, 0, 0, 0.6);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details:after {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-bottom-color: #333;
|
||||
border-width: 20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details.above-event:after {
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-top-color: #333;
|
||||
border-width: 20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details * {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-close-button {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
font-size: 1.6rem;
|
||||
color: #BBB;
|
||||
transition: 100ms ease-out;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-close-button:hover {
|
||||
background-color: #484848;
|
||||
color: #EFEFEF;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details a,
|
||||
#cal-container .cal-event-details a:hover {
|
||||
color: #FFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-name > h3 {
|
||||
margin: 0 0 25px 26px;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
color: #FFF;
|
||||
font-size: 2.5rem;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-name > h3::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 0 0 10px;
|
||||
vertical-align: middle;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAA90lEQVQoz2WRsS6DURiGn/yaaNqBySpGicFg6iJcAYuuNBaJpJEg6gLcADFIdWR0BZZKS4SBRTe3YFf/Y/j/c3LUe4Zz3vd78+U734uUJ7Ptg7k68NDpoIdyU9V3TzzwRdXt1HCq9pwR510W616oZ8Gwoe6KWFN1ScStogui3sRJ9uxYLd/n6hTuaCy3XHfNWuR6hM+OojBQdSXyJ0cZizwSsMo3kEc+ZCEjxZgxE8j4oBFZhRww8gaff4fEL3UuGfK4uG5L4VLVfvrNCrDJHfd0gSrXQB2AJvu0+Cm8HbXnbGw9seqwWH2z65Wv/8MKcfdVHaZx/wKtOg5kifzQhwAAAABJRU5ErkJggg==);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-name:hover > h3 {
|
||||
margin-right: 26px;
|
||||
margin-bottom: 10px;
|
||||
background-color: #484848;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-name:hover > h3::after {
|
||||
content: "Cliquez pour afficher les détails.";
|
||||
display: block;
|
||||
width: auto;
|
||||
height: 15px;
|
||||
padding: 2px 0 0 0;
|
||||
font-size: 1.2rem;
|
||||
background-image: none;
|
||||
color: #DDD;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-name:hover + .cal-detail-close-button {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details table {
|
||||
margin: 0 auto;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details td.cal-detail-label {
|
||||
padding: 0 10px 10px 0;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details td.cal-detail-value {
|
||||
padding: 0 0 10px 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-perm-area {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
background-color: #DFDFDF;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-perm-title {
|
||||
display: block;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-perm-area .cal-detail-perm-count {
|
||||
margin: 0 10px 0 0;
|
||||
font-size: 2.5rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-perm-area .cal-detail-perm-count.cal-perms-missing {
|
||||
color: #E44;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-perm-area .cal-detail-perm-count.cal-perms-full {
|
||||
color: #393;
|
||||
}
|
||||
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-perm-area .cal-detail-perm-subscription-switch {
|
||||
margin: 0 0 0 10px;
|
||||
padding: 10px;
|
||||
font-size: 1.8rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-perm-area .cal-detail-perm-nb-missing-perms {
|
||||
margin: 20px 0 0 0;
|
||||
padding: 5px;
|
||||
background-color: #FFF;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
color: #E44;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-description {
|
||||
margin: 20px 0 20px 0;
|
||||
color: #DDD;
|
||||
font-size: 1.8rem;
|
||||
font-style: italic;
|
||||
text-align: justify;
|
||||
line-height: 120%;
|
||||
}
|
||||
|
||||
#cal-container .cal-event-details .cal-detail-tag {
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border: 1px solid #DDD;
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/* Tipso Bubble Styles */
|
||||
.tipso_bubble, .tipso_bubble > .tipso_arrow{
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.tipso_bubble {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
z-index: 9999;
|
||||
}
|
||||
.tipso_style{
|
||||
/* cursor: help; */
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
.tipso_title {
|
||||
padding: 3px 0;
|
||||
border-radius: 6px 6px 0 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
.tipso_content {
|
||||
word-wrap: break-word;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
/* Tipso Bubble size classes - Similar to Foundation's syntax*/
|
||||
.tipso_bubble.tiny {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
.tipso_bubble.small {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.tipso_bubble.default {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.tipso_bubble.large {
|
||||
font-size: 1.2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tipso_bubble.cal_small {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
/* Tipso Bubble Div */
|
||||
.tipso_bubble > .tipso_arrow{
|
||||
position: absolute;
|
||||
width: 0; height: 0;
|
||||
border: 8px solid;
|
||||
pointer-events: none;
|
||||
}
|
||||
.tipso_bubble.top > .tipso_arrow {
|
||||
border-top-color: #000;
|
||||
border-right-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
}
|
||||
.tipso_bubble.bottom > .tipso_arrow {
|
||||
border-bottom-color: #000;
|
||||
border-right-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-top-color: transparent;
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
}
|
||||
.tipso_bubble.left > .tipso_arrow {
|
||||
border-left-color: #000;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-right-color: transparent;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
margin-top: -8px;
|
||||
}
|
||||
.tipso_bubble.right > .tipso_arrow {
|
||||
border-right-color: #000;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
top: 50%;
|
||||
right: 100%;
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
.tipso_bubble .top_right_corner,
|
||||
.tipso_bubble.top_right_corner {
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.tipso_bubble .bottom_right_corner,
|
||||
.tipso_bubble.bottom_right_corner {
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
.tipso_bubble .top_left_corner,
|
||||
.tipso_bubble.top_left_corner {
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.tipso_bubble .bottom_left_corner,
|
||||
.tipso_bubble.bottom_left_corner {
|
||||
border-top-right-radius: 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,18 +0,0 @@
|
|||
$(function(){
|
||||
function initEnrolment(elt) {
|
||||
elt = $(elt);
|
||||
elt.find("form.enrolment").on("submit", function() {
|
||||
elt.addClass("sending-request");
|
||||
var form = this;
|
||||
var url = form.action + "?ajax";
|
||||
$.post(url, $(form).serialize(), function(data) {
|
||||
elt.html(data);
|
||||
elt.removeClass("sending-request");
|
||||
initEnrolment(elt);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
$.each($(".activity-summary"), function(i, item) { initEnrolment(item) });
|
||||
});
|
|
@ -1,84 +0,0 @@
|
|||
// Interval graph coloring algorithm, by Twal
|
||||
|
||||
class IntervalColoration {
|
||||
constructor (intervals) {
|
||||
this.intervals = intervals;
|
||||
this.n = this.intervals.length;
|
||||
this.computeInterferenceGraph();
|
||||
this.computePEO();
|
||||
this.computeColoration();
|
||||
}
|
||||
|
||||
computeInterferenceGraph() {
|
||||
this.adj = new Array(this.n);
|
||||
for (let i = 0; i < this.n; ++i) {
|
||||
this.adj[i] = [];
|
||||
}
|
||||
for (let i = 0; i < this.n; ++i) {
|
||||
for (let j = 0; j < i; ++j) {
|
||||
let inti = this.intervals[i];
|
||||
let intj = this.intervals[j];
|
||||
if (inti[0] < intj[1] && intj[0] < inti[1]) {
|
||||
this.adj[i].push(j);
|
||||
this.adj[j].push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Perfect elimination order using Maximum Cardinality Search
|
||||
//Runs in O(n^2), could be optimized in O(n log n)
|
||||
computePEO() {
|
||||
let marked = new Array(this.n);
|
||||
let nbMarkedNeighbor = new Array(this.n);
|
||||
this.perm = new Array(this.n);
|
||||
for (let i = 0; i < this.n; ++i) {
|
||||
marked[i] = false;
|
||||
nbMarkedNeighbor[i] = 0;
|
||||
}
|
||||
for (let k = this.n-1; k >= 0; --k) {
|
||||
let maxi = -1;
|
||||
for (let i = 0; i < this.n; ++i) {
|
||||
if (!marked[i] && (maxi == -1 || nbMarkedNeighbor[i] >= nbMarkedNeighbor[maxi])) {
|
||||
maxi = i;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < this.adj[maxi].length; ++i) {
|
||||
nbMarkedNeighbor[this.adj[maxi][i]] += 1;
|
||||
}
|
||||
this.perm[maxi] = k;
|
||||
marked[maxi] = true;
|
||||
}
|
||||
// console.log(this.perm);
|
||||
}
|
||||
|
||||
computeColoration() {
|
||||
this.colors = new Array(this.n);
|
||||
let isColorUsed = new Array(this.n);
|
||||
for (let i = 0; i < this.n; ++i) {
|
||||
this.colors[i] = -1;
|
||||
isColorUsed[i] = false;
|
||||
}
|
||||
for (let i = 0; i < this.n; ++i) {
|
||||
let ind = this.perm[i];
|
||||
for (let j = 0; j < this.adj[ind].length; ++j) {
|
||||
let neigh = this.adj[ind][j];
|
||||
if (this.colors[neigh] >= 0) {
|
||||
isColorUsed[this.colors[neigh]] = true;
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < this.n; ++j) {
|
||||
if (!isColorUsed[j]) {
|
||||
this.colors[ind] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < this.adj[ind].length; ++j) {
|
||||
let neigh = this.adj[ind][j];
|
||||
if (this.colors[neigh] >= 0) {
|
||||
isColorUsed[this.colors[neigh]] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
event/static/js/tipso.min.js
vendored
1
event/static/js/tipso.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1,52 +0,0 @@
|
|||
{% extends "shared/base.html" %}
|
||||
{% load i18n staticfiles event_tags %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block title %}{% trans "Activity" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ activity.title}}
|
||||
{% if user.is_staff %}
|
||||
<a class='glyphicon glyphicon-cog pull-right' href='{% url "admin:event_activity_change" activity.id %}'></a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% include "event/activity_summary.html" with activity=activity %}
|
||||
|
||||
<h2>Description</h2>
|
||||
<p><strong>Description</strong>{{activity.description|default:" - "}}</p>
|
||||
<p><strong>Remarque (staff)</strong>{{activity.remark|default:" - "}}</p>
|
||||
<button class="collapsible active"><h3>Matériel</h3></button>
|
||||
<div class="content fluid">
|
||||
<table class="table table-responsive table-striped">
|
||||
<tr>
|
||||
<th>Matériel</th>
|
||||
<th>Quantité</th>
|
||||
<th>Propriétaire</th>
|
||||
<th>Remarque</th>
|
||||
</tr>
|
||||
{% for att in attributions %}
|
||||
<tr>
|
||||
<td><a href="{% url 'equipment:detail' att.equipment.id %}">
|
||||
{{ att.equipment }}</a></td>
|
||||
<td>{{ att.amount }}</td>
|
||||
<td>{{ att.equipment.owner }}</td>
|
||||
<td>{{ att.remark }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block aside %}
|
||||
<div class="text">
|
||||
Du
|
||||
<strong>
|
||||
{{ activity.beginning | date:"l d F Y H:i" }}
|
||||
</strong>
|
||||
au
|
||||
<strong>
|
||||
{{ activity.end | date:"l d F Y H:i" }}
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,79 +0,0 @@
|
|||
{% load i18n event_tags %}
|
||||
{% with activity|get_herited:'has_perm' as has_perm %}
|
||||
<table class="table table-responsive table-striped">
|
||||
<tr>
|
||||
<td>
|
||||
<span class="glyphicon glyphicon-tree-deciduous"></span>
|
||||
{% with activity|get_herited:'places' as places %}
|
||||
{% if places.all %}
|
||||
<span>{{ places.all |join:", "}}</span>
|
||||
{% else %}
|
||||
<span> - </span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
<td>
|
||||
<strong>public</strong>
|
||||
:
|
||||
{% with activity|get_herited:'is_public' as is_public %}
|
||||
<span class="glyphicon {{ is_public|yesno:"yes glyphicon-ok-sign, no glyphicon-remove-sign, dunno glyphicon-question-sign"}}"></span>
|
||||
{% endwith %}
|
||||
</td>
|
||||
<tr>
|
||||
</tr>
|
||||
<td>
|
||||
<span class="glyphicon glyphicon-duplicate"></span>
|
||||
{% if activity.parent %}
|
||||
<span>{{ activity.parent}}</span>
|
||||
{% else %}
|
||||
<span> - </span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<strong>perm</strong>
|
||||
:
|
||||
<span class="glyphicon {{ has_perm|yesno:"yes glyphicon-ok-sign, no glyphicon-remove-sign, dunno glyphicon-question-sign"}}"></span>
|
||||
</td>
|
||||
<tr>
|
||||
</tr>
|
||||
<td>
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
{% with activity|get_herited:'tags' as tags %}
|
||||
{% if tags.all %}
|
||||
<span>{{ tags.all |join:", "}}</span>
|
||||
{% else %}
|
||||
<span> - </span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
<td>
|
||||
{% if has_perm %}
|
||||
{{ activity|get_herited:'min_perm' }}
|
||||
≤
|
||||
<strong>{{ activity.staff.count }}</strong>
|
||||
≤
|
||||
{{ activity|get_herited:'max_perm' }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% if has_perm %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<strong>En perm : </strong>
|
||||
{% with activity.staff.all as staff %}
|
||||
{% if staff %}
|
||||
<span>{{ staff |join:", "}}</span>
|
||||
{% else %}
|
||||
<span> - </span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{% enrol_btn activity request.user %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
|
@ -1,2 +1,25 @@
|
|||
{% extends "shared/base.html" %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block sidenav %}
|
||||
<div class="centered">
|
||||
<h5 class="centered banner-text">La Nuit 2017</h5>
|
||||
</div>
|
||||
|
||||
<li>
|
||||
<a href="index.html">
|
||||
<i class="fa fa-dashboard"></i>
|
||||
<span>Looool</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="sub-menu">
|
||||
<a href="javascript:;" >
|
||||
<i class="fa fa-desktop"></i>
|
||||
<span>Prout</span>
|
||||
</a>
|
||||
<ul class="sub">
|
||||
<li><a href="general.html">Lolilol</a></li>
|
||||
<li><a href="buttons.html">Lorem</a></li>
|
||||
<li><a href="panels.html">Ipsum</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
{% extends "shared/fluid.html" %}
|
||||
{% load i18n staticfiles event_tags %}
|
||||
|
||||
{% block extra_css %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" href="{% static "css/tipso.css" %}">
|
||||
<link rel="stylesheet" href="{% static "css/calendar.css" %}">
|
||||
|
||||
<style>
|
||||
#cal-toggle-unsubscribed-events-display {
|
||||
display: block;
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
left: 30px;
|
||||
border-bottom: 2px solid rgb(150, 50, 50);
|
||||
font-size: 1.6rem;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4),
|
||||
0 1px 1px rgba(150, 50, 50, 0.7);
|
||||
text-shadow: 0 0 7px rgb(150, 50, 50);
|
||||
z-index: 5000;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript" src="{% static "js/tipso.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "js/interval_coloration.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "js/calendar.js" %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
let calendar = new Calendar({
|
||||
startDate: new Date(2018, 10, 30, 8),
|
||||
endDate: new Date(2018, 11, 2, 6),
|
||||
eventDetailURLFormat: "https://cof.ens.fr/poulpe/event/activity/999999",
|
||||
subscriptionURLFormat: "{% url "event:enrol_activity" 999999 %}?ajax=json",
|
||||
csrfToken: $(".planning [name=csrfmiddlewaretoken]").val(),
|
||||
groupEventsByLocation: true
|
||||
});
|
||||
|
||||
// TODO: move this elsewhere
|
||||
// Button to switch between:
|
||||
// - displaying all events (default);
|
||||
// - only displaying events for which the current user is enroled.
|
||||
|
||||
// Create the button
|
||||
let toggleUnsubscribedEventDisplayButton = $("<button>")
|
||||
.attr("type", "button")
|
||||
.attr("id", "cal-toggle-unsubscribed-events-display")
|
||||
.addClass("btn btn-primary")
|
||||
.appendTo(calendar.containerNode);
|
||||
|
||||
// Set/update its label
|
||||
function updateToggleButtonLabel () {
|
||||
if (calendar.onlyDisplaySubscribedEvents) {
|
||||
toggleUnsubscribedEventDisplayButton.html("Afficher toutes les activités");
|
||||
}
|
||||
else {
|
||||
toggleUnsubscribedEventDisplayButton.html("Afficher seulement mes permanences");
|
||||
}
|
||||
}
|
||||
|
||||
updateToggleButtonLabel();
|
||||
|
||||
// Switch between display modes on click
|
||||
toggleUnsubscribedEventDisplayButton.on("click", () => {
|
||||
calendar.toggleEventsNotSubscribedByUser();
|
||||
updateToggleButtonLabel();
|
||||
});
|
||||
|
||||
|
||||
// DEBUG: js console helpers, to be removed
|
||||
console.log(calendar);
|
||||
window["cal"] = calendar;
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="planning">
|
||||
{% csrf_token %}
|
||||
{% regroup activities by beginning|date:"Y-m-d" as days_list %}
|
||||
<div class="content fluid" id="cal-container">
|
||||
{% for day in days_list %}
|
||||
{% for activity in day.list %}
|
||||
<div class="cal-event">
|
||||
<span class="cal-event-id">{{ activity.id }}</span>
|
||||
<span class="cal-event-name">{{ activity|get_herited:'title' }}</span>
|
||||
<span class="cal-event-start-date">{{ activity.beginning | date:"j/m/Y H:i" }}</span>
|
||||
<span class="cal-event-end-date">{{ activity.end | date:"j/m/Y H:i" }}</span>
|
||||
{% with activity|get_herited:'places' as places %}
|
||||
<span class="cal-event-location">{{ places.all | join:", " }}</span>
|
||||
{% endwith %}
|
||||
<span class="cal-event-description">{{ activity.description }}</span>
|
||||
<span class="cal-event-url">{% url "event:activity" activity.id %}</span>
|
||||
|
||||
{% if activity|get_herited:'has_perm' %}
|
||||
<span class="cal-event-has-perms">1</span>
|
||||
<span class="cal-event-min-nb-perms">{{ activity|get_herited:'min_perm' }}</span>
|
||||
<span class="cal-event-max-nb-perms">{{ activity|get_herited:'max_perm' }}</span>
|
||||
<span class="cal-event-nb-perms">{{ activity.staff.count }}</span>
|
||||
<span class="cal-event-subscribed">{% is_enrolled activity request.user %}</span>
|
||||
{% endif %}
|
||||
|
||||
{% with activity|get_herited:'tags' as tags %}
|
||||
{% for tag in tags.all %}
|
||||
<span class="cal-event-tag">{{ tag.name }}</span>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,101 +0,0 @@
|
|||
{% extends "shared/base.html" %}
|
||||
{% load i18n staticfiles event_tags %}
|
||||
|
||||
{% block title %}{% trans "Évènement" %}{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript" src="{% static "js/enrol_event.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ event.title}}
|
||||
{% if perms.event.event_can_change and user.is_staff %}
|
||||
<a class='glyphicon glyphicon-cog pull-right' href='{% url "admin:event_event_change" event.id %}'></a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
<p>{{ event.description }}</p>
|
||||
<h2>Boîte à outils</h2>
|
||||
<div class="module-list">
|
||||
<a href="#TODO" class="module">
|
||||
<span class="glyphicon glyphicon-duplicate"></span>
|
||||
Templates d'activité
|
||||
</a>
|
||||
<a href="#TODO" class="module">
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
Tags spécifiques
|
||||
</a>
|
||||
<a href="#todo" class="module">
|
||||
<span class="glyphicon glyphicon-tree-deciduous"></span>
|
||||
lieux spécifiques
|
||||
</a>
|
||||
<a href="{% url "event:calendar" event.slug %}" class="module">
|
||||
Calendrier
|
||||
</a>
|
||||
{% if staffuser %}
|
||||
<a href="{% url "event:event" event.slug %}" class="module">
|
||||
Toutes les activités
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% url "event:event-staff" event.slug user.username %}" class="module">
|
||||
Mes perms
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if staffuser %}
|
||||
<h2>Perms de {{ staffuser.first_name }} {{ staffuser.last_name }}</h2>
|
||||
{% else %}
|
||||
<h2>Planning</h2>
|
||||
{% endif %}
|
||||
|
||||
<div class="planning">
|
||||
{% regroup activities by beginning|date:"Y-m-d" as days_list %}
|
||||
{% for day in days_list %}
|
||||
{% with day.list|first as f_act %}
|
||||
<button class="collapsible active"><h3>{{ f_act.beginning|date:"l d F" }}</h3></button>
|
||||
<div class="content fluid">
|
||||
{% endwith %}
|
||||
{% for activity in day.list %}
|
||||
<div class="{% cycle "" "inverted" %} activity">
|
||||
<div class="activity-title">
|
||||
<h4>
|
||||
{% if perms.event.activity_can_change and user.is_staff %}
|
||||
<a class='glyphicon glyphicon-cog' href='{% url "admin:event_activity_change" activity.id %}'></a>
|
||||
{% endif %}
|
||||
<a href="{% url "event:activity" activity.id %}">
|
||||
{{ activity|get_herited:'title' }}
|
||||
</a>
|
||||
</h4>
|
||||
<span class="pull-right">
|
||||
de <strong>{{ activity.beginning | time:"H:i" }}</strong>
|
||||
à <strong>{{ activity.end| time:"H:i" }}</strong>
|
||||
</span>
|
||||
<div class="activity-summary">
|
||||
{% include "event/activity_summary.html" with activity=activity %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block aside %}
|
||||
<div class="heading separator">
|
||||
{{ activities.count }} <span class="sub">activité{{ activities.count|pluralize }}</span>
|
||||
</div>
|
||||
<div class="text inverted">
|
||||
<p>Créé le {{ event.created_at | date:"l d F Y à H:i" }} par {{ event.created_by }}</p>
|
||||
<p>
|
||||
Du
|
||||
<strong>
|
||||
{{ event.beginning_date | date:"l d F Y H:i" }}
|
||||
</strong>
|
||||
au
|
||||
<strong>
|
||||
{{ event.ending_date | date:"l d F Y H:i" }}
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,6 +0,0 @@
|
|||
{% load i18n %}
|
||||
<form method="POST" action="{% url "event:enrol_activity" activity.pk %}" class="enrolment {{ enrolled|yesno:"enrolled,unenrolled" }}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="goal" value="{{ enrolled|yesno:"unenrol,enrol" }}" />
|
||||
{{ enrolled|yesno:_("Inscrit,") }} <input type="submit" value="{{ enrolled|yesno:_("Se désinscrire,S'inscrire") }}" class="btn btn-warning"/>
|
||||
</form>
|
|
@ -1,21 +0,0 @@
|
|||
from django import template
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter()
|
||||
def get_herited(activity, attrname):
|
||||
return activity.get_herited(attrname)
|
||||
|
||||
@register.inclusion_tag("event/tags/enrol_btn.html")
|
||||
def enrol_btn(activity, user):
|
||||
return {
|
||||
"enrolled": activity.staff.filter(id=user.id).exists(),
|
||||
"activity": activity,
|
||||
}
|
||||
|
||||
@register.simple_tag
|
||||
def is_enrolled(activity, user):
|
||||
user_is_enrolled = activity.staff.filter(id=user.id).exists()
|
||||
return "1" if user_is_enrolled else "0"
|
|
@ -1,14 +1,7 @@
|
|||
from django.conf.urls import url
|
||||
from event.views import Index, EventView, EventViewStaff, ActivityView, EnrolActivityView, EventCalendar
|
||||
from event.views import Index
|
||||
|
||||
app_name = 'event'
|
||||
urlpatterns = [
|
||||
# url(r'^$', Index.as_view(), name='index'),
|
||||
url(r'^(?P<slug>[-\w]+)/$', EventView.as_view(), name='event'),
|
||||
url(r'^(?P<slug>[-\w]+)/s/(?P<username>[-\w]+)/$', EventViewStaff.as_view(), name='event-staff'),
|
||||
url(r'^(?P<slug>[-\w]+)/calendar/$', EventCalendar.as_view(), name='calendar'),
|
||||
url(r'^activity/(?P<pk>[0-9]+)/$', ActivityView.as_view(),
|
||||
name='activity'),
|
||||
url(r'^activity/(?P<pk>[0-9]+)/enrol/$',
|
||||
EnrolActivityView.as_view(), name="enrol_activity"),
|
||||
url(r'^$', Index.as_view(), name='index'),
|
||||
]
|
||||
|
|
|
@ -1,97 +1,5 @@
|
|||
from django.views.generic import TemplateView, DetailView, View
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.http import JsonResponse, HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Event, Activity
|
||||
from equipment.models import EquipmentAttribution
|
||||
|
||||
User = get_user_model()
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
|
||||
class Index(TemplateView):
|
||||
template_name = "event/index.html"
|
||||
|
||||
|
||||
class EventCalendar(LoginRequiredMixin, DetailView):
|
||||
model = Event
|
||||
template_name = 'event/calendar.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
event = self.object
|
||||
context['activities'] = (Activity.objects.filter(event=event)
|
||||
.order_by('beginning').prefetch_related(
|
||||
'tags', 'places', 'staff', 'parent'))
|
||||
return context
|
||||
|
||||
|
||||
class EventView(LoginRequiredMixin, DetailView):
|
||||
model = Event
|
||||
template_name = 'event/event.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
event = self.object
|
||||
context['activities'] = (Activity.objects.filter(event=event)
|
||||
.order_by('beginning').prefetch_related(
|
||||
'tags', 'places', 'staff', 'parent'))
|
||||
return context
|
||||
|
||||
|
||||
class EventViewStaff(LoginRequiredMixin, DetailView):
|
||||
model = Event
|
||||
template_name = 'event/event.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
user = User.objects.get(username=self.kwargs['username'])
|
||||
event = self.object
|
||||
context['staffuser'] = user
|
||||
context['activities'] = (user.in_perm_activities
|
||||
.filter(event=event)
|
||||
.order_by('beginning')
|
||||
.prefetch_related(
|
||||
'tags', 'places', 'staff', 'parent')
|
||||
)
|
||||
return context
|
||||
|
||||
|
||||
class ActivityView(LoginRequiredMixin, DetailView):
|
||||
model = Activity
|
||||
template_name = 'event/activity.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
activity = self.object
|
||||
context['attributions'] = (EquipmentAttribution.objects
|
||||
.filter(activity=activity)
|
||||
.prefetch_related('equipment'))
|
||||
return context
|
||||
|
||||
|
||||
class EnrolActivityView(LoginRequiredMixin, View):
|
||||
http_method_names = ['post']
|
||||
|
||||
def post(self, request, pk, *args, **kwargs):
|
||||
activity = get_object_or_404(Activity, id=pk)
|
||||
action = request.POST.get("goal", None)
|
||||
success = True
|
||||
if action == "enrol":
|
||||
activity.staff.add(request.user)
|
||||
elif action == "unenrol":
|
||||
activity.staff.remove(request.user)
|
||||
else:
|
||||
success = False
|
||||
if "ajax" in request.GET:
|
||||
if request.GET["ajax"] == "json":
|
||||
enrols = activity.staff
|
||||
return JsonResponse({
|
||||
"enrolled": enrols.filter(id=request.user.id).exists(),
|
||||
"number": enrols.count(),
|
||||
})
|
||||
return render(request, "event/activity_summary.html",
|
||||
{"activity": activity})
|
||||
return HttpResponseRedirect(reverse("event:activity", kwargs={"pk":pk}))
|
||||
|
|
|
@ -3,7 +3,7 @@ import os
|
|||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "poulpe.settings.devlocal")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evenementiel.settings.devlocal")
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ DBPASSWD="4KZt3nGPLVeWSvtBZPsd9jdssdJMds78"
|
|||
REDIS_PASSWD="dummy"
|
||||
|
||||
# It is used in quite a few places
|
||||
SETTINGS="poulpe.settings.dev"
|
||||
SETTINGS="evenementiel.settings.dev"
|
||||
|
||||
# Fills a "templated file" with the information specified in the variables above
|
||||
# e.g. every occurrence of {{DBUSER}} in the file will be replaced by the value
|
||||
|
@ -90,9 +90,9 @@ redis-cli -a $REDIS_PASSWD CONFIG REWRITE
|
|||
cd /vagrant
|
||||
|
||||
# Setup the secrets
|
||||
sudo -H -u vagrant cp poulpe/settings/secret_example.py \
|
||||
poulpe/settings/secret.py
|
||||
fill_template poulpe/settings/secret.py
|
||||
sudo -H -u vagrant cp evenementiel/settings/secret_example.py \
|
||||
evenementiel/settings/secret.py
|
||||
fill_template evenementiel/settings/secret.py
|
||||
|
||||
# Run the usual django admin commands
|
||||
function venv_python {
|
||||
|
|
|
@ -10,7 +10,7 @@ TimeoutSec=300
|
|||
WorkingDirectory=/vagrant
|
||||
Environment="DJANGO_SETTINGS_MODULE={{SETTINGS}}"
|
||||
ExecStart=/home/vagrant/venv/bin/daphne -u /srv/GE/GE.sock \
|
||||
poulpe.asgi:channel_layer
|
||||
evenementiel.asgi:channel_layer
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
-r requirements.txt
|
||||
django-debug-toolbar
|
||||
django-debug-panel
|
||||
ipython
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
-r requirements.txt
|
||||
|
||||
# Production specific
|
||||
daphne==1.3.0
|
||||
psycopg2
|
||||
gunicorn
|
|
@ -1,14 +1,14 @@
|
|||
asgi-redis==1.3.0
|
||||
asgiref==1.1.1
|
||||
django-bootstrap3==10.0.1
|
||||
channels==1.1.5
|
||||
Django==2.1
|
||||
django-tables2==2.0.0a2
|
||||
django-filter==2.0.0
|
||||
git+https://git.eleves.ens.fr/klub-dev-ens/django-allauth-ens.git@1.1.3
|
||||
django-bootstrap-form==3.4
|
||||
Django==1.11.*
|
||||
psycopg2
|
||||
asgi-redis
|
||||
Pillow
|
||||
channels
|
||||
django-bootstrap-form==3.2.1
|
||||
django-widget-tweaks
|
||||
djangorestframework==3.6.3
|
||||
drf-nested-routers==0.90.0
|
||||
django-notifications==0.1.dev0
|
||||
django-contrib-comments==1.8.0
|
||||
django-taggit==0.22.2
|
||||
Pillow==5.0.0
|
||||
django-notifications
|
||||
django-contrib-comments
|
||||
|
||||
# Production specific
|
||||
daphne
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
default_app_config = 'shared.apps.SharedConfig'
|
|
@ -1,34 +1,3 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.admin import AdminSite
|
||||
from django.contrib.sites.admin import SiteAdmin
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from django.contrib.auth.admin import UserAdmin, GroupAdmin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class CustomAdminSite(AdminSite):
|
||||
site_header = "Administration du Poulpe"
|
||||
site_title = "Poulpe"
|
||||
index_title = "Administration"
|
||||
|
||||
def index(self, request, extra_context=None):
|
||||
if extra_context is None:
|
||||
extra_context = {}
|
||||
|
||||
# Move last app to the top of `app_list`.
|
||||
# TODO fournir un bon ordre
|
||||
app_list = self.get_app_list(request)
|
||||
app_list.insert(0, app_list.pop(-1))
|
||||
|
||||
extra_context['app_list'] = app_list
|
||||
return super().index(request, extra_context)
|
||||
|
||||
|
||||
# admin.site = CustomAdminSite(name='admin')
|
||||
admin.site.register(User, UserAdmin)
|
||||
# admin.site.register(Group, GroupAdmin)
|
||||
# admin.site.register(Site, SiteAdmin)
|
||||
# Register your models here.
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
from allauth.account.adapter import DefaultAccountAdapter
|
||||
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
||||
|
||||
|
||||
class AccountAdapter(DefaultAccountAdapter):
|
||||
def is_open_for_signup(self, request):
|
||||
return False
|
||||
|
||||
|
||||
class SocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||
def is_open_for_signup(self, request, sociallogin):
|
||||
# sociallogin.account is a SocialAccount instance.
|
||||
# See https://github.com/pennersr/django-allauth/blob/master/allauth/socialaccount/models.py
|
||||
|
||||
if sociallogin.account.provider == 'clipper':
|
||||
return True
|
||||
|
||||
# It returns AccountAdapter.is_open_for_signup().
|
||||
# See https://github.com/pennersr/django-allauth/blob/master/allauth/socialaccount/adapter.py
|
||||
return super().is_open_for_signup(request, sociallogin)
|
|
@ -1,10 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
from django.contrib.admin.apps import AdminConfig
|
||||
|
||||
|
||||
class SharedConfig(AppConfig):
|
||||
name = 'shared'
|
||||
|
||||
|
||||
class CustomAdminConfig(AdminConfig):
|
||||
default_site = 'shared.admin.CustomAdminSite'
|
||||
|
|
|
@ -11,7 +11,6 @@ class EventSpecificMixin(models.Model):
|
|||
verbose_name=_("évènement"),
|
||||
help_text=_("Si spécifié, l'instance du modèle"
|
||||
"est spécifique à l'évènement en question"),
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
require 'compass/import-once/activate'
|
||||
# Require any additional compass plugins here.
|
||||
|
||||
# Set this to the root of your project when deployed:
|
||||
http_path = "/"
|
||||
css_dir = "css"
|
||||
sass_dir = "sass"
|
||||
images_dir = "images"
|
||||
javascripts_dir = "javascripts"
|
||||
|
||||
# You can select your preferred output style here (can be overridden via the command line):
|
||||
# output_style = :expanded or :nested or :compact or :compressed
|
||||
|
||||
# To enable relative paths to assets via compass helper functions. Uncomment:
|
||||
# relative_assets = true
|
||||
|
||||
# To disable debugging comments that display the original location of your selectors. Uncomment:
|
||||
# line_comments = false
|
||||
|
||||
|
||||
# If you prefer the indented syntax, you might want to regenerate this
|
||||
# project again passing --syntax sass, or you can uncomment this:
|
||||
# preferred_syntax = :sass
|
||||
# and then run:
|
||||
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,114 +0,0 @@
|
|||
//@import "compass/css3";
|
||||
|
||||
//Variables here:
|
||||
//(alongside with commented suggestions)
|
||||
$foreground-color:#b85b3f;//black;
|
||||
$background-color:#e8e3c7;//white
|
||||
$shadow-color:#ba9186;//$foreground-color;
|
||||
$distance:8px;
|
||||
$cut-distance:3px;//$distance/4;
|
||||
$strips-size:6px; //10px
|
||||
$strips-ratio:50%;//70%
|
||||
$strips-angle:45deg;//90deg;
|
||||
|
||||
//cray stuff yo. be sure to try (if you please)
|
||||
$animate:false;//true
|
||||
$fixed:false;//true
|
||||
|
||||
body{
|
||||
font-family: 'Open Sans Condensed', sans-serif;
|
||||
font-size:85pt;
|
||||
background-color:$background-color;
|
||||
text-align:center;
|
||||
line-height:1.2em;
|
||||
padding-top:70px;
|
||||
}
|
||||
.dashed-shadow{
|
||||
position:relative;
|
||||
top:$distance;
|
||||
left:$distance;
|
||||
display:inline-block;
|
||||
color:$shadow-color;
|
||||
}
|
||||
.dashed-shadow:before{
|
||||
content:" ";
|
||||
display:block;
|
||||
|
||||
position:absolute;
|
||||
$bleeding-horizontal:10px;
|
||||
$bleeding-vertical:0px;
|
||||
top:-$bleeding-vertical - $distance;
|
||||
left:-$bleeding-vertical - $distance;
|
||||
bottom:-$bleeding-horizontal + $distance;
|
||||
right:-$bleeding-horizontal + $distance;
|
||||
z-index:1;
|
||||
$color:$background-color;
|
||||
$size:$strips-ratio/2;
|
||||
$halfSize:$size/2;
|
||||
$p1:$halfSize;
|
||||
$p2:50%-$halfSize;
|
||||
$p3:50%+$halfSize;
|
||||
$p4:100%-$halfSize;
|
||||
$transparent:transparentize($color,1);
|
||||
@include background-image(linear-gradient($strips-angle,$color $p1, $transparent $p1, $transparent $p2,$color $p2, $color $p3, $transparent $p3, $transparent $p4, $color $p4));
|
||||
background-size:$strips-size $strips-size;
|
||||
@if($animate){
|
||||
animation:dash-animation 30s infinite linear;
|
||||
}
|
||||
@if($fixed){
|
||||
background-attachment:fixed;
|
||||
}
|
||||
}
|
||||
.dashed-shadow:hover:before{
|
||||
animation:dash-animation 30s infinite linear;
|
||||
}
|
||||
|
||||
.dashed-shadow:after{
|
||||
z-index:2;
|
||||
content:attr(data-text);
|
||||
position:absolute;
|
||||
left:-$distance;
|
||||
top:-$distance;
|
||||
color:$foreground-color;
|
||||
text-shadow:$cut-distance $cut-distance $background-color;
|
||||
}
|
||||
|
||||
//fancy stuff - just useless fluff, don't mind from here onwards
|
||||
|
||||
.hello{
|
||||
font-family:'Cookie',cursive;
|
||||
font-size:140pt;
|
||||
}
|
||||
.sorta-block{
|
||||
font-size:50pt;
|
||||
line-height:1.1em;
|
||||
@include transform(skew(0,-5deg));
|
||||
z-index:3;
|
||||
position:relative;
|
||||
margin-top:20px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
.sorta{
|
||||
border-top:4px solid $foreground-color;
|
||||
border-bottom:4px solid $foreground-color;
|
||||
|
||||
text-transform:uppercase;
|
||||
z-index:3;
|
||||
//position:relative;
|
||||
//display:block;
|
||||
//width:300px;
|
||||
font-style:italic;
|
||||
}
|
||||
.hipsterish{
|
||||
font-family: 'Sancreek', cursive;
|
||||
font-size:70pt;
|
||||
}
|
||||
.dashed-shadow-text{
|
||||
font-size:140pt;
|
||||
line-height:0.7em;
|
||||
//left:-10px;
|
||||
}
|
||||
.shadow{
|
||||
font-size:120pt;
|
||||
line-height:0.8em;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
// main: global.scss
|
||||
#filter_form {
|
||||
.form-group {
|
||||
.col-md-3, .col-md-9 {
|
||||
float: none;
|
||||
}
|
||||
ul.form-control {
|
||||
padding-left: 15px;
|
||||
list-style: none;
|
||||
height: auto;
|
||||
|
||||
a.selected {
|
||||
text-decoration: underline;
|
||||
color: darken($main_soft_color, 40%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
// main: global.scss
|
||||
.strong-banner {
|
||||
padding-top : 20px;
|
||||
padding-bottom : 10px ;
|
||||
background-color : $header-background;
|
||||
color: $header-color;
|
||||
}
|
||||
|
||||
|
||||
.navbar-inverse {
|
||||
background-color : $header-background;
|
||||
background-color : transparent ;
|
||||
border-style : none ;
|
||||
.navbar-nav {
|
||||
& > .open > a,
|
||||
& > .open > a:focus,
|
||||
& > .open > a:hover {
|
||||
color: #fff;
|
||||
background-color: $header-second-backgroud;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-collapse {
|
||||
border-top: 0px solid transparent ;
|
||||
padding : 0px ;
|
||||
|
||||
/* only < 768px*/
|
||||
background-color : $header-second-backgroud;
|
||||
padding-left: 25px;
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
background-color : transparent;
|
||||
padding-left: 0px;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.navbar-nav {
|
||||
width: 100%;
|
||||
@media (min-width: 768px) {
|
||||
float : right ;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-inverse {
|
||||
/* BRAND */
|
||||
.navbar-brand {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: white;
|
||||
font-family: $font_brand;
|
||||
font-size: xx-large;
|
||||
border-bottom: 5px solid $underline-brand;
|
||||
}
|
||||
}
|
||||
/* ICONE */
|
||||
.navbar-toggle {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $second_bold_color;
|
||||
border-color: $second_bold_color;
|
||||
}
|
||||
.icon-bar {
|
||||
background-color: $second_white_color;
|
||||
}
|
||||
}
|
||||
/* LINKS */
|
||||
.navbar-nav {
|
||||
& > li > a {
|
||||
&,
|
||||
&:hover,
|
||||
&:focus {
|
||||
font-family: $font_nav;
|
||||
font-size: large;
|
||||
color: $second_bold_color;
|
||||
background: transparent;
|
||||
@media (min-width: 768px) {
|
||||
color: $second_white_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
// main: global.scss
|
||||
.tree {
|
||||
font-size:large;
|
||||
ul, li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
li::before,
|
||||
li::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -12px;
|
||||
}
|
||||
li::before {
|
||||
border-top: 3px solid $second_soft_color;
|
||||
top: 9px;
|
||||
width: 8px;
|
||||
height: 0;
|
||||
}
|
||||
li::after {
|
||||
border-left: 3px solid $second_soft_color;
|
||||
height: 100%;
|
||||
width: 0px;
|
||||
top: 2px;
|
||||
}
|
||||
ul > li:last-child::after {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.category_node {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
// main: global.scss
|
||||
$main_c7: #375362;
|
||||
$main_c6: #4F778C;
|
||||
$main_c5: #5D8CA6;
|
||||
$main_c3: #BDD2DE;
|
||||
$main_c1: #F0FAFF;
|
||||
|
||||
$neutral_c2 : #F2EDDC;
|
||||
$neutral_c1: #FFFBEF;
|
||||
|
||||
$activity_c8: #4FADB8;
|
||||
$activity_c7: #5ED1DC;
|
||||
$activity_c3: #CAE4E7;
|
||||
|
||||
$event_c8: #3488A6;
|
||||
$event_c7: #3999BA;
|
||||
$event_c3: #AAD5E2;
|
||||
|
||||
$todo_c8: #F19F5D;
|
||||
$todo_c7: #FF9C4D;
|
||||
$todo_c3: #FFDEBC;
|
||||
|
||||
$equipment_c8: #E75571;
|
||||
$equipment_c7: #FF5C79;
|
||||
$equipment_c3: #FECAD6;
|
||||
|
||||
$staff_c8: #3BAD89;
|
||||
$staff_c7: #42C2A2;
|
||||
$staff_c3: #A9E1D7;
|
||||
|
||||
/* LEGACY COLORS*/
|
||||
$main_bold_color: #FF6969;
|
||||
$main_soft_color: #FF9191;
|
||||
$main_white_color: #FFEBEB;
|
||||
|
||||
$second_bold_color: #FFB363;
|
||||
$second_soft_color: #FFC282;
|
||||
$second_white_color: #FFF5EB;
|
||||
|
||||
$third_bold_color: #48B0C7;
|
||||
$third_soft_color: #8FD4E3;
|
||||
$third_white_color: #DCEAED;
|
||||
|
||||
/* COLORS */
|
||||
/* Header */
|
||||
$header-background: $main_c7;
|
||||
$header-second-backgroud: $main_c5;
|
||||
$header-color: white;
|
||||
$underline-brand: $equipment_c7;
|
||||
|
||||
/* Général */
|
||||
$html-background: $neutral_c1;
|
||||
$content-background: $neutral_c1;
|
||||
$content-border: $main_c7;
|
||||
$aside-background: $main_c7;
|
||||
$aside-inverted-background: $main_c5;
|
||||
|
||||
$title_border: $main_c7;
|
||||
|
||||
/* Le reste */
|
||||
$btn-font-color: white;
|
||||
$btn-bg-base: $main_bold_color;
|
||||
$btn-bg-special: $main_soft_color;
|
||||
$btn-border: $main_bold_color;
|
||||
|
||||
$yes_color: #55C487;
|
||||
$no_color: #E36268;
|
||||
$dunno_color: #5599C4;
|
||||
|
||||
/* Titres */
|
||||
$h1_background: $main_c6;
|
||||
$h2_background: $main_c3;
|
||||
$h3_background: $main_c1;
|
||||
|
||||
$h1_background_activity: $activity_c8;
|
||||
$h2_background_activity: $activity_c7;
|
||||
$h3_background_activity: $main_c1;
|
||||
|
||||
$h1_background_event: $event_c8;
|
||||
$h2_background_event: $event_c7;
|
||||
$h3_background_event: $main_c1;
|
||||
|
||||
$h1_background_todo: $todo_c8;
|
||||
$h2_background_todo: $todo_c7;
|
||||
$h3_background_todo: $main_c1;
|
||||
|
||||
$h1_background_equipment: $equipment_c8;
|
||||
$h2_background_equipment: $equipment_c7;
|
||||
$h3_background_equipment: $main_c1;
|
||||
|
||||
$h1_background_staff: $staff_c8;
|
||||
$h2_background_staff: $staff_c7;
|
||||
$h3_background_staff: $main_c1;
|
||||
|
||||
/* FONTS */
|
||||
$font_brand:'Lily Script One', cursive;
|
||||
$font_nav:'Work Sans', cursive;
|
||||
$font_bold:'Capriola', sans-serif;
|
||||
$font_normal:'Saira Semi Condensed', sans-serif;
|
|
@ -1,4 +1,3 @@
|
|||
// main: global.scss
|
||||
@mixin active {
|
||||
&:active,
|
||||
&.active {
|
||||
|
@ -109,14 +108,3 @@
|
|||
@include button-variant-2modes($btn-font-color, $btn-bg-base, $btn-bg-special, $btn-border);
|
||||
}
|
||||
|
||||
form#filter_form {
|
||||
.form-group {
|
||||
padding-right:20px;
|
||||
}
|
||||
|
||||
ul.form-control {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue