Skip to content

Commit

Permalink
module-tiles: add module tile insights
Browse files Browse the repository at this point in the history
  • Loading branch information
hom3mad3 authored and m4ra committed Mar 11, 2025
1 parent 1355fde commit 0301c52
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 103 deletions.
5 changes: 5 additions & 0 deletions changelog/8866.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Added
- render_module_insights template tag for rendering insights/stats per module

### Removed
- get_num_entries template tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% load i18n meinberlin_project_tags %}

<i class="module-insight__icon {{ icon }}" aria-hidden="true"></i>
<span class="module-insight__count">{{ count }}</span>
<span class="module-insight__label">{{ label }}</span>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
<a href="{% url 'module-detail' module.slug %}" class="module-tile">
<h3 class="module-tile__title">{{ module.name }}</h3>
<p class="module-tile__description">{{ module.description|truncatechars:240 }}</p>
<span class="module-tile__insight">
{% render_module_insights module %}
</span>

{% if module.module_running_time_left %}

Expand All @@ -21,6 +24,5 @@ <h3 class="module-tile__title">{{ module.name }}</h3>
<span class="module-tile__timespan">
{% translate 'Participation ended' %}
</span>

{% endif %}
</a>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% load i18n meinberlin_project_tags %}
<section aria-labelledby="project-participation" class="block">
<h2 id="project-participation">{% translate "Online Participation" %}</h2>
<ul class="list--clean flexgrid grid--3 grid--stretch">
{% get_sorted_modules as modules %}
{% for module in modules %}
<li>
{% include "meinberlin_projects/includes/module-tile/module_tile.html" with project=project module=module %}
</li>
{% endfor %}
</ul>
</section>
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,9 @@
{% include 'meinberlin_projects/project_actions.html' %}

{% include 'meinberlin_projects/includes/project_details_summary.html' %}
<section aria-labelledby="project-participation" class="block">
<h2 id="project-participation">{% translate "Online Participation" %}</h2>
<ul class="list--clean flexgrid grid--3 grid--stretch">
{% get_sorted_modules as modules %}
{% for module in modules %}
<li>
{% include "meinberlin_projects/includes/project_module_tile.html" with project=project module=module %}
</li>
{% endfor %}
</ul>
</section>

{% include 'meinberlin_projects/includes/project_participation.html' %}

{% if events %}
<section aria-labelledby="project-events">
<div class="actionable-list__header">
Expand Down
109 changes: 72 additions & 37 deletions meinberlin/apps/projects/templatetags/meinberlin_project_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
import re

from django import template
from django.db.models import Count
from django.db.models import Q
from django.db.models import Sum
from django.utils.html import strip_tags
from django.utils.translation import ngettext

from adhocracy4.comments.models import Comment
from adhocracy4.polls.models import Vote as Vote
from meinberlin.apps.budgeting.models import Proposal as budget_proposal
from adhocracy4.ratings.models import Rating
from meinberlin.apps.budgeting.models import Proposal
from meinberlin.apps.ideas.models import Idea
from meinberlin.apps.kiezkasse.models import Proposal as kiezkasse_proposal
from meinberlin.apps.likes.models import Like
from meinberlin.apps.kiezkasse.models import Proposal as KKProposal
from meinberlin.apps.livequestions.models import LiveQuestion
from meinberlin.apps.mapideas.models import MapIdea

Expand Down Expand Up @@ -71,36 +70,72 @@ def has_ckeditor_content(value):
return len(text) > 0


@register.simple_tag
def get_num_entries(module):
"""Count all user-generated items."""
item_count = (
Idea.objects.filter(module=module).count()
+ MapIdea.objects.filter(module=module).count()
+ budget_proposal.objects.filter(module=module).count()
+ kiezkasse_proposal.objects.filter(module=module).count()
+ Vote.objects.filter(choice__question__poll__module=module).count()
+ LiveQuestion.objects.filter(module=module).count()
+ Like.objects.filter(question__module=module).count()
@register.inclusion_tag("meinberlin_projects/includes/module-tile/module_insights.html")
def render_module_insights(module):
bp_type = module.blueprint_type
count = 0
label = ""
icon = None

type_to_model_mapping = {
("MIC", "MBS"): MapIdea,
("IC", "BS"): Idea,
(
"PB",
"PB2",
"PB3",
): Proposal, # include PB3 for still existing modules
("KK",): KKProposal, # include KK for still existing modules
("IE",): LiveQuestion,
}

rating_types = (
"TP",
"MTP",
)
comment_filter = (
Q(idea__module=module)
| Q(mapidea__module=module)
| Q(budget_proposal__module=module)
| Q(kiezkasse_proposal__module=module)
| Q(topic__module=module)
| Q(maptopic__module=module)
| Q(paragraph__chapter__module=module)
| Q(chapter__module=module)
| Q(poll__module=module)
)
comment_count = (
Comment.objects.filter(comment_filter)
.annotate(child_comment_count=Count("child_comments__pk", distinct=True))
.aggregate(comment_count=Count("pk") + Sum("child_comment_count"))[
"comment_count"
]
)
if comment_count is None:
comment_count = 0
return item_count + comment_count
comment_types = ("TR",)
vote_types = ("PO",)

for types, model in type_to_model_mapping.items():
if bp_type in types:
count = model.objects.filter(module=module).count()
if model == Proposal or model == KKProposal:
label = ngettext("Proposal", "Proposals", count)
icon = "fas fa-pen"
elif model == LiveQuestion:
label = ngettext("Question", "Questions", count)
icon = "fas fa-question"
else:
label = ngettext("Idea", "Ideas", count)
icon = "far fa-lightbulb"

if bp_type in rating_types:
rating_values = [Rating.POSITIVE, Rating.NEGATIVE]
count = Rating.objects.filter(
Q(maptopic__module=module) | Q(topic__module=module),
value__in=rating_values,
).count()
label = ngettext("Rating", "Ratings", count)
icon = "far fa-thumbs-up"

if bp_type in comment_types:
count = Comment.objects.filter(
Q(paragraph__chapter__module=module)
| Q(chapter__module=module)
| Q(parent_comment__paragraph__chapter__module=module)
| Q(parent_comment__chapter__module=module)
).count()
label = ngettext("Comment", "Comments", count)
icon = "far fa-comments"

if bp_type in vote_types:
count = (
Vote.objects.filter(choice__question__poll__module=module)
.values("creator")
.distinct()
.count()
)
label = ngettext("Participant", "Participants", count)
icon = "fas fa-user-group"

return {"count": count, "label": label, "icon": icon}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ a.module-tile {
}
}

.module-tile__description {
.module-tile__insight {
margin-bottom: auto;
color: $text-light;
font-size: $font-size-sm;
}

.module-tile__timespan {
Expand Down
2 changes: 1 addition & 1 deletion meinberlin/fixtures/modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"weight": 1,
"project": 1,
"is_draft": false,
"blueprint_type": ""
"blueprint_type": "BS"
}
},
{
Expand Down
5 changes: 3 additions & 2 deletions meinberlin/templates/a4modules/module_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ <h2>{% translate 'More from this online participation' %}</h2>
{% get_sorted_modules as modules %}
{% for module in modules %}
<li>
{% include "meinberlin_projects/includes/project_module_tile.html" with project=project module=module %}
{% include "meinberlin_projects/includes/module-tile/module_tile.html" with project=project module=module %}
</li>
{% endfor %}
</ul>
</section>
{% endif %}
</div>{% endblock content %}
</div>
{% endblock content %}
2 changes: 2 additions & 0 deletions tests/projects/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from adhocracy4.test.factories import polls as polls_factory
from meinberlin.test.factories import budgeting
from meinberlin.test.factories import ideas
from meinberlin.test.factories.documents import ChapterFactory
from meinberlin.test.factories.likes import LikeFactory
from meinberlin.test.factories.livequestions import LiveQuestionFactory
from meinberlin.test.factories.topicprio import TopicFactory
Expand All @@ -22,3 +23,4 @@
register(TopicFactory)
register(LiveQuestionFactory)
register(LikeFactory)
register(ChapterFactory)
Loading

0 comments on commit 0301c52

Please sign in to comment.