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": {