티스토리 뷰

S.A (Starting Assignments) ~ 최종 설계

S.A

 

[내일배움캠프-팀 프로젝트] 개발 is in: S.A 작성

프로젝트 설명 프로젝트명: 개발 is in 개발자들이 모여서 글을 쓰는 곳이라는 의미를 담은 이름입니다. 핵심 목적: 개발 스택별로 구분된 게시판을 통해 개발과 관련한 꿀팁들을 공유할 수 있는

interrobang.tistory.com

최종 API

 

개발 is in _ API

A new tool for teams & individuals that blends everyday work apps into one.

go-tiger.notion.site

최종 DB

 

개발 is in _ DB

시트1 USER 컬럼,데이터 타입,제약조건,설명 id,varchar(30),PRIMARY KEY,유저 아이디 email,VARCHAR(50),UNIQUE,유저 이메일 password,VARCHAR(200),NOT NULL,유저 비밀번호(암호화) name,VARCHAR(50),NOT NULL,유저 닉네임 image,VA

docs.google.com

 

완성본

GitHub

 

GitHub - dial11/B2_Project: 22.12.02 B조 2반 프로젝트_뉴스피드 만들기

22.12.02 B조 2반 프로젝트_뉴스피드 만들기. Contribute to dial11/B2_Project development by creating an account on GitHub.

github.com

AWS 배포

 

개발 is in

개발자들만의 꿀팁을 나눠요

54.180.106.216

시연 영상

 

체크리스트 & 아쉬운 점

  • 회원 기능
    • ✅ 회원 가입, 로그인 구현
    • ✅ 마이 페이지 프로필 수정 구현
    • ✅ 비밀번호 DB에 암호화 → Bcrypt 라이브러리 이용하여 바이트 코드로 변환
  • DB
    • ✅ MySQL 정규화 작업
    • ✅ MySQL Join 쿼리문을 활용 하여 데이터 전달
  • CRUD
    • ✅ 게시글 쓰기(+이미지 업로드) 기능 구현
    • ✅ 게시글 글 보여주기 구현
    • ✅ 게시글 글 수정 구현
    • ✅ 게시글 글 삭제 구현
  • GIT
    • ✅ git add / commit / push 활용
    • ✅ git pull / merge 활용
  • 기타 기능
    •  ❗ Logging 데이터 확인 가능: 핸들러, 포매터의 적절한 사용으로 유의미한 로깅이 가능하도록 해야함
    •  ❗ Pagination 정상 동작 →  ✅ 무한스크롤: 특정 페이지로 이동 가능할 수 있도록 pagination과 무한스크롤 모두 가능하면 좋을 것
    •  ❗ 세션 관리: 서버가 알아야할 정보들을 저장할 수 있으나 유지 조건에 관하여 고려해야함

 

주요 코드

카테고리, 페이지 나누기

@app.route('/board', defaults={'category': 'all', 'page': 1})
@app.route('/board/<string:category>/<int:page>')

...
	perpage = 5
	startat = (page - 1) * perpage

        sql = f"""
            SELECT b.id, b.title, b.content, b.created_at, b.updated_at, u.name, u.image, c.name_en
            FROM board b
            INNER JOIN `user` u
            ON b.user_id = u.id
            INNER JOIN category c
            ON b.category_id = c.id
            WHERE c.name_en = '{category}'
            ORDER BY b.id desc
            LIMIT {perpage}
            OFFSET {startat}
            """

암호화

#회원가입시
...
userId = request.form['id']
    password = request.form['password']
    # 입력된 비밀번호를 바이트 코드로 변환
    byte_input = password.encode('UTF-8')
    hash = bcrypt.hashpw(byte_input, bcrypt.gensalt()).hex()
    userName = request.form['name']
    email = request.form['email']

    sql = f'INSERT INTO `user` (id, password, name, email) VALUES("{userId}", "{hash}", "{userName}", "{email}");'
...


#로그인시
...
userId = request.form['id']
password = request.form['password']

# 입력된 비밀번호를 바이트 코드로 변환
byte_input = password.encode('UTF-8')

sql = f'select id,password,name,email,image,description from user where user.id = "{userId}"'

curs.execute(sql)
result = curs.fetchone()
list_result = list(result)
# 기존 저장된 값을 연산을 위해 hex에서 바이트로 변경
origin_pw = bytes.fromhex(list_result[1])
pw_check = bcrypt.checkpw(byte_input, origin_pw)
...

프로필 사진 업로드

file = request.files["file_give"]
    userId = session['id']

    if not os.path.isdir("static/image/user"):
        os.makedirs('static/image/user')  # upload/image 폴더 없을 경우 자동생성
    if file:
        # 매번 확장자가 jpg가 아닐수도 있으니까 파일 네임에서 가장 마지막 점으로 split을 한다
        extension = file.filename.split('.')[-1]
        today = datetime.now()
        mtime = today.strftime('%Y-%m-%d-%H-%M-%S')
        filename = f'{userId}-{mtime}.{extension}'
        save_to = f'static/image/user/{filename}'
        file.save(save_to)

        sql = f'UPDATE `project2b2`.`user` SET image="{filename}" WHERE id="{userId}";'

        curs.execute(sql)
        session['image'] = filename

게시글 수정

@app.route('/boardedit/<int:board_id>/post', methods=['PATCH'])
def postBoard(board_id):

...

    selectPost = request.form['category_id']
    postTitle = request.form['title']
    postContent = request.form['content']
    # userId = session['id']

    sql1 = f"""UPDATE board b
            SET title = %s , content = %s , category_id = %s , updated_at = NOW() 
            WHERE b.id = '{board_id}' """

 

팀 에이스 지우님의 원픽 코드

# 회원탈퇴-----------------------------------------------------
@app.route('/delete/user', methods=['POST'])
def deleteUser():
    db = pymysql.connect(
        user='project2b2',
        password='project2b2',
        host='182.212.65.173',
        port=3306,
        database='project2b2',
        charset='utf8'
    )
    curs = db.cursor()

    idf = request.form['idf']
    pwf = request.form['pwf']
    byte_input = pwf.encode('UTF-8')
    # print(idf, pwf, 2)

    sql_check = f'select password from `user` where id = "{idf}" '

    curs.execute(sql_check)
    print(sql_check)
    result = curs.fetchone()
    print(result)
    if result is None:
        return jsonify({'msg': '회원이 아닙니다.'})

    origin_pw = bytes.fromhex(result[0])
    pw_check = bcrypt.checkpw(byte_input, origin_pw)
    db.commit()
    db.close()

    if pw_check is None:
        return jsonify({'msg': '회원이 아닙니다.'})

    db = pymysql.connect(
        user='project2b2',
        password='project2b2',
        host='182.212.65.173',
        port=3306,
        database='project2b2',
        charset='utf8'
    )
    curs = db.cursor()

    idf = request.form['idf']
    pwf = request.form['pwf']

    sql_check = f'delete from `user` where id = "{idf}" '

    curs.execute(sql_check)
    db.commit()
    db.close()

    return jsonify({'msg': '회원탈퇴가 되었습니다.'})

가장 마지막에 작성한 코드인데, 지금까지 작성해온 코드를 바탕으로 혼자서 작성해낸 코드라서 가장 마음에 듭니다!

 

완성 소감

  • 변준혁: 생각보다 쉽지 않고 막히는 부분도 많았지만 완성 된 페이지를 보니 같이 고생한 팀원들이 자랑스럽습니다.
  • 장빈: 팀원들 모두 고생많았고, 완성시킬 수 있어서 너무 뿌듯했습니다.
  • 정지우: 이번엔 sql을 이용해 db를 사용해보았는데 처음엔 어떻게 쓰는지 모르겠어서 힘들었지만 하나의 웹사이트를 만들고보니 너무 뿌듯하고 자랑하고싶다!
  • 천준기: DB 배우자마자 이렇게 활용해서 하나의 결과물을 내니 너무 뿌듯합니다.

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함