Skip to content
Snippets Groups Projects
Commit 6120dfc2 authored by OndraRehounek's avatar OndraRehounek Committed by jan.bednarik
Browse files

district & region: Unify template for program blocks, finish management command

parent bb253d60
Branches
No related tags found
2 merge requests!468Release,!466Feature/redmine on back
......@@ -174,6 +174,7 @@ Přes CRON je třeba na pozadí spouštět Django `manage.py` commandy:
* `clearsessions` - maže expirované sessions (denně až týdně)
* `publish_scheduled_pages` - publikuje naplánované stránky (každou hodinu)
* `update_callendars` - stáhne a aktualizuje kalendáře (několikrát denně)
* `update_redmine_issues` - aktualizuje programované body MS a KS stránek napojených na Redmine (několikrát denně)
### Fulltextové vyhledávání v češtině
......
......@@ -223,10 +223,10 @@ class StaticProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["district.DistrictPersonPage"])
completion_percentage = IntegerBlock(label="Procento dokončení", required=True)
program_items = ListBlock(ProgramItemBlock())
program_items = ListBlock(ProgramItemBlock(), label="Seznam bodů")
class Meta:
template = "district/blocks/static_program_block.html"
template = "district/blocks/program_block.html"
icon = "list-ul"
label = "Blok programu"
......@@ -236,9 +236,19 @@ class RedmineProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["district.DistrictPersonPage"])
redmine_issue = IntegerBlock(label="Číslo Redmine issue", required=True)
completion_percentage = IntegerBlock(label="Procento dokončení", required=False)
completion_percentage = IntegerBlock(
label="Procento dokončení - bude doplněno automaticky",
required=False,
help_text="Hodnota se automaticky načte s Redmine",
)
program_items = ListBlock(
ProgramItemBlock(),
label="Seznam bodů - bude doplněno automaticky",
help_text="Hodnota se automaticky načte s Redmine",
required=False,
)
class Meta:
template = "district/blocks/redmine_program_block.html"
template = "district/blocks/program_block.html"
icon = "site"
label = "Blok programu stahovaný z Redmine"
......@@ -20,7 +20,7 @@
<div>
<a href="https://redmine.pirati.cz/issues/28177" class="contact-line icon-link content-block--nostyle">
<i class="ico--info"></i>
<span>Plnění programu: {{ self.completion_percentage }}%</span>
<span>Plnění programu: {{ self.completion_percentage | default_if_none:'' }}%</span>
</a>
</div>
</div>
......@@ -43,10 +43,10 @@
<tr>
<td>
<a href="{{ item.issue_link }}" target="_blank">
{{ item.title }}
{{ item.title | default_if_none:'' }}
</a>
</td>
<td>{{ item.completion_percentage }} %</td>
<td>{{ item.completion_percentage | default_if_none:'' }} %</td>
</tr>
{% endfor %}
</tbody>
......
<article class="mt-8">
<div class="lg:flex lg:space-x-16">
<div class="lg:w-3/5">
<h2 class="head-heavy-sm mb-2 lg:mb-4">
{{ self.headline }}
</h2>
<div itemprop="description" class="w-full content-block">
<p>
{{ self.perex }}
</p>
</div>
</div>
<div class="pt-8 lg:w-2/5 md:pt-0">
<div class="card">
<div class="card__body">
{% include "shared/person_badge_snippet.html" with person_page=self.person %}
<div class="content-block">
<div class="space-y-4 mt-8">
<div>
<a href="https://redmine.pirati.cz/issues/{{ self.redmine_issue }}" class="contact-line icon-link content-block--nostyle">
<i class="ico--info"></i>
<span>
Plnění programu:
<span data-redmine-issue-id="{{ self.redmine_issue }}">10</span>%
</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-4">
<table class="table table--striped table--bordered w-full">
<thead>
<tr>
<td>Název</td>
<td>Stav plnění</td>
</tr>
</thead>
<tbody data-redmine-table-id="{{ self.redmine_issue }}">
</tbody>
</table>
</div>
</article>
<script>
(function () {
const redmineIssueId = '{{ self.redmine_issue }}'
fetch(`https://redmine.pirati.cz/issues/${redmineIssueId}.json`)
.then(response => response.json())
.then(data => handleOverallData(data.issue || {}))
fetch(`https://redmine.pirati.cz/issues.json?parent_id=${redmineIssueId}&sort=id:as`)
.then(response => response.json())
.then(data => handleIssueList(data.issues || []))
function handleOverallData(issue) {
document.querySelector('[data-redmine-issue-id="{{ self.redmine_issue }}"]').innerText = issue.done_ratio || 0
}
function handleIssueList(issueList) {
const table = document.querySelector('[data-redmine-table-id="{{ self.redmine_issue }}"]')
for (const issue of issueList) {
table.innerHTML +=
`<tr>
<td>
<a href="https://redmine.pirati.cz/issues/${issue.id}" target="_blank">
${issue.subject || ''}
</a>
</td>
<td>${issue.done_ratio || 0} %</td>
</tr>`
}
}
})()
</script>
from django.core.management.base import BaseCommand
from wagtail.core.blocks import StructValue
from district.blocks import ProgramItemBlock
from district.models import DistrictProgramPage
from region.models import RegionProgramPage
from ...utils import get_issue_list, get_issue_overall
from ...utils import get_issue_list, get_issue_overall_percentage
class Command(BaseCommand):
......@@ -17,14 +19,48 @@ class Command(BaseCommand):
self.stdout.write("Updating Redmine issues...")
for model in updated_models:
program_pages = model.objects.all()
for page_content in model.objects.all().values_list("content", flat=True):
for program_block in page_content:
for page in model.objects.all():
for program_block in page.content:
if program_block.block_type == "redmine_program_block":
# block_content_dict = program_block.value
redmine_issue = program_block.value["redmine_issue"]
program_block.value["headline"] = "test"
get_issue_overall(redmine_issue)
get_issue_list(redmine_issue)
fill_data_from_redmine(program_block.value)
page.save()
self.stdout.write("\nUpdating Redmine issues finished")
def fill_data_from_redmine(program_block_value: dict):
"""
Naplní hondnotu completion_percentage a program_items pro RedmineProgramBlock
"""
redmine_issue_id = program_block_value["redmine_issue"]
fill_overall_percentage_from_redmine(program_block_value, redmine_issue_id)
fill_program_items_from_redmine(program_block_value, redmine_issue_id)
def fill_overall_percentage_from_redmine(program_block_value: dict, issue_id: int):
"""
Naplní hondnotu completion_percentage pro RedmineProgramBlock hodnoutou z Redmine.
"""
program_block_value["completion_percentage"] = get_issue_overall_percentage(
issue_id
)
def fill_program_items_from_redmine(program_block_value: dict, issue_id: int):
"""
Naplní hondnotu program_items pro RedmineProgramBlock. Nejdříve hodnotu (list)
promaže a pak z getných issues naplní pomocí StructValue
"""
issue_list = get_issue_list(issue_id)
program_block_value["program_items"].clear()
for issue in issue_list:
sv = StructValue(ProgramItemBlock)
sv.update(
{
"completion_percentage": issue.get("done_ratio", None),
"title": issue.get("subject", ""),
}
)
program_block_value["program_items"].append(sv)
from django.db import models
class RedmineIssue(models.Model):
pass
import json
import logging
from typing import Dict, List
import requests
logger = logging.getLogger(__name__)
def get_issue_overall(issue_id):
def get_issue_overall_percentage(issue_id: int) -> int or None:
"""
Getne stav issue na redmine a vrátí její procento dokončení (nebo None)
"""
response = requests.get("https://redmine.pirati.cz/issues/{}.json".format(issue_id))
print(response.text)
if response.status_code != 200 or not response.text:
logger.error(
"Nepodařilo se stáhnout info o Redmine issue",
extra={"redmine_issue": issue_id},
)
return None
return json.loads(response.text).get("issue", {}).get("done_ratio", None)
def get_issue_list(issue_id):
def get_issue_list(issue_id: int) -> List[Dict]:
"""
Getne list dceřiných issues a vrátí je jako list dictionaries.
"""
response = requests.get(
"https://redmine.pirati.cz/issues.json?parent_id={}&sort=id:as".format(issue_id)
)
if response.status_code != 200 or not response.text:
# TODO log
return
data = json.loads(response.text)
print(response)
logger.error(
"Nepodařilo se stáhnout dílčí issues pro Redmine issue",
extra={"redmine_issue": issue_id},
)
return []
return data["issues"]
return json.loads(response.text).get("issues", [])
......@@ -223,10 +223,10 @@ class StaticProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["region.RegionPersonPage"])
completion_percentage = IntegerBlock(label="Procento dokončení", required=True)
program_items = ListBlock(ProgramItemBlock())
program_items = ListBlock(ProgramItemBlock(), label="Seznam bodů")
class Meta:
template = "region/blocks/static_program_block.html"
template = "region/blocks/program_block.html"
icon = "list-ul"
label = "Blok programu"
......@@ -236,8 +236,19 @@ class RedmineProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["region.RegionPersonPage"])
redmine_issue = IntegerBlock(label="Číslo Redmine issue", required=True)
completion_percentage = IntegerBlock(
label="Procento dokončení - bude doplněno automaticky",
required=False,
help_text="Hodnota se automaticky načte s Redmine",
)
program_items = ListBlock(
ProgramItemBlock(),
label="Seznam bodů - bude doplněno automaticky",
help_text="Hodnota se automaticky načte s Redmine",
required=False,
)
class Meta:
template = "region/blocks/redmine_program_block.html"
template = "region/blocks/program_block.html"
icon = "site"
label = "Blok programu stahovaný z Redmine"
<article class="mt-8">
<div class="lg:flex lg:space-x-16">
<div class="lg:w-3/5">
<h2 class="head-heavy-sm mb-2 lg:mb-4">
{{ self.headline }}
</h2>
<div itemprop="description" class="w-full content-block">
<p>
{{ self.perex }}
</p>
</div>
</div>
<div class="pt-8 lg:w-2/5 md:pt-0">
<div class="card">
<div class="card__body">
{% include "shared/person_badge_snippet.html" with person_page=self.person %}
<div class="content-block">
<div class="space-y-4 mt-8">
<div>
<a href="https://redmine.pirati.cz/issues/{{ self.redmine_issue }}" class="contact-line icon-link content-block--nostyle">
<i class="ico--info"></i>
<span>
Plnění programu:
<span data-redmine-issue-id="{{ self.redmine_issue }}">10</span>%
</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-4">
<table class="table table--striped table--bordered w-full">
<thead>
<tr>
<td>Název</td>
<td>Stav plnění</td>
</tr>
</thead>
<tbody data-redmine-table-id="{{ self.redmine_issue }}">
</tbody>
</table>
</div>
</article>
<script>
(function () {
const redmineIssueId = '{{ self.redmine_issue }}'
fetch(`https://redmine.pirati.cz/issues/${redmineIssueId}.json`)
.then(response => response.json())
.then(data => handleOverallData(data.issue || {}))
fetch(`https://redmine.pirati.cz/issues.json?parent_id=${redmineIssueId}&sort=id:as`)
.then(response => response.json())
.then(data => handleIssueList(data.issues || []))
function handleOverallData(issue) {
document.querySelector('[data-redmine-issue-id="{{ self.redmine_issue }}"]').innerText = issue.done_ratio || 0
}
function handleIssueList(issueList) {
const table = document.querySelector('[data-redmine-table-id="{{ self.redmine_issue }}"]')
for (const issue of issueList) {
table.innerHTML +=
`<tr>
<td>
<a href="https://redmine.pirati.cz/issues/${issue.id}" target="_blank">
${issue.subject || ''}
</a>
</td>
<td>${issue.done_ratio || 0} %</td>
</tr>`
}
}
})()
</script>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment