1주차 OT 8/30
2주차 주제 선정 (타임캡슐) 9/6
3주차 주제 변경 (냉장고 관리 웹사이트) 9/13
4주차 주제 결정 및 plan A, B 설정 9/20
5주차 프로젝트 첫 번째 중간 보고 9/27 (9/21~9/26)
6주차 프로젝트 두 번째 중간 보고 9/27 (9/27~10/3)
7주차 프로젝트 계획 보고서 발표
8주차 시험 주 (자습)
9주차 프로젝트 세 번째 중간 보고
10주차 프로젝트 네 번째 중간 보고(~10/31)
11주차 프로젝트 다섯 번째 중간 보고(~11/07)
12주차 중간점검 (시연)
13주차 프로젝트 여섯 번째 중간 보고 (~11/21)
TDD란 테스트 주도 방식으로 실제로 사이트에서 실행해보지 않아도 코드를 통한 시연이 가능하다. 나는 설정한 시간에 따른 자동 메일 전송을 수행할 때 직접 해당 시간이 될 때까지 기다려야 했기 때문에 TDD 방식이 필요했다.
# calender/tests.py
# from django.test import TestCase
from .views import send_email_function
from unittest.mock import patch, MagicMock
# calender/tests.py
from django.test import TestCase, SimpleTestCase
from django.contrib.auth.models import User
from django.test import Client
# 로그인한 사용자의 이메일을 가져오는지 확인
class UserEmailTest(TestCase):
def setUp(self):
# 테스트 사용자 생성
self.user = User.objects.create_user(username='testuser', email='test@example.com', password='12345')
self.client = Client()
def test_user_email(self):
# 사용자 로그인
self.client.login(username='testuser', password='12345')
# 로그인한 사용자의 이메일 주소 가져오기
user_email = self.user.email
# 이메일 주소 확인
self.assertEqual(user_email, 'test@example.com')
# python manage.py test calender.tests.UserEmailTest
# 자동 메일 전송이 되는지 확인
class EmailTest(SimpleTestCase):
@patch('calender.views.smtplib.SMTP')
def test_send_email_function(self, mock_smtp):
# Mock 객체 설정
mock_server = MagicMock()
mock_smtp.return_value.__enter__.return_value = mock_server
# 함수 호출
email = 'taegeong@naver.com'
name = '테스트 재료'
date = '2023-11-25 00:00:00'
send_email_function(email, name, date)
# 함수가 호출되었는지 검증
mock_server.send_message.assert_called()
# send_message가 호출된 인자 검증
args, kwargs = mock_server.send_message.call_args
sent_message = args[0]
# 이메일 본문 디코딩
payload = sent_message.get_payload(decode=True)
decoded_payload = payload.decode('utf-8')
self.assertIn(email, sent_message['To'])
self.assertIn(name, decoded_payload)
self.assertIn(date, decoded_payload)
결론 : test DB가 제대로 생성이 안돼서 접었어요..
처음에는 fk가 안 만들어졌었는데 다시 db 만들고 부터는 제대로 db를 못 만드네요..
아마 제가 수정하면 안되는 장고 설정 파일을 만져서 그런 것 같습니다..
그래서 다른 파이썬 파일을 통해 테스트 하는 것으로 변경함
자동 메일 전송은 정상적으로 작동함을 확인하였음
# 웹 스크래핑을 통해 레시피 링크를 얻는 함수
def get_recipe_links(food):
base_url = "https://search.naver.com/search.naver?where=view&sm=tab_jum&query="
end = "+요리+레시피"
search_url = base_url + food + end
r = requests.get(search_url)
soup = BeautifulSoup(r.text, 'html.parser')
cook_name_and_link = soup.select(".title_link._cross_trigger")
links = []
for e, item in enumerate(cook_name_and_link, 1):
if e > 10:
break
title = item.text
link = item.get('href')
links.append(f'<li><a href="{link}">{title}</a></li>')
return '<ul>' + ''.join(links) + '</ul>'
# 이메일 전송 함수
def send_email_function(email, name, date): # 이메일 서버 연결 정보
smtp_server = 'smtp.gmail.com' # SMTP 서버 주소 (Gmail의 경우)
smtp_port = 587 # SMTP 서버 포트 (Gmail의 TLS 포트), 465와의 차이는?
date_only = datetime.strptime(date, "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%d")
recipe_links = get_recipe_links(name) # 레시피 링크 가져오기
# 이메일 메세지 설정
subject = f' 장고 : {name}의 소비기한이 3일 남았습니다!' # 이메일 제목
body = f'{name}의 소비기한이 3일 남았습니다!<br>(소비기한: {date_only})<br><br>{recipe_links}'
sender = 'sw.project.django@gmail.com' # 발신자 이메일 주소
# receiver = 'taegeong@naver.com' # 수신자 이메일 주소
# 이메일 메세지 생성
msg = MIMEMultipart()
msg['Subject'] = subject # 이메일 제목 설정
msg['From'] = sender # 발신자 이메일 주소 설정
msg['To'] = email # 수신자 이메일 주소 설정
msg.attach(MIMEText(body, 'html'))
# 이메일 발송
with smtplib.SMTP(smtp_server, smtp_port) as server: # SMTP 서버 연결
server.starttls() # TLS(전송 계층 보안) 시작
server.login(settings.EMAIL_HOST_USER, settings.EMAIL_HOST_PASSWORD) # 이메일 계정 로그인
server.send_message(msg) # 메시지 발송
# 이메일 스케줄링 함수
def schedule_email(user_email, title, event_date):
# 날짜 3일 전 계산
send_date = datetime.strptime(event_date, "%Y-%m-%d %H:%M:%S") - timedelta(days=3)
timezone = pytz.timezone('Asia/Seoul')
scheduler = BackgroundScheduler()
scheduler.add_job(
send_email_function,
'date',
run_date=send_date.replace(tzinfo=timezone),
args=[user_email, title, event_date]
)
scheduler.start()
@login_required
def add_event(request):
# 요청으로부터 데이터 가져오기
title = request.GET.get("title", None)
start = request.GET.get("start", None)
end = request.GET.get("end", None)
f_category = request.GET.get("f_category", None) # f_category 값 가져오기
# 새로운 이벤트 객체 생성 및 저장
event = Events(
name=str(title),
start=start,
end=end,
f_category=f_category, # 카테고리 설정
user=request.user
)
event.save()
# 사용자 이메일과 이벤트 날짜 가져오기
user_email = request.user.email
event_date = start
# 이메일 스케줄링
schedule_email(user_email, title, event_date)
# JSON 응답 반환
data = {'id': event.id} # 생성된 이벤트의 ID를 응답 데이터에 포함
return JsonResponse(data)
test DB가 제대로 만들어지지 않음..