diff --git a/articles/api.py b/articles/api.py index 21fe9c4..b7d3555 100644 --- a/articles/api.py +++ b/articles/api.py @@ -2,7 +2,7 @@ from collections import defaultdict from datetime import timedelta from typing import Counter, List, Optional -from urllib.parse import quote_plus, unquote +from urllib.parse import quote, quote_plus, unquote from django.contrib.contenttypes.models import ContentType from django.core.paginator import Paginator @@ -168,7 +168,7 @@ def create_article( f"New article submitted in {community.name}" f" by {request.auth.username}" ), - link=f"/community/{community.name}/submissions", + link=f"/community/{quote(community.name, safe='')}/submissions", content=article.title, ) except Exception: diff --git a/communities/api_join.py b/communities/api_join.py index 4f5b3a6..a78bd84 100644 --- a/communities/api_join.py +++ b/communities/api_join.py @@ -1,5 +1,6 @@ import logging from typing import List, Literal +from urllib.parse import quote from django.utils import timezone from ninja import Router @@ -7,6 +8,7 @@ from communities.models import Community, JoinRequest from communities.schemas import JoinRequestSchema, Message +from myapp.services.send_emails import send_join_decision_email, send_join_request_email from users.auth import JWTAuth from users.models import Notification @@ -124,13 +126,18 @@ def join_community(request, community_id: int): community=community, notification_type="join_request_received", message=f"New join request from {user.username}", - link=f"/community/{community.name}/requests", + link=f"/community/{quote(community.name, safe='')}/requests", ) except Exception as e: logger.error(f"Error creating notification: {e}") # Continue even if notification fails pass + try: + send_join_request_email(user, community) + except Exception as e: + logger.error(f"Error sending join request email: {e}") + return 200, {"message": "Your request to join the community has been sent."} except Exception as e: logger.error(f"Error processing join request: {e}") @@ -204,13 +211,18 @@ def manage_join_request( community=community, notification_type="join_request_approved", message=f"Your join request to {community.name} has been approved.", - link=f"/community/{community.name}", + link=f"/community/{quote(community.name, safe='')}", ) except Exception as e: logger.error(f"Error creating notification: {e}") # Continue even if notification fails pass + try: + send_join_decision_email(join_request.user, community, "approve") + except Exception as e: + logger.error(f"Error sending join decision email: {e}") + return 200, { "message": f"Join request approved. \ {join_request.user.username} is now a member of the community." @@ -227,6 +239,11 @@ def manage_join_request( "message": "Error updating join request status. Please try again." } + try: + send_join_decision_email(join_request.user, community, "reject") + except Exception as e: + logger.error(f"Error sending join decision email: {e}") + return 200, { "message": "You have rejected the join request successfully." } diff --git a/communities/articles_api.py b/communities/articles_api.py index 17f60b8..c331b1b 100644 --- a/communities/articles_api.py +++ b/communities/articles_api.py @@ -1,5 +1,6 @@ import logging from typing import List, Literal, Optional +from urllib.parse import quote from django.core.paginator import Paginator from django.db import transaction @@ -119,7 +120,7 @@ def submit_article(request, community_name: str, article_slug: str): message=( f"New article submitted in {community.name} by {request.auth.username}" ), - link=f"/community/{community.name}/submissions", + link=f"/community/{quote(community.name, safe='')}/submissions", content=article.title, ) except Exception as e: diff --git a/myapp/services/send_emails.py b/myapp/services/send_emails.py index 7f2a32d..a09f821 100644 --- a/myapp/services/send_emails.py +++ b/myapp/services/send_emails.py @@ -135,6 +135,87 @@ def send_review_notification_email(article, review, community): logger.error(f"Error sending review notification email: {e}") +def send_join_request_email(user, community): + admin = community.admins.first() + if not admin or not admin.email: + logger.warning( + f"Cannot send join request email: community {community.id} has no admin with email" + ) + return + + if not is_email_notifications_enabled(admin.id): + logger.debug( + f"Email notifications disabled for admin {admin.id}, skipping join request email" + ) + return + + domain = get_frontend_domain() + link = f"{domain}/community/{quote(community.name, safe='')}/requests" + + context = { + "recipient_name": admin.first_name or admin.username, + "notification_type": "New Join Request", + "message_text": mark_safe( + f"{user.username} has requested to join the {community.name} community." + ), + "content_preview": None, + "article_link": link, + } + + send_email_task.delay( + subject=f"New Join Request for {community.name}", + html_template_name="review_comment_notification.html", + context=context, + recipient_list=[admin.email], + from_email=settings.DEFAULT_FROM_EMAIL, + ) + + +def send_join_decision_email(user, community, action): + if not user or not user.email: + logger.warning( + f"Cannot send join decision email: user has no email for community {community.id}" + ) + return + + if not is_email_notifications_enabled(user.id): + logger.debug( + f"Email notifications disabled for user {user.id}, skipping join decision email" + ) + return + + domain = get_frontend_domain() + + if action == "approve": + notification_type = "Join Request Approved" + message_text = mark_safe( + f"Your request to join {community.name} has been approved. Welcome!" + ) + link = f"{domain}/community/{quote(community.name, safe='')}" + else: + notification_type = "Join Request Rejected" + message_text = mark_safe( + f"Your request to join {community.name} has been rejected." + ) + link = f"{domain}/communities" + + context = { + "recipient_name": user.first_name or user.username, + "notification_type": notification_type, + "message_text": message_text, + "content_preview": None, + "article_link": link, + } + + send_email_task.delay( + subject=f"Community Join Request {action.capitalize()}d: {community.name}", + html_template_name="review_comment_notification.html", + context=context, + recipient_list=[user.email], + from_email=settings.DEFAULT_FROM_EMAIL, + ) + + def send_comment_notification_email(comment, review, article, community): """ Send email notification when a new comment/reply is added to a review. diff --git a/myapp/settings.py b/myapp/settings.py index efb2522..b758d71 100644 --- a/myapp/settings.py +++ b/myapp/settings.py @@ -341,7 +341,7 @@ "formatters": { "detailed": { "format": LOG_FORMAT, - "datefmt": "%Y-%m-%d %H:%M:%S,%f", + "datefmt": "%Y-%m-%d %H:%M:%S", }, }, "handlers": { @@ -377,7 +377,7 @@ "formatters": { "detailed": { "format": LOG_FORMAT, - "datefmt": "%Y-%m-%d %H:%M:%S,%f", + "datefmt": "%Y-%m-%d %H:%M:%S", }, }, "handlers": {