Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/ita-social-projects/Forum
Browse files Browse the repository at this point in the history
…into #764-Banner/Logo-update-with-previously-approved-content
  • Loading branch information
Andrewakiv committed Sep 13, 2024
2 parents 9b02160 + 396a48f commit 9c0cbbe
Show file tree
Hide file tree
Showing 38 changed files with 567 additions and 171 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/django_cd_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ jobs:
run: docker compose -f docker-compose.dev.yml exec ${{ vars.API_DEV }} python manage.py loaddata categories
- name: Docker compose LOADDATA regions
run: docker compose -f docker-compose.dev.yml exec ${{ vars.API_DEV }} python manage.py loaddata regions
- name: Docker compose COLLECTSTATIC
run: docker compose -f docker-compose.dev.yml exec ${{ vars.API_DEV }} python manage.py collectstatic --no-input
- name: nginx
run: docker compose -f docker-compose.nginx.yml down -v
- name: nginx
Expand Down
2 changes: 2 additions & 0 deletions BackEnd/administration/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.urls import path

from administration.views import (
ContactsView,
ProfilesListView,
ProfileDetailView,
UsersListView,
Expand All @@ -22,4 +23,5 @@
name="automoderation_hours",
),
path("email/", ModerationEmailView.as_view(), name="moderation-email"),
path("contacts/", ContactsView.as_view(), name="contacts"),
]
12 changes: 12 additions & 0 deletions BackEnd/administration/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.http import JsonResponse
from django.views import View
from drf_spectacular.utils import (
extend_schema,
OpenApiExample,
Expand All @@ -14,6 +16,7 @@
RetrieveUpdateAPIView,
)

from forum.settings import CONTACTS_INFO
from administration.serializers import (
AdminCompanyListSerializer,
AdminCompanyDetailSerializer,
Expand Down Expand Up @@ -136,3 +139,12 @@ class ModerationEmailView(RetrieveUpdateAPIView):

def get_object(self):
return ModerationEmail.objects.first()


class ContactsView(View):
"""
View for retrieving contact information.
"""

def get(self, request):
return JsonResponse(CONTACTS_INFO)
3 changes: 3 additions & 0 deletions BackEnd/authentication/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
class AuthenticationConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "authentication"

def ready(self):
import authentication.schema # noqa: E402
File renamed without changes.
8 changes: 0 additions & 8 deletions BackEnd/forum/apps.py

This file was deleted.

8 changes: 8 additions & 0 deletions BackEnd/forum/celery.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import os
from celery import Celery
from celery.schedules import crontab

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "forum.settings")
app = Celery("forum")

app.config_from_object("django.conf:settings", namespace="CELERY")

app.autodiscover_tasks()

app.conf.beat_schedule = {
"every": {
"task": "images.tasks.celery_send_email_images",
"schedule": crontab(day_of_month="1"),
}
}
9 changes: 7 additions & 2 deletions BackEnd/forum/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
"search",
"drf_spectacular",
"images",
"forum.apps.ForumConfig",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -238,7 +237,6 @@ def show_toolbar(request):
"SHOW_TOOLBAR_CALLBACK": show_toolbar,
}


LOGGING = {
"version": 1,
"disable_existing_loggers": False,
Expand Down Expand Up @@ -268,3 +266,10 @@ def show_toolbar(request):
},
},
}

CONTACTS_INFO = {
"email": "[email protected]",
"phone": "+38 050 234 23 23",
"university": "Львівська Політехніка",
"address": "вул. Степана Бандери 12, Львів",
}
32 changes: 32 additions & 0 deletions BackEnd/images/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from celery import shared_task
from datetime import timedelta

from django.db.models import Sum, Count
from django.utils import timezone

from utils.images.send_email import send_email_about_banners_and_logos
from .models import ProfileImage


@shared_task()
def celery_send_email_images():
now = timezone.now()
photos = ProfileImage.objects.filter(
created_at__gte=now - timedelta(days=30)
)
logo_data = photos.filter(image_type=ProfileImage.LOGO).aggregate(
total_size=Sum("image_size"), count=Count("uuid")
)
banner_data = photos.filter(image_type=ProfileImage.BANNER).aggregate(
total_size=Sum("image_size"), count=Count("uuid")
)

logo_total_size_kb = round(logo_data["total_size"] / 1024, 2)
banner_total_size_kb = round(banner_data["total_size"] / 1024, 2)

send_email_about_banners_and_logos(
banner_data["count"],
logo_data["count"],
banner_total_size_kb,
logo_total_size_kb,
)
25 changes: 25 additions & 0 deletions BackEnd/images/templates/images/email_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="uk">
<head>
<style>
body {
color: black;
font-family: Arial, sans-serif;
}
p, b {
color: black;
}
</style>
</head>
<body>
<div>
<img src="{{protocol}}://178.212.110.52/craftMerge-logo.png" alt="CRAFTMERGE"/>
<p>Доброго дня,</p>
<p>Кількість банерів: {{ num_of_banners }} Загальний розмір: {{ size_of_banners }} Кб</p>
<p>Кількість логотипів: {{ num_of_logos }} Загальний розмір: {{ size_of_logos }} Кб</p>

<p>З повагою,</p>
<p>Команда CraftMerge</p>
</div>
</body>
</html>
30 changes: 28 additions & 2 deletions BackEnd/profiles/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from django.utils.timezone import now
from .models import (
Expand Down Expand Up @@ -32,6 +33,15 @@ class Meta:
fields = "__all__"


@extend_schema_field(
{
"type": "object",
"properties": {
"uuid": {"type": "string", "format": "uuid"},
"path": {"type": "string", "format": "uri"},
},
}
)
class ProfileImageField(serializers.Field):
def to_representation(self, value):
if value.is_deleted == False:
Expand All @@ -46,6 +56,18 @@ def to_internal_value(self, data):
return ProfileImage.objects.filter(uuid=data, is_deleted=False).first()


class ProfileImageFieldApprovedStatus(ProfileImageField):
def to_representation(self, value):
if not value.is_deleted:
return {
"uuid": value.uuid,
"path": self.context["request"].build_absolute_uri(
value.image_path.url
),
"is_approved": value.is_approved,
}


class ProfileListSerializer(serializers.ModelSerializer):
activities = ActivitySerializer(many=True, read_only=True)
categories = CategorySerializer(many=True, read_only=True)
Expand Down Expand Up @@ -190,8 +212,8 @@ class ProfileOwnerDetailViewSerializer(serializers.ModelSerializer):
email = serializers.ReadOnlyField(source="person.email")
regions = RegionSerializer(many=True, read_only=True)
regions_ukr_display = serializers.SerializerMethodField()
banner = ProfileImageField()
logo = ProfileImageField()
banner = ProfileImageFieldApprovedStatus()
logo = ProfileImageFieldApprovedStatus()

class Meta:
model = Profile
Expand Down Expand Up @@ -221,6 +243,8 @@ class Meta:
"banner",
"logo",
"is_deleted",
"status",
"status_updated_at",
)
read_only_fields = (
"id",
Expand Down Expand Up @@ -248,6 +272,8 @@ class Meta:
"banner",
"logo",
"is_deleted",
"status",
"status_updated_at",
)

def get_regions_ukr_display(self, obj) -> str:
Expand Down
10 changes: 10 additions & 0 deletions BackEnd/search/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers

from profiles.models import Profile
Expand All @@ -10,6 +11,15 @@
from utils.regions_ukr_names import get_regions_ukr_names_as_string


@extend_schema_field(
{
"type": "object",
"properties": {
"uuid": {"type": "string", "format": "uuid"},
"path": {"type": "string", "format": "uri"},
},
}
)
class ProfileImageField(serializers.Field):
def to_representation(self, value):
if value.is_deleted == False:
Expand Down
45 changes: 45 additions & 0 deletions BackEnd/utils/images/send_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from decouple import config
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string

from administration.models import ModerationEmail

EMAIL_CONTENT_SUBTYPE = "html"
PROTOCOL = "http"
DOMAIN = config("ALLOWED_ENV_HOST")


def set_admin_email():
instance = ModerationEmail.objects.first()
if instance:
email = instance.email_moderation
else:
email = settings.EMAIL_HOST_USER
return email


def send_email_about_banners_and_logos(
num_of_banners, num_of_logos, size_of_banners_kb, size_of_logos_kb
):
context = {
"protocol": PROTOCOL,
"num_of_banners": num_of_banners,
"num_of_logos": num_of_logos,
"size_of_banners": size_of_banners_kb,
"size_of_logos": size_of_logos_kb,
}

recipient = set_admin_email()
email_body = render_to_string("images/email_template.html", context)
email = EmailMultiAlternatives(
subject="Information about number and size of banners and logos",
body=email_body,
from_email=settings.EMAIL_HOST_USER,
to=[
recipient,
],
)

email.content_subtype = EMAIL_CONTENT_SUBTYPE
email.send(fail_silently=False)
Binary file added FrontEnd/public/img/homecookies.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added FrontEnd/public/img/moderation-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 1 addition & 36 deletions FrontEnd/src/App.css
Original file line number Diff line number Diff line change
@@ -1,42 +1,7 @@
.App {
/*for footer correct work*/
min-height: 100vh;
flex-direction: column;
width: var(--main-block-size);
display: flex;
}

.App-logo {
height: 40vmin;
pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}

.App-link {
color: #61dafb;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
}
Loading

0 comments on commit 9c0cbbe

Please sign in to comment.