diff --git a/.gitignore b/.gitignore index 1e6486a..51af000 100644 --- a/.gitignore +++ b/.gitignore @@ -4,11 +4,7 @@ *~ *# -/media/archives/* -/media/images/* -/media/documents/* -/media/original_images/* -/media/admin +/media/picture /recensements/ /venv/ diff --git a/annuaire/settings.py b/annuaire/settings.py index 614c878..657cae3 100644 --- a/annuaire/settings.py +++ b/annuaire/settings.py @@ -86,7 +86,8 @@ DATABASES = { AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + 'NAME': + 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', @@ -103,7 +104,7 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/dev/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = 'fr-fr' TIME_ZONE = 'UTC' @@ -118,3 +119,7 @@ USE_TZ = True # https://docs.djangoproject.com/en/dev/howto/static-files/ STATIC_URL = '/static/' + +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') + +MEDIA_URL = '/media/' diff --git a/annuaire/urls.py b/annuaire/urls.py index 1d7e4ba..17f0e1d 100644 --- a/annuaire/urls.py +++ b/annuaire/urls.py @@ -13,9 +13,17 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from django.conf import settings from django.contrib import admin -from django.urls import path +from django.urls import path, include +from django.conf.urls.static import static +from fiches.views import home urlpatterns = [ path('admin/', admin.site.urls), + path('fiche/', include('fiches.urls')), + path('', home, name='home') ] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/fiches/admin.py b/fiches/admin.py index 97f45d4..b059338 100644 --- a/fiches/admin.py +++ b/fiches/admin.py @@ -3,9 +3,13 @@ from fiches.models import Profile from fiches.models import Department from fiches.models import Phone from fiches.models import Social +from fiches.models import Mail +from fiches.models import Address + -# Register your models here. admin.site.register(Profile) admin.site.register(Department) admin.site.register(Phone) -admin.site.register(Social) \ No newline at end of file +admin.site.register(Social) +admin.site.register(Mail) +admin.site.register(Address) diff --git a/fiches/forms.py b/fiches/forms.py new file mode 100644 index 0000000..83c20c0 --- /dev/null +++ b/fiches/forms.py @@ -0,0 +1,30 @@ +from django import forms +from fiches.models import Profile, Department + + +class ProfileForm(forms.ModelForm): + class Meta: + model = Profile + fields = [ + "full_name", + "nickname", + "picture", + "department", + "promotion", + "birth_date", + "thurne", + "text_field", + "printing", + "keep_me" + ] + + +class SearchForm(forms.Form): + name = forms.CharField(label='Nom/Surnom', max_length=1023, required=False) + year = forms.IntegerField(label='Promotion', required=False) + department = forms.ModelMultipleChoiceField(queryset=Department.objects.all(), required=False) + + def clean(self): + cleaned_data = super().clean() + if (not cleaned_data['name'] and not cleaned_data['year'] and not cleaned_data['department']): + raise forms.ValidationError(('Tous les champs sont vides'), code='invalid') \ No newline at end of file diff --git a/fiches/migrations/0002_auto_20190408_1929.py b/fiches/migrations/0002_auto_20190408_1929.py new file mode 100644 index 0000000..6b5f8eb --- /dev/null +++ b/fiches/migrations/0002_auto_20190408_1929.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2 on 2019-04-08 19:29 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('fiches', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='phone', + name='profile', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fiches.Profile', verbose_name='profil'), + ), + migrations.AlterField( + model_name='social', + name='profile', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fiches.Profile', verbose_name='profil'), + ), + ] diff --git a/fiches/migrations/0003_auto_20200108_2306.py b/fiches/migrations/0003_auto_20200108_2306.py new file mode 100644 index 0000000..014794e --- /dev/null +++ b/fiches/migrations/0003_auto_20200108_2306.py @@ -0,0 +1,47 @@ +# Generated by Django 2.2.9 on 2020-01-08 23:06 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('fiches', '0002_auto_20190408_1929'), + ] + + operations = [ + migrations.AlterField( + model_name='department', + name='name', + field=models.CharField(max_length=255, verbose_name='nom du département'), + ), + migrations.AlterField( + model_name='phone', + name='name', + field=models.CharField(max_length=255, verbose_name='type'), + ), + migrations.AlterField( + model_name='social', + name='name', + field=models.CharField(max_length=255, verbose_name='type'), + ), + migrations.CreateModel( + name='Mail', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='type')), + ('mail', models.CharField(max_length=1023, verbose_name='adresse mail')), + ('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fiches.Profile', verbose_name='profil')), + ], + ), + migrations.CreateModel( + name='Address', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='type')), + ('content', models.CharField(max_length=1023, verbose_name='adresse')), + ('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fiches.Profile', verbose_name='profil')), + ], + ), + ] diff --git a/fiches/models.py b/fiches/models.py index beeac8d..7793fdb 100644 --- a/fiches/models.py +++ b/fiches/models.py @@ -6,7 +6,10 @@ from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField( - User, on_delete=models.CASCADE, verbose_name=_("utilisateur") + User, + on_delete=models.CASCADE, + verbose_name=_("utilisateur"), + related_name="profile", ) full_name = models.CharField(max_length=1023, verbose_name=_("nom")) nickname = models.CharField(blank=True, max_length=1023, verbose_name=_("surnom")) @@ -27,22 +30,56 @@ class Profile(models.Model): default=False, verbose_name=_("conserver la fiche annuaire ?") ) + def __str__(self): + return self.full_name + class Department(models.Model): - name = models.CharField(max_length=1023, verbose_name=_("nom du département")) + name = models.CharField(max_length=255, verbose_name=_("nom du département")) + + def __str__(self): + return self.name class Phone(models.Model): - profile = models.OneToOneField( + profile = models.ForeignKey( Profile, on_delete=models.CASCADE, verbose_name=_("profil") ) - name = models.CharField(max_length=1023, verbose_name=_("type")) + name = models.CharField(max_length=255, verbose_name=_("type")) number = models.CharField(max_length=1023, verbose_name=_("numéro")) + def __str__(self): + return "{} : {}".format(self.name, self.number) + class Social(models.Model): - profile = models.OneToOneField( + profile = models.ForeignKey( Profile, on_delete=models.CASCADE, verbose_name=_("profil") ) - name = models.CharField(max_length=1023, verbose_name=_("type")) + name = models.CharField(max_length=255, verbose_name=_("type")) content = models.CharField(max_length=1023, verbose_name=_("contenu")) + + def __str__(self): + return "{} : {}".format(self.name, self.content) + + +class Mail(models.Model): + profile = models.ForeignKey( + Profile, on_delete=models.CASCADE, verbose_name=_("profil") + ) + name = models.CharField(max_length=255, verbose_name=_("type")) + mail = models.CharField(max_length=1023, verbose_name=_("adresse mail")) + + def __str__(self): + return "{} : {}".format(self.name, self.mail) + + +class Address(models.Model): + profile = models.ForeignKey( + Profile, on_delete=models.CASCADE, verbose_name=_("profil") + ) + name = models.CharField(max_length=255, verbose_name=_("type")) + content = models.CharField(max_length=1023, verbose_name=_("adresse")) + + def __str__(self): + return "{} : {}".format(self.name, self.content) diff --git a/fiches/static/fiches/css/style.css b/fiches/static/fiches/css/style.css new file mode 100644 index 0000000..a5780d0 --- /dev/null +++ b/fiches/static/fiches/css/style.css @@ -0,0 +1,351 @@ +html { + background-color: black; + color: #FFF; + font-family: Verdana, Verdana, Geneva, sans-serif; +} + +body { + margin: 0 0 0.8em 0; + min-height: 538px; +} + +img { + border: 0; +} + +a:link { + background-color: inherit; + color: #7978DA; + text-decoration: none; +} + +a:visited { + background-color: inherit; + color: #9CA6FF; + text-decoration: none; +} + +a:hover { + background-color: inherit; + color: #006CE3; + text-decoration: underline; +} + +p { + margin-top: 0.6em; + margin-bottom: 0.6em; +} + +.ens { + color: #89C4FF; + background-color: inherit; +} + +.tiny { + font-size: 0.8em; +} + +.verytiny { + font-size: 0.7em; +} + +.dark { + color: #666; + background-color: inherit; +} + +.center { + text-align: center; +} + +.right { + float: right; +} + +.spacer { + width: 100%; + clear: both; +} + +.error { + font-weight: bold; + color: #FB0000; + background-color: inherit; +} + +.warning { + font-weight: bold; + color: #FF8A00; + background-color: inherit; +} + +.mainspacer { + width: 100%; + height: 0.8em; +} + +.success { + font-weight: bold; + color: #00E000; + background-color: inherit; +} + +.success a:link { + background-color: inherit; + color: #008800; + text-decoration: none; +} + +.success a:visited { + background-color: inherit; + color: #008800; + text-decoration: none; +} + +.success a:hover { + background-color: inherit; + color: #4FFF4F; + text-decoration: underline; +} + +.block { + background-color: #333; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + text-align: justify; + padding: 0.5em 0.5em; + margin: 0 1em 1em 1em; +} + +#main { + padding-top: 0.5em; + margin-left: 1em; + background-color: transparent; + color: #FFF; + width: 40em; + float: left; +} + +#header { + margin: 0 1em 0 1em; + float: left; + text-align: center; +} + +#header h1 { + margin-top: 0; + font-family: Georgia, sans-serif; +} + +#header h1 a:link, #header h1 a:visited { + color: #FFF; + background-color: inherit; + text-decoration: none; +} + +#header h1 a:hover { + text-decoration: underline; +} + +#language_switch { + margin-top: 0.5em; + float: left; +} + +#language_switch form { + float: left; + padding: 0; + margin-left: 0.5em; +} + +#content { +} + +#content h3 { + margin-top: 0; + margin-bottom: 0.2em; +} + +#content h4 { + margin-top: 0.5em; + margin-bottom: 0.2em; +} + +#footer { + padding: 0.2em 0; + margin: 1em 5em 0 5em; + clear: both; + background-color: #333; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + text-align: center; +} + +#contact { + margin: 0.5em 8em 0 8em; +} + +#search { + margin-bottom: 1em; +} + +.errorlist { + display: inline; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; +} + +.errorlist li { + display: inline; + font-weight: bold; + color: #E00000; + background-color: inherit; +} + +#advanced_search { + border: 1px solid #CCC; + padding: 0.5em; + margin-bottom: 1em; +} + +.advanced_filter { + width: 50%; + margin-top: 1px; + margin-bottom: 1px; + float: left; +} + +.advanced_filter input { + max-width: 60%; +} + +.submit_button { + text-align: center; +} + +.add_delete_button { + text-align: right; + margin: 0.3em; +} + +#pdflink { + text-align: right; + font-size: 0.8em; +} + +#picture { + width: 8em; + float: left; +} + +#picture img { + margin-top: 0.3em; + max-width: 8em; +} + +#infos { + padding-left: 1em; + float: left; + width: 31em; +} + +#ficheedit { + margin-top: 0; + padding-top: 0; +} + +.editfield { + padding-top: 0.2em; + padding-bottom: 0.2em; +} + +.editfield input { +} + +.editfield textarea { + margin-left: auto; + margin-right: auto; + margin-top:0.2em; + display: block; + width: 98%; + height: 3em; +} + +.message { + margin-top: 0.3em; + margin-bottom: 0.3em; + text-align: center; +} + +.long_message { + margin-top: 0.6em; + margin-bottom: 0.6em; + text-align: justify; +} + +fieldset.address .editfield textarea, fieldset.quote .editfield textarea { + height: 3em; +} + +fieldset.address, fieldset.quote { + padding-bottom: 0.2em; +} + +#main-login-container { + width: 500px; + margin: 3.5em auto; +} + +#main-login-container h3.error { + text-align: center; + width: 100%; + margin-bottom: 20px; + font-size: 1.3em; + font-family: 'Droid Serif', serif; +} + +#main-login { + width: 500px; + border: 15px solid #333; + -webkit-border-radius: 20px; + -moz-border-radius: 20px; + border-radius: 20px; +} + +#main-login.login_block { + padding: 2em; + box-shadow: 0 0 100px #AAA inset; +} + +a#login_clipper, a#login_outsider { + float: left; + display: block; + width: 250px; + height: 200px; + text-align: center; + font-family: 'Droid Serif', serif; + font-size: 1.3em; + font-weight: bold; + line-height: 190px; + text-decoration: none; + color: #FFF; +} + +a#login_clipper { + background-color: #123E96; + box-shadow: 0 0 100px #040C78 inset; +} + +a#login_clipper:hover { + background-color: #164BB6; +} + +a#login_outsider { + background-color: #961221; + box-shadow: 0 0 100px #780411 inset; +} + +a#login_outsider:hover { + background-color: #B31729; +} diff --git a/fiches/templates/fiches/base.html b/fiches/templates/fiches/base.html new file mode 100644 index 0000000..9c076eb --- /dev/null +++ b/fiches/templates/fiches/base.html @@ -0,0 +1,66 @@ +{% load i18n %} +{% load staticfiles %} + + +
+ ++ {% if profile.department.exists %} + Département{{ profile.department.count|pluralize}} : + {% endif %} + {% for dep in profile.department.all %} + {{ dep }} + {% if not forloop.last %} + , + {% endif %} + {% endfor %} + {% if profile.birth_date %} +
+
+ {% if profile.phone_set.exists %}
+ Téléphone{{ profile.phone_set.count|pluralize}} :
+ {% endif %}
+ {% for ph in profile.phone_set.all %}
+ {{ ph }}
+ {% if not forloop.last %}
+ ,
+ {% endif %}
+ {% endfor %}
+
+ {% if profile.social_set.exists %}
+ {{ profile.social_set.count|pluralize:"Réseau social,Réseaux sociaux"}} :
+ {% endif %}
+ {% for ph in profile.social_set.all %}
+ {{ ph }}
+ {% if not forloop.last %}
+ ,
+ {% endif %}
+ {% endfor %}
+
+ Date de naissance : {{ profile.birth_date }} +
+ {% endif %} + + {% if profile.thurne %} ++ Thurne : {{ profile.thurne }} +
+ {% endif %} ++ Champ libre : {{ profile.text_field }} +
+ {% endif %} +