diff --git a/assets/scss/base/_base.scss b/assets/scss/base/_base.scss index a5676bbc59..7af96dbb24 100644 --- a/assets/scss/base/_base.scss +++ b/assets/scss/base/_base.scss @@ -25,7 +25,7 @@ body { } // Elements with a dark background -.flexpage-header, .write-tutorial, .page-footer, .header-menu, .header-right, .modal-title, .taglist, .hat, .linkbox-item.primary { +.flexpage-header, .call-to-action, .page-footer, .header-menu, .header-right, .modal-title, .taglist, .hat, .linkbox-item.primary { &::selection, *::selection { @include negative-selection; } diff --git a/assets/scss/components/_content-item.scss b/assets/scss/components/_content-item.scss index e807fa25db..43e3f01f1e 100644 --- a/assets/scss/components/_content-item.scss +++ b/assets/scss/components/_content-item.scss @@ -8,7 +8,7 @@ $content-item-padding-vertical: $length-14; display: flex; width: 100%; - height: $content-item-height; + min-height: $content-item-height; margin: $length-6 $length-10; @@ -321,18 +321,15 @@ $content-item-padding-vertical: $length-14; margin-bottom: $length-24; } -.write-tutorial { +.call-to-action { display: flex; align-items: center; - - margin: $length-16 $length-10; - - &:not(:last-child) { - margin-bottom: $length-20; - } + flex-wrap: wrap; + box-sizing: border-box; + padding: $length-6 $length-20; width: 100%; - height: $content-item-height; + min-height: $content-item-height; border-color: $color-primary; background-color: $color-primary; @@ -340,13 +337,13 @@ $content-item-padding-vertical: $length-14; color: $grey-000; &:hover { - .btn-write-tutorial { + .btn-call-to-action { background-color: $true-white; transform: scale(1.05); } } - .write-tutorial-text { + .call-to-action-text { flex: 1; text-align: center; @@ -361,9 +358,8 @@ $content-item-padding-vertical: $length-14; } } - .btn-write-tutorial { + .btn-call-to-action { padding: $length-4 $length-20; - margin-right: $length-24; background-color: $grey-000; color: $primary-900; @@ -394,10 +390,6 @@ $content-item-padding-vertical: $length-14; @include mobile { .content-item { - &.write-tutorial { - display: none; - } - .content-tags { display: none; } diff --git a/templates/home.html b/templates/home.html index fca74ce8c5..3e2c09d928 100644 --- a/templates/home.html +++ b/templates/home.html @@ -109,32 +109,54 @@

{% endfor %} +

- {% trans "Derniers tutoriels" %} - {% trans "Tous les tutoriels" %} + {% trans "Dernières pépites validées par l'équipe" %}

- {% include "tutorialv2/list_page_elements/list_of_online_contents.html" with public_contents=last_tutorials col_number=1 ignore_categories=True %} +
+ {% for content in last_contents %} + {% include "tutorialv2/includes/content_item.part.html" with public_content=content show_description=True show_reactions=True ignore_categories=ignore_categories %} + {% endfor %} +
+
+

+ {% blocktrans with plural=contents_count|pluralize_fr %} + Mais ce n'est pas tout... + {% endblocktrans %} +

+

+ {% if validated_contents_count == 0 %} + {% blocktrans %} + Il y a {{ validated_contents_count }} publication validée par l'équipe.

+ {% endblocktrans %} + {% else %} + {% blocktrans %} + Il y a {{ validated_contents_count }} publications validées par l'équipe.

+ {% endblocktrans %} + {% endif %} +
+ {% trans "Montre-les moi !" %} +
+
+
+
-

- {% trans "Derniers articles" %} - {% trans "Tous les articles" %} +

+ {% trans "Dernières publications de la communauté" %}

- {% include "tutorialv2/list_page_elements/list_of_online_contents.html" with public_contents=last_articles col_number=1 ignore_categories=True %} -
- -
-
+
+

{% blocktrans with plural=contents_count|pluralize_fr %} Il y a {{ contents_count }} publication{{ plural }} sur Zeste de Savoir. @@ -142,34 +164,31 @@

{% trans "Pourquoi pas la vôtre ?" %}

- {% trans "Commencer à rédiger" %} + {% trans "Commencer à rédiger" %}
-
-
-
- -
-
-

- {% trans "Derniers billets choisis" %} - {% trans "Tous les billets" %} -

- - - -
{% for opinion in last_opinions %} {% include 'tutorialv2/includes/content_item.part.html' with public_content=opinion show_description=True item_class=forloop.first|yesno:", mini" show_reactions=True ignore_categories=True %} {% empty %}

{% trans "Aucun billet disponible." %}

{% endfor %} +
+
+

+ {% blocktrans with plural=contents_count|pluralize_fr %} + D’autres publications de la communauté vous attendent. + {% endblocktrans %} +

+
+ {% trans "Fais voir !" %} +
+
+

- {% trans "Derniers sujets" %} - {% trans "En voir plus" %} + {% trans "En direct du forum" %}

@@ -180,6 +199,16 @@

{% empty %}

{% trans "Aucun sujet disponible." %}

{% endfor %} +
+
+

+ {% blocktrans with plural=contents_count|pluralize_fr %} + Entraide, débats, discussions : venez sur nos forums ! + {% endblocktrans %} +

+
+ {% trans "Je participe" %} +

diff --git a/zds/featured/managers.py b/zds/featured/managers.py index b33176892a..aec680f597 100644 --- a/zds/featured/managers.py +++ b/zds/featured/managers.py @@ -1,7 +1,6 @@ from datetime import datetime from django.db import models -from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist @@ -14,12 +13,8 @@ class FeaturedResourceManager(models.Manager): Custom featured resource manager. """ - def get_last_featured(self): - return ( - self.order_by("-pubdate") - .exclude(pubdate__gt=datetime.now()) - .prefetch_related("authors__user")[: settings.ZDS_APP["featured_resource"]["home_number"]] - ) + def get_last_featured(self, count): + return self.order_by("-pubdate").exclude(pubdate__gt=datetime.now()).prefetch_related("authors__user")[:count] class FeaturedMessageManager(models.Manager): diff --git a/zds/forum/managers.py b/zds/forum/managers.py index 9cf673207a..384c58f9cc 100644 --- a/zds/forum/managers.py +++ b/zds/forum/managers.py @@ -1,10 +1,8 @@ -from django.conf import settings +import django.db.models from django.db import models from django.db.models import Q, F from model_utils.managers import InheritanceManager -from zds.utils import get_current_user - class ForumManager(models.Manager): """ @@ -65,17 +63,13 @@ class TopicManager(models.Manager): """ def visibility_check_query(self, current_user): - """ - Build a subquery that checks if a topic is readable by current user - :param current_user: - :return: - """ + """Build a subquery that checks if a topic is readable by current user""" if current_user.is_authenticated: return Q(forum__groups__isnull=True) | Q(forum__groups__pk__in=current_user.profile.group_pks) else: return Q(forum__groups__isnull=True) - def last_topics_of_a_member(self, author, user): + def last_topics_of_a_member(self, author, user, count): """ Gets last topics of a member but exclude all topics not accessible for the request user. @@ -86,24 +80,19 @@ def last_topics_of_a_member(self, author, user): queryset = self.filter(author=author).prefetch_related("author") queryset = queryset.filter(self.visibility_check_query(user)).distinct() - return queryset.order_by("-pubdate").all()[: settings.ZDS_APP["forum"]["home_number"]] + return queryset.order_by("-pubdate").all()[:count] def get_beta_topic_of(self, tutorial): return self.filter(key=tutorial.pk, key__isnull=False).first() - def get_last_topics(self): - """ - Get last posted topics and prefetch some related properties. - Depends on settings.ZDS_APP['topic']['home_number'] - :return: - :rtype: django.models.Queryset - """ + def get_last_topics(self, count) -> django.db.models.QuerySet: + """Get last topics and prefetch some related properties.""" return ( self.filter(is_locked=False, forum__groups__isnull=True) .select_related("forum", "author", "author__profile", "last_message") .prefetch_related("tags") .order_by("-pubdate") - .all()[: settings.ZDS_APP["topic"]["home_number"]] + .all()[:count] ) def get_all_topics_of_a_forum(self, forum_pk, is_sticky=False): diff --git a/zds/forum/tests/tests.py b/zds/forum/tests/tests.py index f67d27e7db..756904859f 100644 --- a/zds/forum/tests/tests.py +++ b/zds/forum/tests/tests.py @@ -13,7 +13,6 @@ TopicFactory, PostFactory, TagFactory, - create_category_and_forum, ) from zds.forum.models import Forum, TopicRead, Post, Topic from zds.member.tests.factories import ProfileFactory, StaffProfileFactory @@ -1182,7 +1181,7 @@ def setUp(self): TopicFactory(forum=self.forum3, author=self.staff.user) def test_get_last_topics(self): - topics = Topic.objects.get_last_topics() + topics = Topic.objects.get_last_topics(5) self.assertEqual(2, len(topics)) def test_get_unread_post(self): diff --git a/zds/forum/tests/tests_views.py b/zds/forum/tests/tests_views.py index b73889ec0a..0539c616ce 100644 --- a/zds/forum/tests/tests_views.py +++ b/zds/forum/tests/tests_views.py @@ -96,7 +96,8 @@ def test_topic_list_home_page(self): _, forum = create_category_and_forum() topic = create_topic_in_forum(forum, profile) - topics_nb = len(Topic.objects.get_last_topics()) + topics_count = 5 + topics_nb = len(Topic.objects.get_last_topics(topics_count)) self.client.force_login(staff.user) data = {"lock": "true", "topic": topic.pk} @@ -105,7 +106,7 @@ def test_topic_list_home_page(self): self.assertEqual(302, response.status_code) self.assertTrue(Topic.objects.get(pk=topic.pk).is_locked) - self.assertEqual(len(Topic.objects.get_last_topics()), topics_nb - 1) + self.assertEqual(len(Topic.objects.get_last_topics(topics_count)), topics_nb - 1) class CategoryForumsDetailViewTest(TestCase): diff --git a/zds/member/views/profile.py b/zds/member/views/profile.py index eb8c5d263d..74b3d119c3 100644 --- a/zds/member/views/profile.py +++ b/zds/member/views/profile.py @@ -148,7 +148,8 @@ def get_context_data(self, **kwargs): usr = context["usr"] profile = usr.profile context["profile"] = profile - context["topics"] = list(Topic.objects.last_topics_of_a_member(usr, self.request.user)) + topics_count = settings.ZDS_APP["member"]["topics_on_profile"] + context["topics"] = list(Topic.objects.last_topics_of_a_member(usr, self.request.user, count=topics_count)) followed_query_set = TopicAnswerSubscription.objects.get_objects_followed_by(self.request.user.id) followed_topics = list(set(followed_query_set) & set(context["topics"])) for topic in context["topics"]: diff --git a/zds/pages/views.py b/zds/pages/views.py index 1ec1797115..2c7682a268 100644 --- a/zds/pages/views.py +++ b/zds/pages/views.py @@ -31,28 +31,30 @@ def home(request): - """Display the home page with last topics added.""" + """Display the home page.""" - tutos = PublishableContent.objects.get_last_tutorials() - articles = PublishableContent.objects.get_last_articles() - opinions = PublishableContent.objects.get_last_opinions() - quote = random.choice(QUOTES) + context = { + "featured_message": FeaturedMessage.objects.get_last_message(), + "contents_count": PublishedContent.objects.count_contents(), + "search_form": SearchForm(initial={}), + "validated_contents_count": PublishedContent.objects.count_validated_contents(), + } - return render( - request, - "home.html", - { - "featured_message": FeaturedMessage.objects.get_last_message(), - "last_tutorials": tutos, - "last_articles": articles, - "last_opinions": opinions, - "last_featured_resources": FeaturedResource.objects.get_last_featured(), - "last_topics": Topic.objects.get_last_topics(), - "contents_count": PublishedContent.objects.get_contents_count(), - "quote": quote.replace("\n", ""), - "search_form": SearchForm(initial={}), - }, - ) + contents_count = settings.ZDS_APP["homepage"]["contents_count"] + context["last_contents"] = PublishableContent.objects.get_last_contents(contents_count) + + opinions_count = settings.ZDS_APP["homepage"]["opinions_count"] + context["last_opinions"] = PublishableContent.objects.get_last_opinions(opinions_count) + + features_count = settings.ZDS_APP["homepage"]["features_count"] + context["last_featured_resources"] = FeaturedResource.objects.get_last_featured(features_count) + + topics_count = settings.ZDS_APP["homepage"]["topics_count"] + context["last_topics"] = Topic.objects.get_last_topics(topics_count) + + context["quote"] = random.choice(QUOTES).replace("\n", "") + + return render(request, "home.html", context) def index(request): @@ -60,7 +62,7 @@ def index(request): def about(request): - """Display many informations about the website.""" + """Display many information about the website.""" return render( request, "pages/technologies.html", diff --git a/zds/settings/abstract_base/zds.py b/zds/settings/abstract_base/zds.py index a242c2a1d6..0a8ead2b98 100644 --- a/zds/settings/abstract_base/zds.py +++ b/zds/settings/abstract_base/zds.py @@ -145,6 +145,7 @@ "users_in_hats_list": 5, "requested_hats_per_page": 100, "update_last_visit_interval": 600, # seconds + "topics_on_profile": 5, }, "hats": { "moderation": "Staff", @@ -156,12 +157,13 @@ "gallery_per_page": 21, "images_per_page": 21, }, - "tutorial": { - "home_number": 4, + "homepage": { + "contents_count": 5, + "opinions_count": 4, + "topics_count": 5, + "features_count": 5, }, - "article": {"home_number": 3}, "opinions": { - "home_number": 5, "allow_pdf": zds_config.get("opinions_allow_pdf", True), "allow_epub": zds_config.get("opinions_allow_epub", True), "allow_zip": zds_config.get("opinions_allow_zip", True), @@ -210,7 +212,6 @@ "beta_forum_id": zds_config.get("publications_being_written_forum_id", 1), "max_post_length": 1000000, "top_tag_max": 5, - "home_number": 6, "old_post_limit_days": 90, # Exclude tags from top tags list. Tags listed here should not be relevant for most of users. # Be warned exclude too much tags can restrict performance @@ -219,15 +220,11 @@ "description_size": 120, "max_similar_topics": 10, }, - "topic": { - "home_number": 5, - }, "comment": { "max_pings": 15, }, "featured_resource": { "featured_per_page": 100, - "home_number": 5, "request_per_page": 50, }, "notification": { diff --git a/zds/tutorialv2/managers.py b/zds/tutorialv2/managers.py index 381bb6403f..7a2e2a7fab 100644 --- a/zds/tutorialv2/managers.py +++ b/zds/tutorialv2/managers.py @@ -86,12 +86,12 @@ def last_articles_of_a_member_loaded(self, author): def last_opinions_of_a_member_loaded(self, author): return self.last_contents_of_a_member_loaded(author, _type="OPINION") - def get_contents_count(self): - """ - :rtype: int - """ + def count_contents(self) -> int: return self.filter(must_redirect=False).count() + def count_validated_contents(self) -> int: + return self.filter(must_redirect=False, content_type__in=["ARTICLE", "TUTORIAL"]).count() + def get_top_tags(self, displayed_types, limit=-1): """ Retrieve all most rated tags. @@ -203,32 +203,7 @@ def transfer_paternity(self, unregistered_user, replacement_author, gallery_clas content.sha_draft = sha content.save() - def get_last_tutorials(self, number=0): - """ - get list of last published tutorial - - :param number: number of tutorial you want. By default it is interpreted as \ - ``settings.ZDS_APP['tutorial']['home_number']`` - :return: list of last published content - :rtype: list - """ - number = number or settings.ZDS_APP["tutorial"]["home_number"] - all_contents = ( - self.filter(type="TUTORIAL") - .filter(public_version__isnull=False) - .prefetch_related("authors") - .select_related("public_version") - .prefetch_related("subcategory") - .prefetch_related("tags") - .order_by("-public_version__publication_date")[:number] - ) - published = [] - for content in all_contents: - content.public_version.content = content - published.append(content.public_version) - return published - - def get_last_articles(self, number=0): + def get_last_contents(self, number): """ ..attention: this one uses a raw subquery for historical reasons. It will hopefully be replaced one day by an @@ -244,9 +219,8 @@ def get_last_articles(self, number=0): "utils_comment.id", "tutorialv2_contentreaction.comment_ptr_id", ) - number = number or settings.ZDS_APP["article"]["home_number"] all_contents = ( - self.filter(type="ARTICLE") + self.filter(type__in=["ARTICLE", "TUTORIAL"]) .filter(public_version__isnull=False) .prefetch_related("authors") .select_related("last_note") @@ -263,14 +237,13 @@ def get_last_articles(self, number=0): published.append(content.public_version) return published - def get_last_opinions(self): + def get_last_opinions(self, count): """ This depends on settings.ZDS_APP['opinions']['home_number'] parameter. :return: list of last opinions :rtype: list """ - home_number = settings.ZDS_APP["opinions"]["home_number"] all_contents = ( self.filter(type="OPINION") .filter(public_version__isnull=False, sha_picked=F("sha_public")) @@ -279,7 +252,7 @@ def get_last_opinions(self): .select_related("public_version") .prefetch_related("subcategory") .prefetch_related("tags") - .order_by("-public_version__publication_date")[:home_number] + .order_by("-public_version__publication_date")[:count] ) published = [] for content in all_contents: