Merge pull request 'carnet_rouge' (#1) from carnet_rouge into master

Reviewed-on: #1
This commit is contained in:
2023-06-04 08:51:26 +00:00
22 changed files with 389 additions and 2 deletions

2
.idea/Reskreen.iml generated
View File

@@ -7,7 +7,7 @@
<excludeFolder url="file://$MODULE_DIR$/Reskreen/.vs" /> <excludeFolder url="file://$MODULE_DIR$/Reskreen/.vs" />
<excludeFolder url="file://$MODULE_DIR$/vehicles/migrations" /> <excludeFolder url="file://$MODULE_DIR$/vehicles/migrations" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">

2
.idea/misc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (Reskreen)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser"> <component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" /> <option name="shown" value="true" />
</component> </component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

View File

@@ -16,11 +16,22 @@ Including another URLconf
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.views.generic import RedirectView
urlpatterns = [ urlpatterns = [
path('', RedirectView.as_view(url='admin/login/', permanent=False), name='/'),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('accounts/', admin.site.urls), path('accounts/', admin.site.urls),
path('collabs/', include('collabs.urls')), path('collabs/', include('collabs.urls')),
path('vehicules/', include('vehicles.urls')), path('vehicules/', include('vehicles.urls')),
path('caldav/', include('mycaldav.urls')), path('caldav/', include('mycaldav.urls')),
#path('collabs_hour/', include('collabs.urls')), #path('collabs_hour/', include('collabs.urls')),
path('carnet_rouge/', include('carnet_rouge.urls')),
path('summernote/', include('django_summernote.urls')),
path('editor/', include('django_summernote.urls')),
] ]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

0
carnet_rouge/__init__.py Normal file
View File

104
carnet_rouge/admin.py Normal file
View File

@@ -0,0 +1,104 @@
from django.contrib import admin
from carnet_rouge.models import cr_Category, cr_Message
from django.contrib.auth.models import User
from django.contrib.admin import SimpleListFilter
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
from django_summernote.admin import SummernoteModelAdmin
class DefaultListFilter(SimpleListFilter):
all_value = '_all'
def default_value(self):
raise NotImplementedError()
def queryset(self, request, queryset):
if self.parameter_name in request.GET and request.GET[self.parameter_name] == self.all_value:
return queryset
if self.parameter_name in request.GET:
return queryset.filter(**{self.parameter_name:request.GET[self.parameter_name]})
return queryset.filter(**{self.parameter_name:self.default_value()})
def choices(self, cl):
yield {
'selected': self.value() == self.all_value,
'query_string': cl.get_query_string({self.parameter_name: self.all_value}, []),
'display': _('All'),
}
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == force_str(lookup) or (self.value() == None and force_str(self.default_value()) == force_str(lookup)),
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}
class StatusFilter(DefaultListFilter):
title = _('Actif ')
parameter_name = 'bEnabled__exact'
def lookups(self, request, model_admin):
return ((0,'Désactivé'), (1,'Activé'))
def default_value(self):
return 1
@admin.register(cr_Message)
class cr_Message_Admin(SummernoteModelAdmin):
summernote_fields = ('sText',)
class Meta:
verbose_name = 'Message carnet rouge'
verbose_name_plural = 'Messages carnet rouge'
def save_model(self, request,obj , form, change):
obj.Author = request.user
obj.sAuthor = request.user.first_name + " " + request.user.last_name
#Get all user of selected group
obj.sDestUsers = "" # reset
users_all = User.objects.filter(groups__name=obj.DestGroup.name)
_con = ""
for usr in users_all:
obj.sDestUsers += f"{_con}[{usr.id}]"
_con = ";"
obj.sNotReadUsers = obj.sDestUsers
obj.save()
def has_change_permission(self, request, obj=None):
if obj is not None and obj.Author != request.user :
return False
return True
def has_delete_permission(self, request, obj=None):
if obj is not None and obj.Author != request.user and not request.user.is_superuser:
return False
return True
always_show_username = True
list_display = ('MessageId','sTitle', 'DestGroup', 'get_dtCreated', 'sAuthor','bEnabled', 'calc_read_quotas')
list_filter = ["sAuthor", StatusFilter]
fields = ["Caterogy", "DestGroup", 'sTitle', "sText", "dtValidityFrom", "dtValidityTo", "bEnabled"]
search_fields = ['sTitle', 'sText']
"""
list_filter = [('dtDate', DateRangeFilter), ('user', admin.RelatedOnlyFieldListFilter),'sBases','type', 'bNoticed']
search_fields = ['userName']
readonly_fields = ["userName"]
"""
# Register your models here.
admin.site.register(cr_Category)

6
carnet_rouge/apps.py Normal file
View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class CarnetRougeConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'carnet_rouge'

7
carnet_rouge/forms.py Normal file
View File

@@ -0,0 +1,7 @@
from django import forms
from carnet_rouge.models import cr_Message
class CrForm(forms.ModelForm):
class Meta:
model = cr_Message
fields = ('sText',)

74
carnet_rouge/models.py Normal file
View File

@@ -0,0 +1,74 @@
import datetime
from django.db import models
from django.conf import settings
from django.contrib.auth.models import Group
from django.utils import timezone
import uuid
from django_quill.fields import QuillField
from django.dispatch import receiver
from django.db.models.signals import pre_save
# Create your models here.
class cr_Category(models.Model):
sName = models.CharField("Désignation", max_length=250)
dtUpdated = models.DateTimeField('date updated', auto_now=True)
dtCreated = models.DateTimeField('date published', auto_now_add=True)
def __str__(self):
return self.sName
class Meta:
verbose_name = "catégorie"
verbose_name_plural = "catégories"
def increment_MessageId():
last_id = cr_Message.objects.all().order_by('MessageId').last()
if not last_id:
return 1
last_id = last_id.MessageId
return last_id + 1
class cr_Message(models.Model):
uuid = models.UUIDField(default=uuid.uuid4(), editable=False, primary_key=True)
MessageId = models.IntegerField("ID Message",editable=False, unique=True, default=increment_MessageId)
Caterogy = models.ForeignKey(cr_Category, on_delete=models.DO_NOTHING, verbose_name="Catégorie")
sDestUsers = models.TextField("Liste des utilisateurs cibles")
sNotReadUsers = models.TextField()
sReadedUsers = models.TextField("Liste des utilisateurs ayant lu", blank=True)
DestGroup = models.ForeignKey(Group, on_delete=models.DO_NOTHING, verbose_name="Groupe de destination")
sTitle = models.CharField("Titre", max_length=120)
sText = models.TextField ("Corps de texte")
dtValidityFrom = models.DateField("Validité depuis",default=timezone.now)
dtValidityTo = models.DateField("Validité jusqu'à", blank=True, null=True)
bEnabled = models.BooleanField("Actif", default=True)
Author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name="Auteur", on_delete=models.SET_NULL, null=True)
sAuthor = models.CharField("Auteur", max_length=120)
dtUpdated = models.DateTimeField('date updated', auto_now=True)
dtCreated = models.DateTimeField('date published', auto_now_add=True)
def get_dtCreated(self):
return self.dtCreated.strftime("%d.%b.%Y %H:%M:%S")
def calc_read_quotas(self):
obj = self
n_dest = obj.sDestUsers.count('[')
n_readed = obj.sReadedUsers.count('[')
if n_dest == 0:
return "No dest"
return f"{(n_readed/n_dest)*100}%"
def __str__(self):
return self.sTitle
class Meta:
verbose_name = "message"
verbose_name_plural = "messages"

12
carnet_rouge/static/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
img {
max-width: 100%;
}
footer {
font-size: 12px;
padding: 10px;
background-color: #eee;
}

View File

@@ -0,0 +1,51 @@
{% load static %}
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<!-- Custom CSS -->
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'style.css' %}">
<title>django-quill-editor</title>
</head>
<body>
<div id="wrap">
<nav class="navbar navbar-expand navbar-dark bg-primary mb-3 ps-3 pe-3">
<a href="" class="navbar-brand">Intranet Ambulance Clerc</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01"
aria-controls="navbarColor01"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="w-100">
<ul class="navbar-nav">
<li class="nav-item">
</li>
<li class="nav-item mr-auto">
<a href="{% url 'admin:index' %}" class="nav-link" target="_blank">Administration intranet</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'carnet_rouge:cr_not_read_list' %}" target="_blank">Repository</a>
</li>
</ul>
</div>
</nav>
{% block content %}
{% endblock %}
<footer class="mt-2 text-center">© 2023 <a href="https://ambulance-clerc.ch"
target="_blank">Ambulance Clerc</a></footer>
{% block script %}
{% endblock %}
</div>
</body>
</html>

View File

@@ -0,0 +1,19 @@
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row d-flex align-items-center mb-3">
<div class="col-125 col-md-12 mb-sm-2 mb-xs-2">
<h2 class="mb-0">{% block title %}title{% endblock %}</h2>
</div>
<div class="col-12 col-md-12 col-lg-9">
<div class="d-flex justify-content-end">
</div>
</div>
</div>
{% block cr_content %}
{% endblock %}
</div>
{% endblock %}

View File

@@ -0,0 +1,7 @@
<div class="card">
<div class="card-body">
<div>
{{ obj.sText|safe }}
</div>
</div>
</div>

View File

@@ -0,0 +1,6 @@
{% extends 'carnet_rouge/base_cr.html' %}
{% block title %}<h2>Détail du message: {{ object.sTitle }}</h2>{% endblock %}
{% block cr_content %}
{% include 'carnet_rouge/cr_message.html' with obj=object %}
{% endblock %}

View File

@@ -0,0 +1,19 @@
{% extends 'carnet_rouge/base_cr.html' %}
{% block title %}Messages non lus{% endblock %}
{% block cr_content %}
<div class="row">
<div class="col">
{% if object_list %}
{% for obj in object_list %}
<h2>{{ obj.sTitle }}</h2>
{% include 'carnet_rouge/cr_message.html' with obj=obj %}
{% if not forloop.last %}
<hr>{% endif %}
{% endfor %}
{% else %}
<p>There is no post.</p>
{% endif %}
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{{ form.media }}
</head>
<body>
test
<form action="" method="POST">{% csrf_token %}
{{ form.sText }}
</form>
{{ obj.sText }}
</body>
</html>

3
carnet_rouge/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

15
carnet_rouge/urls.py Normal file
View File

@@ -0,0 +1,15 @@
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from carnet_rouge import views
app_name = "carnet_rouge"
urlpatterns = [
path('cr', views.model_form_view, name='model_form_view'),
path('view/<uuid:pk>', views.CrDetailView.as_view(), name='cr_view'),
path('notread', views.CrNotReadView.as_view(), name='cr_not_read_list'),
]

30
carnet_rouge/views.py Normal file
View File

@@ -0,0 +1,30 @@
from django.shortcuts import render
from carnet_rouge.forms import CrForm
from django.views.generic import ListView, UpdateView, DetailView, FormView, CreateView
from carnet_rouge.models import *
def model_form_view(request):
return render(request, "form_view.html", {'form': CrForm()})
class CrDetailView(DetailView):
model = cr_Message
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["test"] = timezone.now()
return context
class CrNotReadView(ListView):
model = cr_Message
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["test"] = timezone.now()
return context
def cr_view(request, id):
print(id)
cr = cr_Message.objects.get(pk=id)
return render(request, "form_view.html", {'form': CrForm(), 'obj': cr})
# Create your views here.

Binary file not shown.