Skip to content

Commit

Permalink
Merge pull request #5 from sepid-org/email-service
Browse files Browse the repository at this point in the history
Email Service
  • Loading branch information
AmooHashem authored Jun 16, 2024
2 parents f1e16a7 + d5430d8 commit f4b306e
Show file tree
Hide file tree
Showing 26 changed files with 601 additions and 92 deletions.
9 changes: 4 additions & 5 deletions apps/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

from apps.accounts.validators import percentage_validator
from manage_content_service.settings.base import VOUCHER_CODE_LENGTH, DISCOUNT_CODE_LENGTH, PURCHASE_UNIQ_CODE_LENGTH
from proxies.sms_system.main import SMS_CODE_DELAY, SMS_CODE_LENGTH, get_sms_service_proxy
from proxies.sms_system.settings import SMS_CODE_DELAY, SMS_CODE_LENGTH
from proxies.sms_system.sms_service_facade import SMSServiceFacade


class User(AbstractUser):
Expand Down Expand Up @@ -385,10 +386,8 @@ class VerificationType(models.TextChoices):
objects = VerificationCodeManager()

def notify(self, verification_type, party_display_name='سپید'):
sms_service_proxy = get_sms_service_proxy(
type='kavenegar', token='todo')
sms_service_proxy.send_otp(
self.phone_number, verification_type, token=party_display_name, token2=str(self.code))
sms_service_facade = SMSServiceFacade(provider='kavenegar')
sms_service_facade.send_otp(self.phone_number, verification_type, token=party_display_name, token2=str(self.code))

def __str__(self):
return f'{self.phone_number}\'s code is: {self.code} {"+" if self.is_valid else "-"}'
Expand Down
2 changes: 1 addition & 1 deletion apps/accounts/serializers/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from errors.error_codes import serialize_error
from manage_content_service.settings.base import DISCOUNT_CODE_LENGTH
from proxies.sms_system.main import SMS_CODE_LENGTH
from proxies.sms_system.settings import SMS_CODE_LENGTH
from ..models import User, VerificationCode, EducationalInstitute, School, University, SchoolStudentship, Studentship, \
AcademicStudentship, Merchandise, DiscountCode, Purchase
from ..validators import phone_number_validator, grade_validator, price_validator
Expand Down
9 changes: 4 additions & 5 deletions apps/fsm/views/registration_receipt_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from apps.fsm.permissions import IsRegistrationReceiptOwner, IsReceiptsFormModifier
from apps.fsm.serializers.answer_sheet_serializers import RegistrationReceiptSerializer, RegistrationStatusSerializer
from apps.fsm.serializers.certificate_serializer import create_certificate
from proxies.sms_system.main import get_sms_service_proxy
from proxies.sms_system.sms_service_facade import SMSServiceFacade


class RegistrationReceiptViewSet(GenericViewSet, RetrieveModelMixin, DestroyModelMixin):
Expand Down Expand Up @@ -82,11 +82,10 @@ def validate(self, request, pk=None):

# todo: fix academy name
if older_status != receipt.status:
sms_service_proxy = get_sms_service_proxy(
type='kavenegar', token='todo')
sms_service_proxy.send_otp(
sms_service_facade = SMSServiceFacade(provider='kavenegar')
sms_service_facade.send_otp(
receptor_phone_number=receipt.user.phone_number,
type=sms_service_proxy.RegularSMSTypes.UpdateRegistrationReceiptState,
type=sms_service_facade.RegularSMSTypes.UpdateRegistrationReceiptState,
# todo: get real academy name from mps
token='کاموا',
token2=receipt.answer_sheet_of.program_or_fsm.name
Expand Down
390 changes: 390 additions & 0 deletions assets/greeting_mail.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion errors/error_codes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from rest_framework.exceptions import ValidationError

from proxies.sms_system.main import SMS_CODE_LENGTH
from proxies.sms_system.settings import SMS_CODE_LENGTH

logger = logging.getLogger(__name__)

Expand Down
3 changes: 3 additions & 0 deletions manage_content_service/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from manage_content_service.celery_app import app as celery_app

__all__ = ("celery_app",)
7 changes: 7 additions & 0 deletions manage_content_service/celery_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'manage_content_service.settings.development')
app = Celery()
app.config_from_object('django.conf:settings', namespace="CELERY")
app.autodiscover_tasks()
60 changes: 21 additions & 39 deletions manage_content_service/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def get_environment_var(var_name, default, prefixed=True):
return os.getenv(var_name, default)


CORS_ORIGIN_ALLOW_ALL = True

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(
os.path.dirname(os.path.abspath(__file__))))
Expand All @@ -43,6 +45,8 @@ def get_environment_var(var_name, default, prefixed=True):
'rest_framework.authtoken',
'import_export',
'drf_yasg',
'celery',
'messenger',
'polymorphic',
'django_extensions',
'django_filters',
Expand Down Expand Up @@ -72,26 +76,6 @@ def get_environment_var(var_name, default, prefixed=True):
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# multi-lingual settings below
# LANGUAGES = [
# ('en', _('English')),
# ('fa', _('Persian')),
# ]

# USE_I18N = True
#
# USE_L10N = True
#
# LANGUAGE_CODE = 'en'
#
# LOCALE_PATHS = [
# os.path.join(BASE_DIR, 'locale'),
# ]
# multilingual settings above

CORS_ORIGIN_ALLOW_ALL = True

ROOT_URLCONF = 'manage_content_service.urls'

TEMPLATES = [
{
Expand All @@ -109,6 +93,7 @@ def get_environment_var(var_name, default, prefixed=True):
},
]


WSGI_APPLICATION = 'manage_content_service.wsgi.application'

# Password validation
Expand Down Expand Up @@ -151,31 +136,17 @@ def get_environment_var(var_name, default, prefixed=True):
MEDIA_URL = '/api/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

EMAIL_HOST = 'smtp.zoho.com'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'ET6vmrh.$gHZFjL'
EMAIL_PORT = 587
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_USE_SSL = False
DEFAULT_FROM_EMAIL = "Rastaiha <" + EMAIL_HOST_USER + ">"

# Activate Django-Heroku.

OK_STATUS = 'ok'
ERROR_STATUS = 'err'
HELP_STATUS = 'help'

THUMBNAIL_ALIASES = {
'': {
'avatar': {'size': (80, 80), 'crop': True},
},
}
EMAIL_PORT = 587
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'tmyz glmk cjsj urnw'

STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

CONSTANTS = {
"PAGINATION_NUMBER": 50,

}

# Custom user model
Expand Down Expand Up @@ -227,6 +198,17 @@ def get_environment_var(var_name, default, prefixed=True):
PURCHASE_UNIQ_CODE_LENGTH = 10


########## Celery ##########

CELERY_TIMEZONE = TIME_ZONE
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
ROOT_URLCONF = 'manage_content_service.urls'
CELERY_BROKER_URL = get_environment_var('BROKER_URL', 'amqp://')


########## Zarrinpal Payment ##########

def GET_PAYMENT_CALLBACK_URL(domain, status):
PAYMENT = {
'success': f'http://{domain}/message/payment/success',
Expand Down
2 changes: 2 additions & 0 deletions manage_content_service/settings/development.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

ALLOWED_HOSTS = ['*']



# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

Expand Down
1 change: 1 addition & 0 deletions manage_content_service/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
path('api/report/', include('apps.report.urls')),
path('api/scoring/', include('apps.scoring.urls')),
path('test/hi/', say_hello),
path('email/' , include('messenger.urls')),
# https://pypi.org/project/django-link-shortener/
path('s/', include('shortener.urls')),
]
Expand Down
Empty file added messenger/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions messenger/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions messenger/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class MessengerConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'messenger'
Empty file.
3 changes: 3 additions & 0 deletions messenger/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
15 changes: 15 additions & 0 deletions messenger/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from celery import shared_task
from django.core.mail import EmailMessage


@shared_task()
def send_email_task(subject, recipients_emails, body):
sender_email = '[email protected]'
mail = EmailMessage(subject=subject, body=body,
from_email=sender_email, to=recipients_emails)
mail.content_subtype = 'html'
try:
mail.send()
return True
except:
return False
3 changes: 3 additions & 0 deletions messenger/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
6 changes: 6 additions & 0 deletions messenger/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.urls import path
from messenger.views import *

urlpatterns = [
path('test/', send_email)
]
49 changes: 49 additions & 0 deletions messenger/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import os
from django.http import HttpResponse
from messenger.tasks import send_email_task
from manage_content_service.settings.base import BASE_DIR


import requests
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import redirect

@csrf_exempt
def send_email(request):
if request.method == 'POST':
email_data = {
# todo: convert it to recipients:
"email": request.POST.get("email"),
"subject": request.POST.get("subject"),
"body": request.POST.get("body")
# todo: add a field for choosing template
}
response = requests.post("http://127.0.0.1:8080/send-email/", json=email_data)

if response.status_code == 200:
return JsonResponse({"message": "Email has been sent"}, status=200)
else:
return JsonResponse({"error": "Failed to send email"}, status=500)

return JsonResponse({"error": "Invalid request method"}, status=405)



# def send_email(request):
# html_content =os.path.join(BASE_DIR, "assets/greeting_mail.html")
# html_content= open(html_content, "r", encoding="utf-8").read()
# send_emailQeue.delay("ehsna" , "[email protected]" , html_content)
# return HttpResponse("goi")


# def send_email(request):
# subject = 'Subject of the email'
# message = 'This is the message body.'
# from_email = '[email protected]' # Sender's email address
#
# # List of recipient email addresses
# recipient_list = ['[email protected]']
#
# send_mail(subject, message, from_email, recipient_list)
# return HttpResponse('Email sent successfully!')
7 changes: 7 additions & 0 deletions proxies/email_service/send_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# email api: https://smtp.sepid.org/send-email/

# todo: remove messenger app

def send_email():
# todo
pass
15 changes: 9 additions & 6 deletions proxies/sms_system/kavenegar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@

from kavenegar import *

from proxies.sms_system.main import SMSServiceProxy
from proxies.sms_system.sms_service_interface import SMSService


class KaveNegarSMSServiceProxy(SMSServiceProxy):
class KaveNegarSMSService(SMSService):

def __init__(self, token) -> None:
def __init__(self, token: str) -> None:
super().__init__()
self.api = KavenegarAPI(token)

def send_sms(self):
pass

def send_otp(self, receptor_phone_number, type, token, token2=None, token3=None):
params = {
'receptor': receptor_phone_number,
Expand All @@ -26,3 +23,9 @@ def send_otp(self, receptor_phone_number, type, token, token2=None, token3=None)
if token3:
params['token3'] = token3
self.api.verify_lookup(params)

def send_bulk(self):
return super().send_bulk()

def send_sms(self):
return super().send_sms()
35 changes: 0 additions & 35 deletions proxies/sms_system/main.py

This file was deleted.

2 changes: 2 additions & 0 deletions proxies/sms_system/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SMS_CODE_DELAY = 5
SMS_CODE_LENGTH = 5
21 changes: 21 additions & 0 deletions proxies/sms_system/sms_service_facade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from proxies.sms_system.sms_service_interface import SMSService


class SMSServiceFacade(SMSService):
provider: SMSService = None

def __init__(self, provider: str) -> None:
if provider == 'kavenegar':
from proxies.sms_system.kavenegar import KaveNegarSMSService
from django.conf import settings
self.provider = KaveNegarSMSService(token=settings.KAVENEGAR_TOKEN)

def send_otp(self, receptor_phone_number, action, token, token2=None, token3=None):
self.provider.send_otp(receptor_phone_number,
action, token, token2, token3)

def send_sms(self):
self.provider.send_sms()

def send_bulk(self):
self.provider.send_bulk()
Loading

0 comments on commit f4b306e

Please sign in to comment.