def __init__(self, board_name, board_alias, board_description, order, category, type=BOARD_TYPE_NORMAL, to_read_level=3, to_write_level=3, anonymous=False): ''' @type board_name: string @type board_description: string @type order: int @type category: model.Category @type type: int @type to_read_level: int (0: 비회원, 1: 메일인증(non-@kaist), 2: 메일인증(@kaist), 3: 포탈인증) @type to_write_level: int (0: 비인증, 1: 메일인증(non-@kaist), 2: 메일인증(@kaist), 3: 포탈인증) ''' self.board_name = smart_unicode(board_name) self.board_alias = smart_unicode(board_alias) self.board_description = smart_unicode(board_description) self.deleted = False self.read_only = False self.hide = False self.order = order self.category = category self.type = type self.to_read_level = to_read_level self.to_write_level = to_write_level
def __init__(self, board, heading, title, content, author, author_ip, parent): ''' @type board: model.Board @type heading: model.BoardHeading @type title: string @type content: string @type author: model.User @type author_ip: string @type parent: model.Article ''' self.board = board self.heading = heading self.title = smart_unicode(title) self.content = smart_unicode(content) self.author = author self.author_nickname = author.nickname self.author_ip = smart_unicode(author_ip) self.deleted = False self.date = datetime.datetime.fromtimestamp(time.time()) self.hit = 0 self.positive_vote = 0 self.negative_vote = 0 self.reply_count = 0 self.is_searchable = True if parent: if parent.root: self.root = parent.root else: self.root = parent else: self.root = None self.parent = parent self.last_modified_date = self.date self.destroyed = False self.last_reply_date = self.date
def login(self, username, password, user_ip): ''' 로그인 처리를 담당하는 함수. 아이디와 패스워드를 받은 뒤 사용자 Login Session를 리턴. @type username: string @param username: User Username @type password: string @param password: User Password @type user_ip: string @param user_ip: User IP @rtype: string @return: 사용자 Login Session ''' # TODO: login 함수가 고민할 필요가 없는 Exception 들은 그냥 넘기기 (더 이상 매니저간 통신은 Thrift 를 거치지 않는다) username = smart_unicode(username) password = smart_unicode(password) user_ip = smart_unicode(user_ip) # 가끔 Thrift 가 맛이 가서 LoginManager -> MemberManager 통신이 끊어질 때가 있다. # 이런 경우 Thrift 자체 Timeout 이 지난 뒤에 Error 가 돌아가므로, InternalError 로 에쁘게 Wrapping 한다. try: msg = self.engine.member_manager.authenticate(username, password, user_ip) except InvalidOperation: raise except InternalError: raise except Exception, e: self.logger.warning("Internal Error occur on MemberManager.authenticate(): %s" % repr(e)) raise InternalError("Ask SYSOP")
def edit_category(self, session_key, category_name, new_category_name): ''' 카테고리의 이름을 변경한다. @type session_key: string @param session_key: 사용자 로그인 Session @type category_name: string @param category_name: 변경할 카테고리의 이름 @type new_category_name: string @param new_category_name: 카테고리의 새 이름 @rtype: void @return: 1.성공 : 아무것도 리턴하지 않음 2.실패 : 이미 있는 카테고리의 이름일 경우 InvalidOperation(category already exists) ''' self._is_sysop(session_key) category_name = smart_unicode(category_name) new_category_name = smart_unicode(new_category_name) session = model.Session() category = self._get_category_from_session(session, category_name) category.category_name = new_category_name try: session.commit() session.close() except IntegrityError: raise InvalidOperation("category already exists") except InvalidRequestError: # TODO: 어떤 경우에 이렇게 되나? raise InternalError() self._clear_cache(category=True)
def _add_board(self, board_name, board_alias, board_description, heading_list, category_name, board_type, to_read_level, to_write_level): ''' 보드를 신설한다. 내부 사용 전용. @type session_key: string @param session_key: 사용자 Login Session (시삽이어야 함) @type board_name: string @param board_name: 개설할 Board Name @type board_description: string @param board_description: 보드에 대한 한줄 설명 @type heading_list: list<string> @param heading_list: 보드에 존재할 말머리 목록 (초기값 : [] 아무 말머리 없음) @type category_name: string @param category_name: 보드가 속하는 카테고리의 이름(초기값 : None 카테고리 없음) @type board_type: int @param board_type: 보드의 종류 (0 : 일반 게시판, 1 : 사진 게시판, 2 : 익명 게시판) @type to_read_level: int @param to_read_level: 게시판 글을 읽기위해 필요한 authentication_mode 레벨 (초기값: 3 포탈인증자 읽기 가능) @type to_write_level: int @param to_write_level: 게시판 글을 쓰기위해 필요한 authenticatino_mode 레벨 (초기값: 3 포탈인증자 쓰기 가능) @rtype: void @return: 1. 성공: void 2. 실패: 1. 로그인되지 않은 유저: 'NOT_LOGGEDIN' 2. 시샵이 아닌 경우: 'no permission' 3. 존재하는 게시판: 'board already exist' 4. 데이터베이스 오류: 'DATABASE_ERROR' ''' # TODO: 존재않는 Category 를 집어넣을 때에 대한 대처 # TODO: board_order 를 좀 더 깔끔하게 구하기 session = model.Session() board_order = self._get_last_board_order_until_category(category_name) + 1 # board order 와 같거나 뒤에 있던 모든 board 의 순서를 재조정한다. boards = session.query(model.Board).filter(model.Board.order != None).order_by(model.Board.order)[board_order - 1:] # TODO: for문을 돌리지 않고 query 한큐에 해결할 수는 없을까? for board in boards: board.order += 1 category = None if category_name != None: category = self._get_category_from_session(session, category_name) board_to_add = model.Board(smart_unicode(board_name), board_alias, board_description, board_order, category, board_type, to_read_level, to_write_level) try: session.add(board_to_add) # Board Heading 들도 추가한다. # TODO: heading 에 대한 중복 검사가 필요하다. (지금은 따로 없다) for heading in heading_list: board_heading = model.BoardHeading(board_to_add, smart_unicode(heading)) session.add(board_heading) session.commit() session.close() except IntegrityError: session.rollback() session.close() raise InvalidOperation('already added') self._clear_cache(board=True)
def test_smart_unicode(self): # ABC123가나다, 라는 문자열을 이용하여 검사 unicode_string = u'ABC123\uac00\ub098\ub2e4' cp949_string = 'ABC123\xb0\xa1\xb3\xaa\xb4\xd9' utf_8_string = 'ABC123\xea\xb0\x80\xeb\x82\x98\xeb\x8b\xa4' self.assertEqual(unicode_string, libs.smart_unicode(cp949_string)) self.assertEqual(unicode_string, libs.smart_unicode(utf_8_string)) self.assertEqual(unicode_string, libs.smart_unicode(unicode_string))
def edit_board(self, session_key, board_name, new_name, new_alias, new_description, new_category_name=None): ''' 보드의 이름과 설명을 변경한다. 이름이나 설명을 바꾸고 싶지 않으면 파라메터로 길이가 0 인 문자열을 주면 된다. @type session_key: string @param session_key: 사용자 Login Session (SYSOP) @type board_name: string @param board_name: 설명을 수정하고자 하는 Board Name @type new_name: string @param new_name: 보드에게 할당할 새 이름 (미변경시 '') @type new_alias: string @param new_alias: 보드에게 할당할 새 Alias (미변경시 '') @type new_description: string @param new_description: 보드에게 할당할 새 설명 (미변경시 '') @type new_category_name: string @param new_category_name: 보드에게 할당할 새 카테고리 (미변경시 값을 주지 않음. 초기값 None) @rtype: void @return: 1. 성공: 아무것도 리턴하지 않음 2. 실패: 1. 로그인되지 않은 유저: NotLoggedIn 2. 시샵이 아닌 경우: InvalidOperation('no permission') 3. 존재하지 않는 게시판: InvalidOperation('board does not exist') 4. 기타 오류 : 주석 추가해 주세요 ''' # XXX (2010.12.05) # Category 가 할당되어 있던 보드에 Category 를 지우려면 어째야 할까. # XXX end self._is_sysop(session_key) board_name = smart_unicode(board_name) new_name = smart_unicode(new_name) new_alias = smart_unicode(new_alias) new_description = smart_unicode(new_description) if new_category_name != None: # 파라메터로 주어지지 않았을 때 new_category_name = smart_unicode(new_category_name) # 변경이 필요한 항목에 대해서만 변경을 진행한다. session = model.Session() board = self._get_board_from_session(session, board_name) if new_name != u'': board.board_name = new_name if new_alias != u'': board.alias = new_alias if new_description != u'': board.board_description = new_description if new_category_name != None: board.category = self._get_category_from_session(session, new_category_name) try: session.commit() session.close() except IntegrityError: raise InvalidOperation("board already exist") # TODO :전체적인 Error 들 정리 ... except InvalidRequestError: raise InternalError() self._clear_cache(board=True)
def compare_password(self, password): ''' @type password: string @rtype: bool ''' hash_from_user = self.encrypt_password(password, self.password) hash_from_db = self.password hash_from_user = smart_unicode(hash_from_user.strip()) hash_from_db = smart_unicode(hash_from_db.strip()) return hash_from_user == hash_from_db
def __init__(self, link_name, link_description, link_url, order): ''' @type link_name: string @type link_description: string @type link_url: string @type order: int ''' self.link_name = smart_unicode(link_name) self.link_description = smart_unicode(link_description) self.link_url = smart_unicode(link_url) self.ishidden = False self.deleted = False self.order = order
def __init__(self, from_user, from_user_ip, to_user, message): ''' @type from_user: model.User @type from_user_ip: string @type to_user: model.User @type mesage: string ''' self.from_user = from_user self.from_user_ip = smart_unicode(from_user_ip) self.to_user = to_user self.sent_time = datetime.datetime.fromtimestamp(time.time()) self.message = smart_unicode(message) self.received_deleted = False self.sent_deleted = False self.read_status = u'N'
def __init__(self, board, heading): ''' @type board: model.Board @type heading: string ''' self.board = board self.heading = smart_unicode(heading)
def cancel_confirm(self, username): ''' 사용자의 이메일 인증을 해제하고 다른 사용자가 해당 이메일을 사용할 수 있도록 함 @type username: string @param username: 사용자의 User ID @rtype: None @return: None ''' username_ = smart_unicode(username) session = model.Session() user = self._get_user(session, username, 'user does not exist') if not user.activated: raise InvalidOperation('Not confirmed') key = (user.username + user.nickname + str(time.time())) activation_code = hashlib.md5(key).hexdigest() try: user_activation = model.UserActivation(user, activation_code) session.add(user_activation) user.activated = False user.email = u'' session.commit() except IntegrityError: session.rollback() session.close() raise InvalidOperation('already canceled') except: raise InternalError('database error')
def __init__(self, category_name, order): ''' @type category_name: string @type order: int ''' self.category_name = smart_unicode(category_name) self.order = order
def get_info(self, session_key): ''' 회원 정보 수정을 위해 현재 로그인된 회원 자신의 정보를 가져오는 함수. 다른 사용자의 정보를 열람하는 query와 다름. @type session_key: string @param session_key: 사용자 Login Session @rtype: ttypes.UserInformation @return: 1. 가져오기 성공: user_dic 2. 가져오기 실패: 1. 로그인되지 않은 유저: InvalidOperation('NOT_LOGGEDIN') 2. 존재하지 않는 회원: InvalidOperation('MEMBER_NOT_EXIST') 3. 데이터베이스 오류: InvalidOperation('DATABASE_ERROR') ''' session = model.Session() username = self.engine.login_manager.get_session(session_key).username username = smart_unicode(username) user = self._get_user(session, username, 'member does not exist') user_dict = filter_dict(user.__dict__, USER_PUBLIC_WHITELIST) if user_dict['last_logout_time']: user_dict['last_logout_time'] = datetime2timestamp( user_dict['last_logout_time']) else: user_dict['last_logout_time'] = 0 session.close() return UserInformation(**user_dict)
def _get_board(self, session, board_name): try: board = session.query(model.Board).filter_by(board_name=smart_unicode(board_name)).one() except InvalidRequestError: session.close() raise InvalidOperation("board does not exist") return board
def query_by_username(self, session_key, username): ''' username 기반 쿼리 함수. 다른 사용자의 정보를 알아내는 데 사용한다. @type session_key: string @param session_key: 사용자 Login Session @type username: string @param username: User ID to send Query @rtype: ttypes.PublicUserInformation @return: 1. 쿼리 성공: query_dic 2. 쿼리 실패: 1. 존재하지 않는 아이디: InvalidOperation('QUERY_ID_NOT_EXIST') 2. 로그인되지 않은 유저: InvalidOperation('NOT_LOGGEDIN') 3. 데이터베이스 오류: InvalidOperation('DATABASE_ERROR') ''' # TODO: Exception 내용 정정 username = smart_unicode(username) session = model.Session() query_user = self._get_user(session, username, 'Query username does not exist') query_user_dict = filter_dict(query_user.__dict__, USER_QUERY_WHITELIST) if query_user_dict['last_logout_time']: query_user_dict['last_logout_time'] = datetime2timestamp( query_user_dict['last_logout_time']) else: query_user_dict['last_logout_time'] = 0 session.close() return PublicUserInformation(**query_user_dict)
def modify_password_sysop(self, session_key, user_password_info): ''' 회원의 password를 시삽이 강제로 수정. @type session_key: string @param session_key: 사용자 Login Session (SYSOP) @type user_password_info: ttypes.UserPasswordInfo @param user_password_info: 사용자의 비밀번호 정보 @rtype: void @return: 1. modify 성공: void 2. modify 실패: 1. 로그인되지 않은 사용자: NotLoggedIn 2. 사용자가 존재하지 않을 경우: InvalidOperation('user does not exist') 3. 수정 권한 없음: InvalidOperation('no permission') 4. 데이터베이스 오류: InvalidOperation('DATABASE_ERROR') ''' # TODO: 쿼리 밖으로 빼기 # TODO: check_sysop 구현하여 그걸 쓰기 if not self.is_sysop(session_key): raise InvalidOperation('no permission') username = smart_unicode(user_password_info.username) session = model.Session() user = self._get_user(session, username, 'user does not exist') user.set_password(user_password_info.new_password) session.commit() self.logger.info(u"PASSWORD CHANGE:(username=%s)" % username) session.close()
def query_by_nick(self, session_key, nickname): ''' nickname 기반 쿼리 함수. 다른 사용자의 정보를 알아내는 데 사용한다. @type session_key: string @param session_key: 사용자 Login Session @type username: string @param nickname: User Nickname to send Query @rtype: ttypes.PublicUserInformation @return: 1. 쿼리 성공: query_dic 2. 쿼리 실패: 1. 존재하지 않는 닉네임: InvalidOperation('QUERY_NICK_NOT_EXIST' 2. 로그인되지 않은 유저: InvalidOperation('NOT_LOGGEDIN' 3. 데이터베이스 오류: InvalidOperation('DATABASE_ERROR' ''' # TODO: 쿼리 밖으로 빼기 nickname = smart_unicode(nickname) session = model.Session() try: query_user = session.query(model.User).filter_by( nickname=nickname).filter_by(deleted=False).one() query_user_dict = filter_dict(query_user.__dict__, USER_QUERY_WHITELIST) if query_user_dict['last_logout_time']: query_user_dict['last_logout_time'] = datetime2timestamp( query_user_dict['last_logout_time']) else: query_user_dict['last_logout_time'] = 0 session.close() return PublicUserInformation(**query_user_dict) except InvalidRequestError: session.close() raise InvalidOperation('query nickname does not exist')
def delete_blacklist(self, session_key, username): ''' 현재 로그인한 사용자가 차단 해제하고자 하는 사용자를 Blacklist 에서 제거한다. @type session_key: string @param session_key: 사용자 Login Session @type username: string @param username: 차단을 해제하고자 하는 사용자의 username @rtype: void @return: 1. 삭제 성공: void 2. 삭제 실패: 1. 블랙리스트에 존재하지 않는 아이디: InvalidOperation Exception 2. 로그인되지 않은 사용자: InvalidOperation Exception 3. 데이터베이스 오류: InternalError Exception ''' # TODO: user_id 를 파라메터로 하는 함수 분리 user_id = self.engine.login_manager.get_user_id(session_key) username = smart_unicode(username) session = model.Session() blacklisted_user = self.engine.member_manager._get_user(session, username) try: blacklist_to_del = session.query(model.Blacklist).filter_by(user_id=user_id, blacklisted_user_id=blacklisted_user.id).one() except InvalidRequestError: session.close() raise InvalidOperation('username not in blacklist') session.delete(blacklist_to_del) session.commit() session.close() return
def user_to_sysop(self, session_key, username): ''' user를 SYSOP으로 바꿔주는 함수 @type session_key: string @param session_key: 사용자 Login Session (must be SYSOP) @type username_string @param username: Username that will be SYSOP @return: 1. 성공했을 경우: void 2. 실패했을 경우: Invalid Operation ''' # TODO: 사용자 쿼리 밖으로 빼기 # TODO: sysop 인지 체크하는 거 밖으로 빼기 if not self.is_sysop(session_key): raise InvalidOperation('no permission') username = smart_unicode(username) session = model.Session() user = self._get_user(session, username, 'user does not exist') if user.is_sysop: session.close() raise InvalidOperation('already sysop..') user.is_sysop = True session.commit() session.close()
def get_user_reg_dic(cls, username, default_user_reg_dic=None): ''' 사용자 등록에 사용되는 User Registration Dictionary 를 생성한다. @type username: str @param username: 등록하고자 하는 사용자의 username @type default_user_reg_dic: dict @param default_user_reg_dic: 사용자 등록 시 지정할 값들 @rtype: dict @return: 해당 사용자에 대한 User Registration Dictionary ''' default_user_reg_dic = default_user_reg_dic or {} # Default User Registration Dictionary username = libs.smart_unicode(username) user_reg_dic = { 'username': username, 'password': username, 'nickname': username, 'email': username + u'@kaist.ac.kr', 'signature': username, 'self_introduction': username, 'default_language': u'english', 'campus': u'Daejeon' } # 파라메터로 지정된 값들은 덮어쓴다. for key in default_user_reg_dic: user_reg_dic[key] = default_user_reg_dic[key] return user_reg_dic
def delete_blacklist(self, session_key, username): ''' 현재 로그인한 사용자가 차단 해제하고자 하는 사용자를 Blacklist 에서 제거한다. @type session_key: string @param session_key: 사용자 Login Session @type username: string @param username: 차단을 해제하고자 하는 사용자의 username @rtype: void @return: 1. 삭제 성공: void 2. 삭제 실패: 1. 블랙리스트에 존재하지 않는 아이디: InvalidOperation Exception 2. 로그인되지 않은 사용자: InvalidOperation Exception 3. 데이터베이스 오류: InternalError Exception ''' # TODO: user_id 를 파라메터로 하는 함수 분리 user_id = self.engine.login_manager.get_user_id(session_key) username = smart_unicode(username) session = model.Session() blacklisted_user = self.engine.member_manager._get_user( session, username) try: blacklist_to_del = session.query(model.Blacklist).filter_by( user_id=user_id, blacklisted_user_id=blacklisted_user.id).one() except InvalidRequestError: session.close() raise InvalidOperation('username not in blacklist') session.delete(blacklist_to_del) session.commit() session.close() return
def _update_monitor_status(self, session_key, action): ''' 현재 사용자가 어떤 일을 하고있는지 update 하는 메소드. @type session_key: string @param session_key: 사용자 Login Session @type action: string @param action: 사용자가 취하고 있는 동작 @rtype: bool @return: 사용자가 로그인 중이면 True, 아니면 False ''' # TODO: 이 함수를 누가 호출하는지 보고, 왜 T/F 가 필요한지 확인하기 action = smart_unicode(action) try: if session_key in self.session_dic: # self.session_dic 구현에 상관없이 갱신된 값이 저장되도록 설정 user_session = self.session_dic[session_key] user_session['current_action'] = action self.session_dic[session_key] = user_session # last_action_time 갱신 self.update_session(session_key) return True else: return False except KeyError: return False
def delete_board(self, session_key, board_name): ''' 주어진 게시판을 삭제 처리한다. @type session_key : string @param session_key : 사용자 Login Session (SYSOP) @type category_name : string @param category_name : 삭제할 보드의 이름 ''' # TODO: hide 와 delete 의 차이는 ? self._is_sysop(session_key) session = model.Session() board_to_delete = self._get_board_from_session(session, smart_unicode(board_name)) board_order_to_delete = board_to_delete.order # 삭제할 게시판보다 뒤에 있는 게시판들의 order 를 하나씩 당겨 준다. if board_to_delete.order != None: boards = session.query(model.Board).filter(model.Board.order != None).order_by(model.Board.order)[board_order_to_delete:] for board in boards: board.order -= 1 board_to_delete.order = None board_to_delete.deleted = True session.commit() session.close() self._clear_cache(board=True)
def confirm(self, username_to_confirm, activation_code): ''' 인증코드(activation code) 확인. 예외상황: 1. 잘못된 인증코드 입력시: InvalidOperation('wrong activation code') @type username_to_confirm: string @param username_to_confirm: Confirm 하고자 하는 Username @type activation_code: string @param activation_code: Confirm Key ''' # TODO: user 쿼리하는 거 별도로 분리하기 username_to_confirm = smart_unicode(username_to_confirm) session = model.Session() user = self._get_user(session, username_to_confirm, 'user does not exist') try: user_activation = session.query(model.UserActivation).filter_by(user_id=user.id).one() except InvalidRequestError: if user.activated == True: session.close() raise InvalidOperation('already confirmed') else: session.close() raise InternalError('database error') if user_activation.activation_code == activation_code: user_activation.user.activated = True session.delete(user_activation) session.commit() session.close() return else: session.close() raise InvalidOperation('wrong confirm key')
def _add_category(self, category_name): ''' 카테고리를 실제로 추가한다. Internal use only. @type category_name: string @param category_name: name of category @rtype: void @return: 1.성공 : 없음 2.오류가 있을 경우 InvalidOperation ''' # TODO: category_name 에 공백 문자 금지 # TODO: 좀더 다양한 예외상황에 대한 처리 session = model.Session() category_order = len(self.get_category_list()) + 1 category_to_add = model.Category(smart_unicode(category_name), category_order) try: session.add(category_to_add) session.commit() session.close() except IntegrityError: session.rollback() session.close() raise InvalidOperation('already added') self._clear_cache(category=True)
def _get_board(self, session, board_name): try: board = session.query(model.Board).filter_by( board_name=smart_unicode(board_name)).one() except InvalidRequestError: session.close() raise InvalidOperation("board does not exist") return board
def __init__(self, user, activation_code): ''' @type user: model.User @type activation_code: string ''' self.user = user self.activation_code = smart_unicode(activation_code) self.issued_date = datetime.datetime.fromtimestamp(time.time())
def __init__(self, filename, saved_filename, filepath, user, board, article): ''' @type filename: string @type saved_filename: string @type filepath: string @type user: model.User @type board: model.Board @type article: model.Article ''' # TODO: 왜 이렇게 많은 정보가 필요하지? self.filename = smart_unicode(filename) self.saved_filename = smart_unicode(saved_filename) self.filepath= filepath self.user = user self.board = board self.article = article self.deleted = False
def __init__(self, username, password, nickname, email, signature, self_introduction, default_language, campus): ''' @type username: string @type password: string @type nickname: string @type email: string @type signature: string @type self_introduction: string @type default_language: string @type capus: string ''' self.username = smart_unicode(username) self.set_password(password) self.nickname = smart_unicode(nickname) self.email = smart_unicode(email) self.signature = smart_unicode(signature) self.self_introduction = smart_unicode(self_introduction) self.default_language = smart_unicode(default_language) self.campus = smart_unicode(campus) self.activated = False self.widget = 0 self.layout = 0 self.join_time = datetime.datetime.fromtimestamp(time.time()) self.last_login_time = None self.last_logout_time = None self.last_login_ip = u'' self.is_sysop = False self.authentication_mode = 0 self.listing_mode = 0 self.activated_backup = False self.deleted = False
def __init__(self, filename, saved_filename, filepath, user, board, article): ''' @type filename: string @type saved_filename: string @type filepath: string @type user: model.User @type board: model.Board @type article: model.Article ''' # TODO: 왜 이렇게 많은 정보가 필요하지? self.filename = smart_unicode(filename) self.saved_filename = smart_unicode(saved_filename) self.filepath = filepath self.user = user self.board = board self.article = article self.deleted = False
def get_board(self, board_name): ''' 보드 하나에 대한 자세한 정보를 얻는다. @type board_name: string @param board_name: 찾고자 하는 board 의 이름 @rtype: ttypes.Board ''' return self._get_board(smart_unicode(board_name))
def register_(self, user_reg_info): ''' DB에 회원 정보 추가. activation code를 발급한다. 예외상황: 1. 시샵이 아이디인 경우: InvalidOperation('permission denied') 2. 이미 가입한 사용자의 경우: InvalidOperation('already added') 3. 데이터베이스 오류: InternalError('database error') @type user_reg_info: ttypes.UserRegistration @param user_reg_info: 사용자의 회원가입 정보를 담은 객체 @rtype: string @return: 사용자 인증코드 ''' # TODO: 한글 아이디 허용 # Smart Unicode 적용 for keys in USER_PUBLIC_KEYS: user_reg_info.__dict__[keys] = smart_unicode(user_reg_info.__dict__[keys]) # Check if username is proper if user_reg_info.username.lower() == etc.arara_settings.SYSOP_INITIAL_USERNAME.lower(): raise InvalidOperation('permission denied') if not PROPER_USERNAME_REGEX.match(user_reg_info.username): raise InvalidOperation('username not permitted') if not PROPER_EMAIL_REGEX.match(user_reg_info.email): raise InvalidOperation('emai other than @KAIST not permitted') key = (user_reg_info.username + user_reg_info.password + user_reg_info.nickname) activation_code = hashlib.md5(key).hexdigest() session = model.Session() try: # Register user to db user = model.User(**user_reg_info.__dict__) session.add(user) # Register activate code to db user_activation = model.UserActivation(user, activation_code) session.add(user_activation) session.commit() except IntegrityError: session.rollback() session.close() raise InvalidOperation('already added') except InvalidRequestError: session.rollback() session.close() raise InternalError('database error') # If everything is clear, send validation mail to user. self._send_activation_code(user.email, user.username, user_activation.activation_code) # pipoket: SECURITY ISSUE! PASSWORD SHOULD NOT BE LOGGED! # This logging function will log necessary information but NOT PASSWORD. self.logger.info(u"USER REGISTRATION:(username=%s, nickname=%s, email=%s)" % (user_reg_info.username, user_reg_info.nickname, user_reg_info.email)) session.close() return activation_code
def change_board_order(self, session_key, board_name, new_order): """ 보드의 순서를 바꾼다. 카테고리의 범위를 넘어서지 않는 선에서. @type session_key: string @param session_key: 사용자 Login Session (SYSOP) @type board_name: string @param board_name: 순서를 변경할 보드의 이름 @type new_order: int @param new_order: 보드가 표시될 순서 @rtype: void @return: 1. 성공: None 2. 실패: 1. 로그인되지 않은 유저: 'NOT_LOGGEDIN' 2. 시삽이 아닌 경우: 'no permission' 3. 존재하지 않는 게시판: 'board does not exist' 4. 순서를 지정할 수 없는 게시판: 'invalid board' 5. 잘못된 순서(범위 초과): 'invalid order' 6. 데이터베이스 오류: 'DATABASE_ERROR' """ self._is_sysop(session_key) session = model.Session() board_name = smart_unicode(board_name) current_board = self._get_board_from_session(session, board_name) if current_board.order == None: session.close() raise InvalidOperation('invalid board') board_list = session.query(model.Board).filter_by(category=current_board.category).filter(model.Board.order != None).order_by(model.Board.order).all() if not board_list[0].order <= new_order <= board_list[-1].order: session.close() raise InvalidOperation('invalid order') if new_order < current_board.order: for board in board_list: if new_order <= board.order < current_board.order: board.order += 1 elif new_order > current_board.order: for board in board_list: if current_board.order < board.order <= new_order: board.order -= 1 #현재 보드의 order를 new_order로 변경한다. current_board.order = new_order try: session.commit() except InvalidRequestError: # TODO: 이게 날 가능성이 있는지 고민해보자 session.close() raise InternalError("DATABASE ERROR") session.close() self._clear_cache(board=True)
def __init__(self, content, weight, due_date): ''' @type content: string @type weight: int @type due_date: datetime ''' self.content = smart_unicode(content) self.valid = True self.weight = weight self.issued_date = datetime.datetime.fromtimestamp(time.time()) self.due_date = due_date
def authenticate(self, username, password, user_ip): ''' 사용자가 입력한 password 로 검사한다. @type username: string @param username: 사용자의 id @type password: string @param password: 사용자의 비밀번호 @type user_ip: string @param user_ip: 사용자의 IP 주소 ''' # TODO: user 쿼리 밖으로 빼기 # TODO: ret 딕셔너리 만드는 코드 다듬기 # TODO: 궁극적으로 비밀번호 저장방식 바꾸기 username = smart_unicode(username) if username.strip() == u"" or username == u" ": raise InvalidOperation('wrong username') session = model.Session() user = self._get_user(session, username, 'wrong username') try: if user.compare_password(password): if user.activated: current_time = time.time() user.last_login_time = datetime.datetime.fromtimestamp( current_time) user.last_login_ip = unicode(user_ip) ret = { 'last_login_time': current_time, 'nickname': user.nickname, 'id': user.id } if user.lost_password_token: for tok in user.lost_password_token: session.delete(tok) session.commit() session.close() return AuthenticationInfo(**ret) else: session.close() raise InvalidOperation(u'not activated\n%s\n%s' % (user.username, user.nickname)) else: session.close() raise InvalidOperation('wrong password') except InvalidOperation: raise except Exception, e: self.logger.warning( "Exception occur on member_manager.authenticate. username <%s> and Error <%s>" % (username, repr(e))) raise InvalidOperation( "unexpected error on authentication, contact SYSOP")
def search_user(self, session_key, search_user, search_key=None): ''' 찾고자 하는 username와 nickname에 해당하는 user를 찾아주는 함수 search_key 가 username 또는 nickname 으로 주어질 경우 해당하는 search key로만 찾는다 (주어지지 않으면 두 방향 모두에 대하여 찾는다) @type session_key: string @param session_key: 사용자 Login Session @type search_user: string @param search_user: User Info(username or nickname) @type search_key: string @param search_key: Search key @rtype: list<ttypes.SearchUserResult> @return: 1. 성공시: True, {'username':'******','nickname':'mikkang'} 2. 실패시: 1. 존재하지 않는 사용자: InvalidOperation('NOT_EXIST_USER' 2. 잘못된 검색 키:InvalidOperation('INCORRECT_SEARCH_KEY') ''' # TODO: session_key 를 이용한 Login check # TODO: 쿼리 직접 쓰지 말고 나머지 두 함수 합쳐서 할 것 # TODO: SearchUserResult 는 뭐고 PublicUserInformation 는 뭔가? search_user = smart_unicode(search_user) session = model.Session() try: if not search_key: user = session.query(model.User).filter( or_(model.User.username == search_user, model.User.nickname == search_user)).filter_by( deleted=False).all() else: if search_key.lower() == u'username': user = session.query(model.User).filter_by( username=search_user).filter_by(deleted=False).all() elif search_key.lower() == u'nickname': user = session.query(model.User).filter_by( nickname=search_user).filter_by(deleted=False).all() else: session.close() raise InvalidOperation('incorrect search key') user_dict_list = self._get_dict_list(user, USER_SEARCH_WHITELIST) user_list = [SearchUserResult(**x) for x in user_dict_list] session.close() return user_list except InvalidRequestError: session.close() raise InvalidOperation('user does not exist') except AssertionError: session.close() raise InvalidOperation('invalid key')
def add_blacklist(self, session_key, username, block_article=True, block_message=True): ''' 현재 로그인한 사용자가 차단하고자 하는 새로운 사용자를 Blacklist 에 추가한다. @type session_key: string @param session_key: 사용자 Login Session @type username: string @param username: 차단하고자 하는 사용자의 username @type block_article: bool @param block_article: 해당 사용자의 글을 읽지 않을 것인지의 여부 @type block_message: bool @param block_message: 해당 사용자의 메시지를 받지 않을 것인지의 여부 @rtype: void @return: 1. 추가 성공: void 2. 추가 실패: 1. Wrong Dictionary: InvalidOperation Exception 2. 존재하지 않는 아이디: InvalidOperation Exception 3. 자기 자신은 등록 불가: InvalidOperation Exception 4. 이미 추가되어있는 아이디: InvalidOperation Exception 5. 로그인되지 않은 사용자: NotLoggedIn Exception 6. 데이터베이스 오류: InternalError Exception ''' # TODO: 시삽을 차단하게 허용할 것인가? # TODO: block_article, block_message 가 모두 False 라면? # TODO: user_id 를 파라메터로 하는 함수 분리 user_info = self.engine.login_manager.get_session(session_key) username = smart_unicode(username) if username == user_info.username: raise InvalidOperation('cannot add yourself') session = model.Session() user = self.engine.member_manager._get_user(session, user_info.username) target_user = self.engine.member_manager._get_user(session, username) integrity_chk = session.query(model.Blacklist).filter_by( user_id=user.id, blacklisted_user_id=target_user.id).all() if integrity_chk: session.close() raise InvalidOperation('already added') new_blacklist = model.Blacklist(user, target_user, block_article, block_message) session.add(new_blacklist) session.commit() session.close() return
def modify_password(self, session_key, user_password_info): ''' 회원의 password를 수정. ---user_password_info {username, current_password, new_password} @type session_key: string @param session_key: 사용자 Login Session @type user_password_info: ttypes.UserPasswordInfo @param user_password_info: 사용자의 비밀번호 정보 @rtype: void @return: 1. modify 성공: void 2. modify 실패: 1. 수정 권한 없음: 'NO_PERMISSION' 2. 잘못된 현재 패스워드: 'WRONG_PASSWORD' 3. 로그인되지 않은 유저: InvalidOperation('NOT_LOGGEDIN') 4. 데이터베이스 오류: InvalidOperation('DATABASE_ERROR') ''' # TODO: 쿼리 바깥으로 빼기 # TODO: 비밀번호 암호화하여 전달하기 session_info = self.engine.login_manager.get_session(session_key) username = smart_unicode(session_info.username) session = model.Session() user = self._get_user(session, username) try: if not username == user_password_info.username: raise NoPermission() if not user.compare_password(user_password_info.current_password): raise WrongPassword() user.set_password(user_password_info.new_password) session.commit() # pipoket: SECURITY ISSUE! PASSWORD SHOULD NOT BE LOGGED! # This logging function will log necessary information but NOT PASSWORD. self.logger.info(u"PASSWORD CHANGE:(username=%s)" % username) session.close() return except NoPermission: session.close() raise InvalidOperation('no permission') except WrongPassword: session.close() raise InvalidOperation('wrong password') except KeyError: session.close() raise NotLoggedIn()
def modify_user(self, session_key, user_modification): ''' password를 제외한 회원 정보 수정 @type session_key: string @param session_key: 사용자 Login Session @type user_reg_infot: ttypes.UserModification @param user_reg_infot: 변경할 사용자 정보 @rtype: void @return: 1. modify 성공: void 2. modify 실패: 1. 로그인되지 않은 유저: InvalidOperation('NOT_LOGGEDIN' 2. 데이터베이스 오류: InvalidOperation('DATABASE_ERROR' 3. 양식이 맞지 않음(부적절한 NULL값 등): 'WRONG_DICTIONARY' ''' session_info = self.engine.login_manager.get_session(session_key) username = smart_unicode(session_info.username) if not is_keys_in_dict(user_modification.__dict__, USER_PUBLIC_MODIFIABLE_WHITELIST): raise InvalidOperation('wrong input') session = model.Session() user = self._get_user(session, username) for key, value in user_modification.__dict__.items(): # 문자열에 한하여 smart_unicode 로 변환하여 저장한다 if type(value) in [str, unicode]: setattr(user, key, smart_unicode(value)) else: setattr(user, key, value) session.commit() session.close() # Member Manager Cache ara_memcached.clear_memcached(self.get_listing_mode, session_info.id)
def remove_user(self, session_key): ''' session key로 로그인된 사용자를 등록된 사용자에서 제거하고, Primary Key Violation 방지와 재가입 꼼수 방지를 위해 적절한 placeholder를 같은 primary key와 같은 ID, email로서 배치한다. @type session_key: string @param session_key: 사용자 Login Session @rtype: void @return: 1. 성공시: void 2. 실패시: NotLoggedIn ''' session = model.Session() username = smart_unicode( self.engine.login_manager.get_session(session_key).username) try: user = session.query(model.User).filter_by(username=username).one() # Create placeholder user.password = u'youcannotlogin' user.nickname = u'탈퇴회원' user.signature = u'' user.self_introduction = u'' user.deleted = True # Clean-Up almost everythings session.query( model.UserActivation).filter_by(user_id=user.id).delete() session.query( model.BBSManager).filter_by(manager_id=user.id).delete() session.query( model.ScrapStatus).filter_by(user_id=user.id).delete() session.query(model.Blacklist).filter( or_(model.Blacklist.user_id == user.id, model.Blacklist.blacklisted_user_id == user.id)).delete() session.query( model.SelectedBoards).filter_by(user_id=user.id).delete() session.query( model.LostPasswordToken).filter_by(user_id=user.id).delete() session.commit() session.close() return except KeyError: session.close() raise NotLoggedIn()
def _get_user_by_nickname(self, session, nickname): ''' @type session: model.Session @param session: 사용중인 SQLAlchemy Session @type nickname: string @param nickname: 얻고자 하는 사용자의 nickname @rtype: model.User @return: 해당되는 사용자의 객체 ''' # TODO: member_manager 로 옮기기 try: user = session.query(model.User).filter_by(nickname=smart_unicode(nickname)).one() except InvalidRequestError: session.close() raise InvalidOperation('nickname not found') return user