eo_redmine: first version (#83233)

so far it only allows filtering the client list, more to come
This commit is contained in:
Pierre Ducroquet 2023-11-08 13:31:53 +01:00
parent a588ee12ea
commit 5d7894bfab
12 changed files with 186 additions and 1 deletions

View File

@ -125,11 +125,44 @@ class ActiveFilter(admin.SimpleListFilter):
return queryset.filter(active=bool(self.value() == 'True'))
class MyClientsFilter(admin.SimpleListFilter):
title = 'CPF'
parameter_name = 'cpf'
def __init__(self, request, params, model, model_admin):
super().__init__(request, params, model, model_admin)
self.request = request
def value(self):
from eo_gestion.eo_redmine.models import Project
value = super().value()
default_value = 'all'
user = self.request.user
if user and Project.objects.filter(cpfs__contains=[user.username]).exists():
default_value = 'True'
return value if value in ('True', 'all') else default_value
def choices(self, changelist):
choices = list(super().choices(changelist))
return choices[1:] # don't include automatic "All"
def lookups(self, request, model_admin):
return [('all', 'tous'), ('True', 'mes clients')]
def queryset(self, request, queryset):
if self.value() == 'True':
return queryset.filter(project__cpfs__contains=[request.user.username])
else:
return queryset
class ClientAdmin(admin.ModelAdmin):
form = forms.ClientForm
list_display = ['nom', 'adresse', 'email', 'telephone']
list_editable = ['email', 'telephone']
list_filter = [ActiveFilter]
list_filter = [ActiveFilter, MyClientsFilter]
ordering = ['nom']
search_fields = ['nom', 'email']
save_on_top = True

View File

View File

@ -0,0 +1,14 @@
from django.contrib import admin
import eo_gestion.admin
from . import models
class ProjectAdmin(admin.ModelAdmin):
readonly_fields = ['name', 'cpfs']
list_display = ['name', 'cpfs', 'client']
admin.site.register(models.Project, ProjectAdmin)
eo_gestion.admin.site.register(models.Project, ProjectAdmin)

View File

@ -0,0 +1,77 @@
import requests
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from eo_gestion.eo_redmine.models import Project
REDMINE_HEADERS = {'X-Redmine-API-Key': settings.REDMINE_API_KEY}
def redmine_iterator(base_url, entity_name):
result = requests.get(base_url + '?limit=100', headers=REDMINE_HEADERS).json()
total = 0
while total < result['total_count']:
for item in result[entity_name]:
yield item
total += 1
if total < result['total_count']:
result = requests.get(base_url + '?limit=100&offset=%s' % total, headers=REDMINE_HEADERS).json()
redmine_user_cache = {}
def redmine_get_login(user_id):
if not user_id in redmine_user_cache:
user_data = requests.get(
settings.REDMINE_BASE_URL + 'users/%s.json' % user_id, headers=REDMINE_HEADERS
).json()
redmine_user_cache[user_id] = user_data['user']['login']
return redmine_user_cache[user_id]
class Command(BaseCommand):
@transaction.atomic
def handle(self, *args, **options):
alive_projects = []
for project in redmine_iterator(settings.REDMINE_BASE_URL + 'projects.json', 'projects'):
project_id = project['id']
project_name = project['name']
# Skip inactive or non-client projects
if project['status'] != 1:
continue
if not ('parent' in project) or project['parent']['name'] != 'Projets Clients':
continue
alive_projects.append(project_id)
# get the members
cpf_ids = set()
for membership in redmine_iterator(
settings.REDMINE_BASE_URL + 'projects/%s/memberships.json' % project_id, 'memberships'
):
if not 'user' in membership:
continue
for role in membership['roles']:
if role['name'] in ('CPF', 'CPF (Backup)'):
cpf_ids.add(membership['user']['id'])
cpfs = []
for cpf_id in cpf_ids:
cpfs.append(redmine_get_login(cpf_id))
# now match in our DB, maybe update
insert = False
try:
project_object = Project.objects.get(id=project_id)
except Project.DoesNotExist:
project_object = Project()
project_object.id = project_id
insert = True
project_object.name = project_name
project_object.cpfs = cpfs
project_object.save(force_insert=insert)
# Purge dead projects
Project.objects.exclude(id__in=alive_projects).delete()

View File

@ -0,0 +1,38 @@
# Generated by Django 3.2.21 on 2023-11-08 10:11
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('eo_facture', '0019_alter_contrat_client'),
]
operations = [
migrations.CreateModel(
name='Project',
fields=[
(
'id',
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
('name', models.CharField(max_length=255)),
(
'cpfs',
django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=255), size=None
),
),
(
'client',
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.CASCADE, to='eo_facture.client'
),
),
],
),
]

View File

@ -0,0 +1,13 @@
from django.contrib.postgres.fields import ArrayField
from django.db import models
from eo_gestion.eo_facture.models import Client
class Project(models.Model):
name = models.CharField(max_length=255)
cpfs = ArrayField(models.CharField(max_length=255))
client = models.ForeignKey(Client, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.name

View File

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

View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -169,6 +169,7 @@ INSTALLED_APPS = (
'eo_gestion.eo_facture',
'eo_gestion.eo_banque',
'eo_gestion.eo_conges',
'eo_gestion.eo_redmine',
'eo_gestion.chorus',
'taggit',
'adminsortable2',
@ -207,6 +208,9 @@ WORKERS_CALENDAR_CONFIG = {
],
}
REDMINE_BASE_URL = 'https://dev.entrouvert.org/'
REDMINE_API_KEY = ''
local_settings_file = os.environ.get('BARBACOMPTA_SETTINGS_FILE', 'local_settings.py')
if os.path.exists(local_settings_file):
with open(local_settings_file) as fd: