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
No related branches found
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: ...@@ -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ě) * `clearsessions` - maže expirované sessions (denně až týdně)
* `publish_scheduled_pages` - publikuje naplánované stránky (každou hodinu) * `publish_scheduled_pages` - publikuje naplánované stránky (každou hodinu)
* `update_callendars` - stáhne a aktualizuje kalendáře (několikrát denně) * `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ě ### Fulltextové vyhledávání v češtině
......
...@@ -223,10 +223,10 @@ class StaticProgramBlock(StructBlock): ...@@ -223,10 +223,10 @@ class StaticProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True) perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["district.DistrictPersonPage"]) person = PageChooserBlock(label="Garant", page_type=["district.DistrictPersonPage"])
completion_percentage = IntegerBlock(label="Procento dokončení", required=True) completion_percentage = IntegerBlock(label="Procento dokončení", required=True)
program_items = ListBlock(ProgramItemBlock()) program_items = ListBlock(ProgramItemBlock(), label="Seznam bodů")
class Meta: class Meta:
template = "district/blocks/static_program_block.html" template = "district/blocks/program_block.html"
icon = "list-ul" icon = "list-ul"
label = "Blok programu" label = "Blok programu"
...@@ -236,9 +236,19 @@ class RedmineProgramBlock(StructBlock): ...@@ -236,9 +236,19 @@ class RedmineProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True) perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["district.DistrictPersonPage"]) person = PageChooserBlock(label="Garant", page_type=["district.DistrictPersonPage"])
redmine_issue = IntegerBlock(label="Číslo Redmine issue", required=True) 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: class Meta:
template = "district/blocks/redmine_program_block.html" template = "district/blocks/program_block.html"
icon = "site" icon = "site"
label = "Blok programu stahovaný z Redmine" label = "Blok programu stahovaný z Redmine"
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<div> <div>
<a href="https://redmine.pirati.cz/issues/28177" class="contact-line icon-link content-block--nostyle"> <a href="https://redmine.pirati.cz/issues/28177" class="contact-line icon-link content-block--nostyle">
<i class="ico--info"></i> <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> </a>
</div> </div>
</div> </div>
...@@ -43,10 +43,10 @@ ...@@ -43,10 +43,10 @@
<tr> <tr>
<td> <td>
<a href="{{ item.issue_link }}" target="_blank"> <a href="{{ item.issue_link }}" target="_blank">
{{ item.title }} {{ item.title | default_if_none:'' }}
</a> </a>
</td> </td>
<td>{{ item.completion_percentage }} %</td> <td>{{ item.completion_percentage | default_if_none:'' }} %</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </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 django.core.management.base import BaseCommand
from wagtail.core.blocks import StructValue
from district.blocks import ProgramItemBlock
from district.models import DistrictProgramPage from district.models import DistrictProgramPage
from region.models import RegionProgramPage 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): class Command(BaseCommand):
...@@ -17,14 +19,48 @@ class Command(BaseCommand): ...@@ -17,14 +19,48 @@ class Command(BaseCommand):
self.stdout.write("Updating Redmine issues...") self.stdout.write("Updating Redmine issues...")
for model in updated_models: for model in updated_models:
program_pages = model.objects.all() for page in model.objects.all():
for page_content in model.objects.all().values_list("content", flat=True): for program_block in page.content:
for program_block in page_content:
if program_block.block_type == "redmine_program_block": if program_block.block_type == "redmine_program_block":
# block_content_dict = program_block.value fill_data_from_redmine(program_block.value)
redmine_issue = program_block.value["redmine_issue"]
program_block.value["headline"] = "test" page.save()
get_issue_overall(redmine_issue)
get_issue_list(redmine_issue)
self.stdout.write("\nUpdating Redmine issues finished") 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 json
import logging
from typing import Dict, List
import requests 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)) 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( response = requests.get(
"https://redmine.pirati.cz/issues.json?parent_id={}&sort=id:as".format(issue_id) "https://redmine.pirati.cz/issues.json?parent_id={}&sort=id:as".format(issue_id)
) )
if response.status_code != 200 or not response.text: if response.status_code != 200 or not response.text:
# TODO log logger.error(
return "Nepodařilo se stáhnout dílčí issues pro Redmine issue",
extra={"redmine_issue": issue_id},
data = json.loads(response.text) )
return []
print(response)
return data["issues"] return json.loads(response.text).get("issues", [])
...@@ -223,10 +223,10 @@ class StaticProgramBlock(StructBlock): ...@@ -223,10 +223,10 @@ class StaticProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True) perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["region.RegionPersonPage"]) person = PageChooserBlock(label="Garant", page_type=["region.RegionPersonPage"])
completion_percentage = IntegerBlock(label="Procento dokončení", required=True) completion_percentage = IntegerBlock(label="Procento dokončení", required=True)
program_items = ListBlock(ProgramItemBlock()) program_items = ListBlock(ProgramItemBlock(), label="Seznam bodů")
class Meta: class Meta:
template = "region/blocks/static_program_block.html" template = "region/blocks/program_block.html"
icon = "list-ul" icon = "list-ul"
label = "Blok programu" label = "Blok programu"
...@@ -236,8 +236,19 @@ class RedmineProgramBlock(StructBlock): ...@@ -236,8 +236,19 @@ class RedmineProgramBlock(StructBlock):
perex = TextBlock(label="Krátký text pod nadpisem", required=True) perex = TextBlock(label="Krátký text pod nadpisem", required=True)
person = PageChooserBlock(label="Garant", page_type=["region.RegionPersonPage"]) person = PageChooserBlock(label="Garant", page_type=["region.RegionPersonPage"])
redmine_issue = IntegerBlock(label="Číslo Redmine issue", required=True) 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: class Meta:
template = "region/blocks/redmine_program_block.html" template = "region/blocks/program_block.html"
icon = "site" icon = "site"
label = "Blok programu stahovaný z Redmine" 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