Skip to content
This repository was archived by the owner on Jan 4, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions 광공중나#4/board.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import os
import csv
from post import Post

SAVE_FILE_PATH = './광일공방중고나라_게시판목록.csv'

def auto_save(func):
# caller.save가 구현되지 않은 곳에 데코레이터가 붙은 경우에 대한 예외 처리
def decorated(caller, *args, **kwargs):
func(caller, *args, **kwargs)
caller.save()
return decorated

class Board():
PAGINATION_SIZE = 15

def __init__(self, user_id):
self.user_id = user_id
self.posts = list()
self.actions = [self.create_post, self.update_post, self.delete_post, self.save, self.go_to_previous_page, self.go_to_next_page]
self.current_page_num = 1
self.load()

@staticmethod
def print_actions():
print('-' * 100)
print('1. 작성하기')
print('2. 수정하기')
print('3. 삭제하기')
print('4. 저장하기')
print('5. 이전 페이지로')
print('6. 다음 페이지로')
print('-' * 100)

# iterate posts and print
def show_posts(self):
reversed_posts = list(reversed(self.posts))
reversed_existed_posts = [post for post in reversed_posts if post.existence_state] # filter soft_deleted posts

fromIdx = Board.PAGINATION_SIZE * (self.current_page_num - 1)
toIdx = Board.PAGINATION_SIZE * self.current_page_num
for post in reversed_existed_posts[fromIdx:toIdx]:
print('{:^6} | {:60.60} | {:^10} | {}'.format(post.posting_num, post.posting_title, post.posting_user, post.posting_time))

# check existence of post in posts and handle messages
def check_existence_of_posts(self):
if len(self.posts) == 0:
print('게시판에 아직 작성된 글이 없습니다.')
print('한 번 작성해 보는 것은 어떨까요?')
return
self.show_posts()

def find_target_post(self, target_posting_num):
target_post = None
i = 0
while target_post is None and i < len(self.posts):
target_post = self.posts[i] if self.posts[i].posting_num == target_posting_num else None
i += 1
return target_post

@auto_save
def create_post(self):
post = Post(posting_user = self.user_id)
self.posts.append(post)
print('{}번 글이 성공적으로 작성되었습니다.'.format(post.posting_num))

@auto_save
def update_post(self):
if len(self.posts) == 0:
raise Exception('현재 글이 없습니다.')

update_idx = int(input('몇 번 글을 수정할까요? '))
post_to_update = self.find_target_post(update_idx)
if post_to_update is None or post_to_update.existence_state is False:
raise Exception('수정할 해당 번호 글이 없습니다.')

post_to_update.update_posting_title(self.user_id)

@auto_save
def delete_post(self):
if len(self.posts) == 0:
raise Exception('현재 글이 없습니다.')

delete_idx = int(input('몇 번 글을 지울까요? '))
post_to_delete = self.find_target_post(delete_idx)
if post_to_delete is None or post_to_delete.existence_state is False:
raise Exception('삭제할 해당 번호 글이 없습니다.')

post_to_delete.soft_delete_post(self.user_id)

def save(self):
global SAVE_FILE_PATH

f = open(SAVE_FILE_PATH, 'w', encoding='utf-8')
for post in self.posts:
print(post.to_csv(), file=f)
f.close()

def load(self):
global SAVE_FILE_PATH
if os.path.exists(SAVE_FILE_PATH) is False:
return

f = open(SAVE_FILE_PATH, 'r', encoding='utf-8')
posts = f.readlines()
for post in posts:
self.posts.append(Post.from_csv(post))
f.close()

def go_to_previous_page(self):
if self.current_page_num == 1:
input('이전 페이지가 없습니다.')
return
self.current_page_num -= 1

def go_to_next_page(self):
if (self.current_page_num - 1) * Board.PAGINATION_SIZE < len(self.posts) <= self.current_page_num * Board.PAGINATION_SIZE:
input('다음 페이지가 없습니다.')
return
self.current_page_num += 1

# manage CRUD of posts
def post_CRUD_handler(self):
try:
menuSel = int(input('> '))
self.actions[menuSel - 1]()
return
except TypeError:
input('잘못 입력하셨습니다. 올바른 번호를 선택하세요.')
except IndexError:
input('잘못 입력하셨습니다. 현재 글 번호를 맞게 입력하세요.')
except Exception as e:
input('잘못 입력하셨습니다.', e)
78 changes: 78 additions & 0 deletions 광공중나#4/membership_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import hashlib
import os
from user import User

USER_FILE_PATH = './광일공방중고나라_사용자목록.csv'

class Membership_manager():
def __init__(self):
self.actions = [self.log_in, self.sign_up]

# 로그인 / 회원가입 메뉴
def menu(self):
print('-' * 100)
print('1. 로그인')
print('2. 회원가입')
print('-' * 100)

def action_handler(self):
try:
menuSel = int(input('> '))
if menuSel <= 0:
raise IndexError
return self.actions[menuSel - 1]()
except ValueError:
input('잘못 입력하셨습니다. 올바른 번호를 선택하세요.')
except IndexError:
input('잘못 입력하셨습니다. 메뉴의 번호를 알맞게 입력하세요.')
except Exception as e:
input('잘못 입력하셨습니다.', e)

# 입력한 ID와 사용자 목록에서의 아이디 비교
def check_existing_id(self, id):
global USER_FILE_PATH
if os.path.exists(USER_FILE_PATH) is False:
return None

f = open(USER_FILE_PATH, 'r', encoding='utf-8')
users = f.readlines()
target_user = None
i = 0
while i < len(users) and target_user is None:
target_id, target_pwd = users[i][:-1].split(',')
target_user = (target_id, target_pwd) if target_id == id else None
i += 1
f.close()
return target_user

def log_in(self):
global USER_FILE_PATH

id = input('아이디 : ')
pwd = input('비밀번호 : ')
target_id, target_pwd = self.check_existing_id(id) or (None, None)
if target_id is None:
input('로그인 실패 : 아이디가 존재하지 않습니다. 처음이시라면 회원가입을 선택해주세요.')
return None
if target_pwd != hashlib.sha256(pwd.encode()).hexdigest():
input('로그인 실패 : 비밀번호가 틀렸습니다. 다시 시도해주세요.')
return None

input('로그인 성공 : 환영합니다 {}님!'.format(id))
return id

def sign_up(self):
id = input('아이디 : ')
pwd = input('비밀번호 : ')
target_id, _ = self.check_existing_id(id) or (None, None)
if target_id is not None:
input('회원가입 실패 : 해당 아이디가 이미 존재합니다. 다른 아이디를 작성해주세요.')
return None

new_user = User(id, pwd)
f = open(USER_FILE_PATH, 'a', encoding='utf-8')
print(new_user.to_csv(), file=f)
f.close()

input('회원가입 및 로그인 성공 : 환영합니다 {}님!'.format(id))
return id
45 changes: 45 additions & 0 deletions 광공중나#4/post.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from datetime import datetime

def auto_check_permission(action_type):
def decorated(func):
def inner(caller, *args, **kwargs):
if caller.check_permission(*args, action_type = action_type): # 처리하려면 조건 True
func(caller, *args, **kwargs)
return inner
return decorated

class Post():
CURRENT_POSTING_NUM = 0

def __init__(self, posting_user, existence_state = None, posting_num = None, posting_title = None, posting_time = None):
self.posting_user = posting_user
self.existence_state = True if existence_state is None else existence_state == 'True' # check the validation of this post
self.posting_num = Post.CURRENT_POSTING_NUM + 1 if posting_num is None else int(posting_num)
Post.CURRENT_POSTING_NUM = Post.CURRENT_POSTING_NUM + 1 if posting_num is None else max(Post.CURRENT_POSTING_NUM, int(posting_num))
self.posting_title = input('작성 > ') if posting_title is None else posting_title
self.posting_time = datetime.now().strftime('%Y-%m-%d %H:%M') if posting_time is None else posting_time

def check_permission(self, user_id, action_type):
action_kwds = ['수정', '삭제']
if user_id != self.posting_user:
input('{}님께는 해당 글 {} 권한이 없습니다!'.format(user_id, action_kwds[action_type - 1]))
return False
return True

@auto_check_permission(1)
def update_posting_title(self, user_id):
self.posting_title = input('수정 > ')
input('{}번 글이 성공적으로 수정되었습니다.'.format(self.posting_num))

@auto_check_permission(2)
def soft_delete_post(self, user_id):
self.existence_state = False
input('{}번 글이 성공적으로 삭제되었습니다.'.format(self.posting_num))

@classmethod
def from_csv(cls, csv):
existence_state, posting_num, posting_title, posting_user, posting_time = csv[:-1].split(',')
return cls(posting_user, existence_state, posting_num, posting_title, posting_time)

def to_csv(self):
return '{},{},{},{},{}'.format(self.existence_state, self.posting_num, self.posting_title, self.posting_user, self.posting_time)
9 changes: 9 additions & 0 deletions 광공중나#4/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import hashlib

class User():
def __init__(self, id, pwd):
self.id = id
self.pwd = hashlib.sha256(pwd.encode()).hexdigest()

def to_csv(self):
return '{},{}'.format(self.id, self.pwd)
37 changes: 37 additions & 0 deletions 광공중나#4/광일공방중고나라#4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
import sys
from board import Board
from membership_manager import Membership_manager

def clear_screen():
os.system('cls' if os.name == 'nt' else 'clear')

def greeting_messages():
clear_screen()
print("""
본 프로그램은 광일공방에서 중고거래 사이트를 기웃기웃 거리던 광일이가
어느 날 삘이 꽃혀 '아! 여기가 돈 나오는 방석이다!' 생각하자마자 아주
급하게 만들어낸 불안정한 중고거래 사이트입니다. 물론 아직은 허접한
게시판이지만 1000만 사용자를 꿈꾸는 광일이는 커다란 희망의 씨앗을 마음에
품고서 오늘도 밤을 지새우며 코드를 작성합니다.""")
print()
input('프로그램을 시작하시려면 로그인하세요...')


if __name__ == '__main__':
greeting_messages()
membership_manager = Membership_manager()
while True:
clear_screen()
membership_manager.menu()
log_in_user_id = membership_manager.action_handler() # 로그인 성공한 유저가 없으면 None, 있으면 id 반환

if log_in_user_id is not None:
break

board = Board(log_in_user_id)
while True:
clear_screen()
board.check_existence_of_posts()
board.print_actions()
board.post_CRUD_handler()