AID 스터디 정리

yeonddori·2023년 7월 3일
0

AID_WEB

목록 보기
6/14

이론 (블로그 정리 O)

[1주차] - 가상환경 공부

pyenv, pipenv, fastapi
https://velog.io/@yeonddori/Python-Pyenv-Pipenv
https://velog.io/@yeonddori/Python-FastAPI

[2주차]

pre-commit, github action, pytest, docker
https://velog.io/@yeonddori/2nd

[3주차]

clone coding – to do app 만들기
https://velog.io/@yeonddori/Clone-coding-To-do-app

[4주차]

docker compose, pymongo, mongodb, sql, nosql
https://velog.io/@yeonddori/Docker-Compose-Pymongo-MongoDB-SQL-NoSQL


프로젝트 과정 (블로그 정리X)

[5주차]

앞으로의 계획과 역할을 나누어 추진 방향을 논의하였고, 나의 역할은 2인 1조로 admin page를 담당하여 만드는 것이었다.

  • 학기 말까지 웹페이지 제작이 목표
  • github 이용시 pull, push 순서 항상 주의하며 지키기

[admin page]

  • admin 따로 하나 만들고 페이지 하나 만들기
    jinja2, html, database, (crud도 필요하면) endpoint에서 db 가져와서 사용
  • 세부적인 기능은 각자 생각해서 만들기
    전달해준 기능에서 추가사항이나 살짝 바꾸는 등 어차피 디자인 쪽이기 때문에 상관X
  • fastapi 튜토리얼 보면서 차근차근 해가기
  • 도움 필요 시 chatgpt 활용
  • 팀끼리 서로 조율을 하면서(어떤 기능을 구현할 건지 정해서 하든지, 같이 얘기하면서 구현하든지) 알아서 하면 됨
  • 이번 주까지 admin 페이지는 만들어놓기(과제)

admin page를 만들기 위해 팀원과 얘기를 하였으나 다음 날부터 연락이 되지 않았다. 다음 회의 전날까지 연락이 되지 않았고, 회의 당일이 되어서야 프로젝트를 관두었다는 사실을 알게 되었다. 연락이라도 해주지 나만 애태웠다..

pull을 받은 후 서버가 열리지 않는 상황을 겪게 되었는데, 그 이유는 env 파일에서 db와 server의 내용이 바뀌었기 때문이었다. 둘의 내용을 바꾼 후 시도해보니 정상적으로 열렸다.

이번 주차는 Jinja2에 대해 공부를 해갔다. 코드를 보며 html에서의 사용법을 이해하고 admin page html을 작성하며 직접 적용도 해보았다.
(Jinja2 따로 블로그 정리할 것)

[6주차]

이제 mongodb에 연결하여 테스트를 해보려고 하였으나, 맥북은 연결이 되고 윈도우는 연결이 되지 않는 아이러니한 상황이 발생하였다. 이번 회의 내내 고치지 못하였고 부득이하게도 다음 회의 전까지 해결하는 것이 목표가 되었는데, 일주일 정도 지난 후 집에서 재설치를 해보았더니 갑자기 연결이 되었다. 이때 업데이트하라는 문구가 떴었고 업데이트를 눌러도 반응이 없자 재설치를 한 것이었는데, 아마 단순 mongodb 버전의 오류이지 않았을까 싶다.

[7주차 ~ 8주차]

시험 전 주 휴무

[9주차]

버튼 클릭시 sumbitdetail page로 이동 구현

  • submission_list 표의 정보 어느 부분을 클릭하든 submission_detail로 이동하도록 구현
  • 마우스를 갖다댔을 때 선택된 부분이 회색으로 표시되도록 구현
  • 마우스를 갖다댔을 때 마우스 커서가 선택(링크 이동) 형태로 바뀌도록 구현
<tr onclick="location.href='/admin/detail?submit_id={{submit._id}}'" onmouseover="this.style.background='#E6E6E6'" onmouseout="this.style.background='white'" style="cursor:pointer">

간단하게 html의 형식을 조금 바꿈으로써 해결할 수 있었다.

+ submit enter 방지 도움
추가적으로 엔터 시 제출되는 현상을 방지하는 것을 도와주기 위해 찾아본 적이 있었는데 이도 단순하게 html에서 조금 바꿔줌으로써 해결할 수 있었다.

<form method="post" action="/submit" onkeypress="if(event.keyCode==13){return false;}">

[10주차]

fastapi 스터디 책 2장까지 읽고, 궁금한 점은 정리하였다. 근데 2장까지의 내용은 이미 이론 공부한 내용이라 복습이 되었고 딱히 궁금한 점은 없었다.
이때 pr 오류가 있어서 회장님께서 해결해주셨다.

[11주차]

팀원과 함께 로그인 폼을 만들고 연결하였다.

이때 패스워드 해싱을 공부하고 직접 적용해보았다.

from fastapi import APIRouter, Request, Form
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from passlib.context import CryptContext

from backend.crud.submit import read_all_submit, read_submit

router = APIRouter()

template = Jinja2Templates(directory="templates")  # terminal 기준 path

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

class HashPassword:
    def create_hash(self, password: str):
        return pwd_context.hash(password)
    
    def verify_hash(self, plain_password: str, hashed_password: str):
        return pwd_context.verify(plain_password, hashed_password)


hash_password = HashPassword()


@router.get("", response_class=HTMLResponse)
def login_page(request: Request):
    """login 페이지 반환"""
    return template.TemplateResponse("login.html", context={"request": request})


@router.post("", response_class=HTMLResponse)
def login(request: Request, username: str = Form(...), password: str = Form(...)):
    # stored_password = hash_password.create_hash("password")
    if username == "admin" and hash_password.verify_hash(password, "$2b$12$hIHjhGoO0nsUD92hynfEQevyg28RvwmyEDydRZSpNOq73BAbxjhRe"):
        print(password)
        # print(stored_password)
        return submission_list_page(request)
    else:
        return template.TemplateResponse("login.html", context={"request": request, "message": "잘못된 ID입니다."})


@router.get("", response_class=HTMLResponse)
def submission_list_page(request: Request):
    """admin 페이지 반환"""

    all_data = read_all_submit()
    # TODO

    return template.TemplateResponse("submission_list.html", context={"request": request, "submission": all_data})


@router.get("/detail", response_class=HTMLResponse)
def submission_detail_page(request: Request, submit_id: str):
    submit_info = read_submit(submit_id)
    print(submit_info)
    return template.TemplateResponse(
        "submission_detail.html",
        context={"request": request, "submit_info": submit_info},
    )

[12주차]

fastapi 스터디 책 4장까지 읽기

이메일 전송 페이지 구현

  • 이메일 단체 보내기
  • mongodb와 연결

[13주차]

모든 스터디의 진행 상황을 발표하는 세미나를 진행하였다.
세미나 발표 준비를 위해 함께 피피티와 발표 대본을 제작하였다.

[14주차]

fastapi 스터디 책 끝까지 읽기

import smtplib
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.text import MIMEText

from fastapi import APIRouter, Request, status, BackgroundTasks
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates

from backend.crud.user import read_all_is_pass_email
from backend.core import settings

router = APIRouter()

template = Jinja2Templates(directory="templates")  # terminal 기준 path


@router.get("", response_class=HTMLResponse)
def sender_page(request: Request):
    return template.TemplateResponse("sender.html", context={"request": request})


@router.post("/send_email")
async def sender(request: Request, background_tasks: BackgroundTasks):
    # SMTP 서버를 dictionary로 정의
    smtp_info = {
        'gmail.com': ('smtp.gmail.com', 587),
        'naver.com': ('smtp.naver.com', 587),
        'outlook.com': ('smtp-mail.outlook.com', 587),
        'hotmail.com': ('smtp-mail.outlook.com', 587),
        'yahoo.com': ('smtp.mail.yahoo.com', 587),
        'nate.com': ('smtp.mail.nate.com', 465),
        'daum.net': ('smtp.daum.net', 465),
        'hanmail.net': ('smtp.daum.net', 465)
    }

    # 메일 보내는 함수 정의 (발신 메일, 수신 메일(여러개 가능), 제목, 본문, 비밀번호)
    def send_email(From, To, subject, message, passwd='', subtype='plain'):
        
        # 멀티파트로 메일을 만들기 위한 포맷 생성
        form = MIMEBase('multipart', 'mixed')
        
        # 입력받은 메일주소와 제목, 본문 등의 문자열을 인코딩해서 form에 입력
        form['From'] = From
        form['To'] = ', '.join(To) # 수신 메일 리스트를 문자열로 변환 (,와 한칸 공백을 추가해서 구분)
        form['Subject'] = Header(subject.encode('utf-8'), 'utf-8')
        msg = MIMEText(message.encode('utf-8'), _subtype=subtype, _charset='utf-8')
        form.attach(msg)
            
        # SMTP 서버 로그인 및 작성된 메일 보내기
        id, host = From.rsplit("@",1) # 발신인 메일 주소의 @를 기준으로 id와 host로 나눔
        smtp_server, port = smtp_info[host] # dict를 이용해서 host와 port 정보들을 받아옴
        
        # SMTP 서버 접속 여부 확인
        if port == 587:
            smtp = smtplib.SMTP(smtp_server, port)
            rcode1, _ = smtp.ehlo()
            rcode2, _ = smtp.starttls()
        else:
            smtp = smtplib.SMTP_SSL(smtp_server, port)
            rcode1, _ = smtp.ehlo()
            rcode2 = 220  
        if rcode1 != 250 or rcode2 != 220:
            smtp.quit()
            return '연결에 실패하였습니다.'
        
        smtp.login(From, passwd)
        smtp.sendmail(From, To, form.as_string())    
        smtp.quit()


    # 실제 함수 실행 부분
    me = settings.email_id
    data = await request.form()
    is_pass = True if data["status"] == "true" else False # 합격/불합격 선택 여부 확인
    receivers = read_all_is_pass_email(True) if is_pass else read_all_is_pass_email(False)

    subject = data["subject"] # 제목
    message = data["message"] # 본문

    background_tasks.add_task(send_email, me, receivers, subject, message, passwd=settings.email_pw)

    return RedirectResponse(url="/admin", status_code=status.HTTP_303_SEE_OTHER)

이메일 backgroundtasks로 동작하게 변경

메일 전송 클릭 시 이메일 전송 페이지 이동

pagination 처음과 끝 이동 버튼 수정

0개의 댓글

관련 채용 정보