def test_send_password_recovery_email(self): self.register_user(u'panda') # 정상적인 상황 mail_count = len(smtplib.SMTP.mail_list) self.engine.member_manager.send_password_recovery_email(u'panda', u'*****@*****.**') self.assertEqual(1, len(smtplib.SMTP.mail_list) - mail_count) mail_count = len(smtplib.SMTP.mail_list) from_addr, to_addrs, msg = smtplib.SMTP.mail_list[-1] msg = email.message_from_string(msg).get_payload(decode=True).decode('utf8') session = model.Session() user = self.engine.member_manager._get_user(session, 'panda') codes = user.lost_password_token self.assertEqual(1, len(codes)) session.close() if not codes[0].code in msg: self.fail("Recovery code is not in the mail content.") # 등록되지 않은 유저일때 try: self.engine.member_manager.send_password_recovery_email(u'hodduc', u'*****@*****.**') self.fail("Sent password recovery email for non-existing user.") except InvalidOperation: pass # 유저는 맞으나 이메일이 다를때 try: self.engine.member_manager.send_password_recovery_email(u'panda', u'*****@*****.**') self.fail("Sent password recoveryt email for wrong email address.") except InvalidOperation: pass # 다시 보내면 다른 코드로 갱신되어야 함 self.engine.member_manager.send_password_recovery_email(u'panda', u'*****@*****.**') self.assertEqual(1, len(smtplib.SMTP.mail_list) - mail_count) from_addr, to_addrs, new_msg = smtplib.SMTP.mail_list[-1] new_msg = email.message_from_string(new_msg).get_payload(decode=True).decode('utf8') self.assertNotEqual(new_msg, msg) session = model.Session() user = self.engine.member_manager._get_user(session, 'panda') new_codes = user.lost_password_token self.assertEqual(1, len(new_codes)) session.close() if codes[0].code in new_msg: self.fail("Recovery code is not flushed.") if not new_codes[0].code in new_msg: self.fail("Recovery code is not in the mail content.")
def get_activated_users(self, session_key, limit=-1): ''' 전체 사용자들 중 사용자 인증이 된 사용자들의 목록을 돌려준다. SYSOP 만 사용 가능. @type session_key: string @param session_key: 사용자 Login Session @type limit: int @param limit: 최대 몇 명의 사용자를 돌려줄 것인가. -1 일 때는 모든 사용자 @rtype: list<arara_thrift.SearchUserResult> @return: 사용자 인증이 된 사용자들의 목록 ''' if not self.is_sysop(session_key): raise InvalidOperation('not sysop') session = model.Session() query = session.query(model.User).filter_by(activated=True) users = query.all() # 갯수 제한 설정 if limit > len(users): limit = len(users) result = [None] * limit for idx, user in enumerate(users): if limit == idx: # limit == -1 이면 절대 여기 걸리지 않는다 break # 한편 그 외의 경우엔 limit 갯수만큼만 통과 result[idx] = SearchUserResult( **self._get_dict(user, USER_SEARCH_WHITELIST)) session.close() return result
def change_listing_mode(self, session_key, listing_mode): ''' 로그인한 user의 listing mode (글 목록 정렬 방식) 를 변경한다. @type session_key: string @param session_key: 사용자 Login Session (must be SYSOP) @type listing_mode: int @param listing_mode: 글 목록 정렬 방식 (ArticleManager 참고) @return: 1. 성공했을 경우: void 2. 실패했을 경우 : Invalid Operation ''' if listing_mode < 0 or 1 < listing_mode: raise InvalidOperation('wrong listing mode') session = model.Session() user = self._get_user_by_session(session, session_key) user_id = user.id try: user.listing_mode = listing_mode session.commit() session.close() except InvalidRequestError: session.close() raise InvalidOperation('database error') # Cache update ara_memcached.clear_memcached(self.get_listing_mode, user_id)
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 send_id_recovery_email(self, email): ''' ID를 잃어버렸을 때, e-mail 기반으로 id를 찾아서 그 이메일로 id를 전송해주는 함수. 성공할 경우 True, 실패할 경우 False를 반환한다. @type email: string @param email: 이메일 주소 @rtype: bool @return: 1. 성공 시 : True 2. 실패 시 : False ''' session = model.Session() query = session.query(model.User).filter_by(email=email) try: user = query.one() session.close() except NoResultFound: session.close() return False title = arara_settings.MAIL_TITLE['id_recovery'] content = arara_settings.MAIL_CONTENT['id_recovery'] content += ' Here is your ARA account username which is associated with %s <br /><br /> ' % email content += ' Your ID : %s <br /><br />' % user.username content += ' Please visit http://' + arara_settings.WARARA_SERVER_ADDRESS + '<br /><br />' content += ' This is post-only mailing. <br /> Thanks. ' send_mail(title, email, content) return True
def get_welcome(self): ''' welcome 가져오는 함수 >>> notice.get_welcome() '<html> .... ' @rtype: string @return: 1. welcome 있을 때: 랜덤하게 선택된 welcome(html) 2. welcome 없을 때: InvalidOperation Exception ''' session = model.Session() available_welcome = session.query( model.Welcome).filter_by(valid=True).all() available_welcome_dict_list = self._get_dict_list( available_welcome, NOTICE_PUBLIC_WHITELIST) if available_welcome_dict_list: weight_welcome = [] for index in range(len(available_welcome_dict_list)): for weight in range(available_welcome_dict_list[index].weight): weight_welcome.append(index) n = random.choice(weight_welcome) session.close() return available_welcome_dict_list[n].content else: session.close() raise InvalidOperation('no welcome')
def set_selected_boards(self, session_key, board_ids): ''' boards_id로 주어진 게시판들을 주어진 사용자의 즐겨찾는 게시판으로 설정한다 @type session_key: string @param session_key: 사용자 Login Session @type board_ids: list<int> @param board_ids: 게시판들의 아이디 목록 @rtype: void @return: None ''' session = model.Session() user = self._get_user_by_session(session, session_key) if len(board_ids) > 3: session.close() raise InvalidOperation("Please check 3 boards at most") try: boards = [ session.query(model.Board).filter_by(id=x).one() for x in board_ids ] except NoResultFound, MultipleResultsFound: session.close() raise InvalidOperation("Not a valid board id")
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 list_welcome(self, session_key): ''' 관리자용 welcome 페이지 목록을 가져오는 함수 >>> notice.list_welcome(SYSOP_session_key) [{'no': 32, 'content': '신입회원을 모집합니다','availability': 'True'}, {'no': 33', content': '환영합니다','availability': 'False'} @rtype: list @return: 1. welcome 페이지가 있을 때: True, welcome 페이지들의 목록(text) 2. welcome 페이지가 없을 때: 1. welcome 없을때 : False, 'NO_WELCOME' 2. 데이터베이스 오류: False, 'DATABASE_ERROR' 3. 시삽이 아닐 때: False, 'NOT_SYSOP' ''' if not self.engine.member_manager.is_sysop(session_key): raise InvalidOperation('not sysop') session = model.Session() welcome = session.query(model.Welcome).all() welcome_dict_list = self._get_dict_list(welcome, NOTICE_PUBLIC_WHITELIST) if welcome_dict_list: session.close() return welcome_dict_list else: session.close() raise InvalidOperation('no welcome')
def delete_file(self, session_key, article_id, file_id): ''' 지울 파일이 저장된 장소와 저장된 파일명을 리턴해주는 함수 @type session_key: string @param session_key: 사용자 Login Session @type article_id: int @param article_id: Article Number @type file_id: int @param file_id: File 번호 @rtype: ttypes.FileInfo @return: 1. 성공: {'file_path': 'blah/blah', 'saved_filename': 'blah'} 2. 실패: 1. 로그인되지 않은 유저: False, 'NOT_LOGGEDIN' 2. 데이터베이스 오류: False, 'DATABASE_ERROR' ''' # TODO: download_file함수와 유사하다.. 똑같은 코드가 많다.. 먼가 비효율적이다.. 나중에 하나로 좀 해보자.. 일단 지금은 급하니까.. 복사해놓고... #ret, filepath_to_delete= self.download_file(session_key, article_id, filename) session = model.Session() article = self._get_article(session, article_id) file = self._get_file(session, file_id, article) file.deleted = True download_path = file.filepath ghost_filename = file.saved_filename session.commit() session.close() return FileInfo(download_path, ghost_filename)
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 get_blacklist(self, session_key): ''' 로그인한 사용자의 블랙리스트 목록을 돌려준다. @type session_key: string @param session_key: 사용자 Login Session @rtype: list<ttypes.BlacklistInformation> @return: 1. 성공: BlacklistInformation 의 List 2. 실패: 1. 로그인되지 않은 사용자:InvalidOperation 'NOT_LOGGEDIN' 2. 데이터베이스 오류: InternalError 'DATABASE_ERROR' ''' # TODO: user_id 를 파라메터로 하는 함수 분리 user_id = self.engine.login_manager.get_user_id(session_key) try: session = model.Session() blacklist_list = session.query( model.Blacklist).filter_by(user_id=user_id).all() session.close() blacklist_list = self._get_dict_list(blacklist_list, BLACKLIST_LIST_DICT) except: session.close() raise InternalError('database error') return blacklist_list
def read_sent_message(self, session_key, msg_no): ''' 쪽지 하나 읽어오기 @type session_key: string @param session_key: 사용자 Login Session @type msg_no: int @param msg_no: Message Number @rtype: dictionary @return: 1. 읽어오기 성공: Message 2. 읽어오기 실패: 1. 메세지가 존재하지 않음: InvalidOperation Exception 2. 로그인되지 않은 사용자: NotLoggedIn Exception 3. 데이터베이스 오류: InternalError Exception ''' # TODO: 쿼리 부분 분리하여 좀더 함수 조립식으로 만들기 user_info = self.engine.login_manager.get_session(session_key) session = model.Session() from_user = self.engine.member_manager._get_user(session, user_info.username) try: message = session.query(model.Message).filter(and_(model.Message.from_id==from_user.id, model.Message.id==msg_no, not_(model.Message.sent_deleted==True))).one() except InvalidRequestError: session.close() raise InvalidOperation('message not exist') message_dict = self._get_dict(message, MESSAGE_WHITELIST) message.read_status = u'R' session.commit() session.close() return Message(**message_dict)
def test_cleanup_expired_sessions(self): # 테스트 상황 설계 # 1) 2명의 사용자 모두 ReadStatus 가 로드되어 있음 # 2) 이중 1명만 Session 이 Expire 되어야 함 session_key_panda = self.register_and_login(u'panda') # user 2 session_key_sillo = self.register_and_login(u'sillo') # user 3 self.engine.read_status_manager._initialize_data(2) self.engine.read_status_manager._initialize_data(3) time.time.elapse(SESSION_EXPIRE_TIME + 1.0) self.engine.login_manager.update_session(session_key_sillo) self.engine.login_manager.cleanup_expired_sessions() # LoginManager self.assertEqual( { session_key_sillo: { 'username': u'sillo', 'current_action': 'login_manager.login()', 'ip': u'127.0.0.1', 'logintime': 1.1000000000000001, 'last_action_time': 3612.0999999999999, 'nickname': u'sillo', 'id': 3 } }, self.engine.login_manager.session_dic) # MemberManager expect = datetime.datetime.fromtimestamp(1.1 + SESSION_EXPIRE_TIME + 1) result = model.Session().query(model.User).filter_by(id=2).one() self.assertEqual(expect, result.last_logout_time) # ReadStatusManager self.assertEqual([3], self.engine.read_status_manager.read_status.keys()) self.assertEqual([(0, 'N')], self.engine.read_status_manager.read_status[3].data)
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 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 get_banner(self): ''' 배너를 가져오는 함수 >>> notice.get_banner() '<html> .... ' @rtype: string @return: 1. 배너가 있을 때: 랜덤하게 선택된 배너(html) 2. 배너가 없을 때: InvalidOperation Exception ''' session = model.Session() available_banner = session.query( model.Banner).filter_by(valid=True).all() available_banner_dict_list = self._get_dict_list( available_banner, NOTICE_PUBLIC_WHITELIST) if available_banner_dict_list: weight_banner = [] for index in range(len(available_banner_dict_list)): for weight in range(available_banner_dict_list[index].weight): weight_banner.append(index) n = random.choice(weight_banner) session.close() return available_banner_dict_list[n].content else: session.close() raise InvalidOperation('no banner')
def _register_without_confirm(self, user_reg_dic, is_sysop): ''' confirm 과정 없이 사용자를 활성화된 상태로 등록하는 함수 @type user_reg_dic: dict('username', 'password', 'nickname', 'email', 'signature', 'self_introduction', 'default_language', 'campus') @param user_reg_dic: User Information @type is_sysop: bool @param is_sysop: 유저가 시삽권한을 가질지를 결정 @rtype: void @return: 1. 사용자 등록이 성공했을 경우 : void 2. 사용자 등록이 실패했을 경우 : Invalid Operation ''' # TODO: 예외 상황이 여러 가지가 있을 수 있다. DB 자체 에러, 이미 등록된 유저 등. 나누어야 한다. try: user = model.User(**user_reg_dic) session = model.Session() session.add(user) user.activated = True user.is_sysop = is_sysop session.commit() session.close() except: session.rollback() session.close() import traceback self.logger.exception("Special Exception : \n%s", traceback.format_exc()) raise InvalidOperation('Cannot add users without confirm')
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 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 download_file(self, article_id, file_id): ''' article의 파일을 다운로드 할때 실제로 파일이 저장된 장소와 저장된 파일명을 리턴해주는 함수 @type article_id: int @param article_id: Article Number @type file_id: int @param file_id: 다운로드하려는 파일의 번호 @rtype: ttypes.DownloadFileInfo @return: 1. 경로 찾기 성공: {'file_path': blah, 'saved_filename': blah, 'real_filename': blah} 2. 경로 찾기 실패: 1. 로그인되지 않은 유저: NotLoggedIn Exception 2. 데이터베이스 오류: InternalError Exception ''' # TODO: 아래 commit 이 왜 필요한지 알아보기 session = model.Session() article = self._get_article(session, article_id) file = self._get_file(session, file_id, article) download_path = file.filepath ghost_filename = file.saved_filename real_filename = file.filename session.commit() session.close() return DownloadFileInfo(download_path, ghost_filename, real_filename)
def send_message_by_nickname(self, session_key, to_nickname, msg): ''' 해당 하는 nickname을 갖는 사용자에게 쪽지를 전송하는 함수 @type session_key: string @param session_key: 사용자 Login Session @type to_nickname: string @param to_nickname: Destination nickname @type msg: string @param msg: Message string @rtype: void @return: 1. 메세지 전송 성공: void 2. 메세지 전송 실패: 1. 보낼 아이디가 존재하지 않음: InvalidOperation Exception 2. 로그인되지 않은 사용자: NotLoggedIn Exception 3. 데이터베이스 오류: InternalError Exception ''' user_info = self.engine.login_manager.get_session(session_key) session = model.Session() to_user = self._get_user_by_nickname(session, to_nickname) from_user = self.engine.member_manager._get_user(session, user_info.username) from_user_ip = user_info.ip message = model.Message(from_user, from_user_ip, to_user, msg) try: session.add(message) session.commit() except InvalidRequestError: session.close() raise InternalError('database error') session.close()
def receive_list(self, session_key, page=1, page_length=20): ''' @type session_key: string @param session_key: 사용자 Login Session @type page: int @param page: Page Number @type page_length: int @param page_length: Number of Messages to get in one page @rtype: ttypes.MessageList @return: 1. 리스트 읽어오기 성공: MessageList 2. 리스트 읽어오기 실패: 1. 로그인되지 않은 사용자: NotLoggedIn Exception 2. 데이터베이스 오류: InternalError Exception ''' # TODO: ArticleManager 참고하여 싹 뜯어고치기 # TODO: page 관련 정보 처리하는거 ArticleManager 에서 아예 util 로 옮기기 ret_dict = {} user_info = self.engine.login_manager.get_session(session_key) session = model.Session() to_user = self.engine.member_manager._get_user(session, user_info.username) blacklist_dict_list = self.engine.blacklist_manager.get_blacklist(session_key) blacklist_users = set() for blacklist_item in blacklist_dict_list: if blacklist_item.block_message: blacklist_users.add(blacklist_item.blacklisted_user_username) received_messages_count = session.query(model.Message).filter( and_(model.Message.to_id==to_user.id, not_(model.Message.received_deleted==True) )).count() received_new_messages_count = session.query(model.Message).filter( and_(model.Message.to_id==to_user.id, model.Message.read_status==u'N', not_(model.Message.received_deleted==True) )).count() last_page = int(received_messages_count / page_length) page = int(page) if received_messages_count % page_length != 0: last_page += 1 elif received_messages_count == 0: last_page += 1 if page > last_page: session.close() raise InvalidOperation('wrong pagenum') offset = page_length * (page - 1) last = offset + page_length received_messages = session.query(model.Message).filter( and_(model.Message.to_id==to_user.id, not_(model.Message.received_deleted==True) )).order_by(model.Message.id.desc())[offset:last] received_messages_dict_list = self._get_dict_list(received_messages, MESSAGE_WHITELIST, blacklist_users) ret_dict['hit'] = received_messages_dict_list ret_dict['last_page'] = last_page ret_dict['new_message_count'] = received_new_messages_count ret_dict['results'] = received_messages_count session.close() return MessageList(**ret_dict)
def __contains__(self, key): session = model.Session() try: login_session = session.query(model.LoginSession).filter_by(session_key=key).one() session.close() return True except NoResultFound: session.close() return False
def __getitem__(self, key): session = model.Session() try: login_session = session.query(model.LoginSession).filter_by(session_key=key).one() session.close() return login_session.session_data except NoResultFound: session.close() raise KeyError()
def __setitem__(self, key, value): session = model.Session() try: # 로그인되어 있는 사용자의 경우 DB의 해당 row에 새로운 값을 기록한다 login_session = session.query(model.LoginSession).filter_by(session_key=key).one() login_session.session_data = value except NoResultFound: # 로그인되어 있지 않은 사용자의 경우 DB에 새로운 row를 생성한다 login_session = model.LoginSession(key, value, datetime.datetime.now()) session.add(login_session) session.commit() session.close()
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 test_update_last_logout_time(self): # 2명의 사용자를 등록한다 self.register_user(u'panda') # user 2 self.register_user(u'bbashong') # user 3 # 시삽과 이 2명의 사용자의 로그아웃 시간을 업데이트한다 self.engine.member_manager.update_last_logout_time([1, 2, 3]) # 사용자들의 로그아웃 시간이 잘 업데이트되었는지 확인 time_1 = datetime.datetime.fromtimestamp(time.time()) users = model.Session().query(model.User).order_by(model.User.id.asc()).all() self.assertEqual(time_1, users[0].last_logout_time) self.assertEqual(time_1, users[1].last_logout_time) self.assertEqual(time_1, users[2].last_logout_time) # 두 사용자만 업데이트하고 둘만 변화했는지 확인 time.time.elapse(1) self.engine.member_manager.update_last_logout_time([1, 3]) time_2 = datetime.datetime.fromtimestamp(time.time()) users = model.Session().query(model.User).order_by(model.User.id.asc()).all() self.assertEqual(time_2, users[0].last_logout_time) self.assertEqual(time_1, users[1].last_logout_time) self.assertEqual(time_2, users[2].last_logout_time)
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