Exemplo n.º 1
0
class Handler:
    """Bộ điều khiển truy vấn và xác thực qua API.
    Các API key được quản lý qua công cụ api_manager trong gói admin kèm trong
    mã nguồn. 
    Theo mặc định, API key chỉ có duy nhất 1 và không giới hạn lượt truy cập và
    độ trễ giữa mỗi lần truy câp.
    """
    def __init__(self):
        self.m = URIMapper()
        self.error = Error()
    
    def _parse_request(self, path):
        try:
            info = path.split(':')
            request = info[1][:-1].replace("'&", '"&')  # Normalize
            params = {}
            for keyword in request.split('"&'):
                pair = keyword.split("=")
                params[pair[0]] = urllib.unquote(pair[1][1:])
            return params
        except:
            return 400  # Bad request

    def request_handler(self, environ, start_response):
        try:
            # check method
            if environ['REQUEST_METHOD'] != 'GET':
                info = '<error status_code="405" \
                    description="Phương thức này không được hệ thống hỗ trợ"/>'   
                response_headers = [('Content-type', 'text/xml'),
                                    ('Content-Length', str(len(info)))]
                start_response(status, response_headers)
                return [info]
            
            
            #-- get uri --
            path = environ['PATH_INFO'].lstrip('/')
            path = urllib.unquote(path)
            
            # some tweak :-)
            if path == 'favicon.ico':
                response_headers = [('Content-type', 'text/xml'),
                                    ('Content-Length', 0)]
                start_response(status, response_headers)
                return ['']
            
            if path.startswith('about'):
                info = """<about author="AloneRoad" 
                                 full_name="Phạm Tuấn Anh"
                                 email="*****@*****.**"
                                 mobile_phone="+84 167 345 0 799"
                                 message="Cảm ơn vì đã quan tâm ⍣ "/>"""   
                response_headers = [('Content-type', 'text/xml'),
                                    ('Content-Length', str(len(info)))]
                start_response(status, response_headers)
                return [info]
        
            #------ for documents------
            elif path == '':    # return api developer's guide
                doc = open(os.path.join(os.path.dirname(__file__), 
                                        'doc/build/html/index.html')).read()
                response_headers = [('Content-type', 'text/html'),
                                    ('Content-Length', str(len(doc)))]
                start_response(status, response_headers)
                return [doc]
            
            elif path in ['_static/nature.css', 
                          '_static/pygments.css',
                          '_static/basic.css']:
                doc = open(os.path.join(os.path.dirname(__file__), 
                                        'doc/build/html/', path)).read()
                response_headers = [('Content-type', 'text/css'),
                                    ('Content-Length', str(len(doc)))]
                start_response(status, response_headers)
                return [doc]
            
            elif path in ['_static/jquery.js',
                          '_static/doctools.js',
                          '_static/jquery.js']:
                doc = open(os.path.join(os.path.dirname(__file__), 
                                        'doc/build/html/', path)).read()
                response_headers = [('Content-type', 'text/javascript'),
                                    ('Content-Length', str(len(doc)))]
                start_response(status, response_headers)
                return [doc]
            #----- end developer's guide -----
            
            #----- get remote ip -----
            ip_request = environ['REMOTE_ADDR']
            ip_key = 'api::address="%s"?last_request' % ip_request
            _time = datetime.now()
            last_request = API_DB.get(ip_key)        # get info
            if last_request:
                last_request = datetime.strptime(last_request, '%Y-%m-%d %H:%M:%S.%f')
            else:
                last_request = _time
            
            API_DB.set(ip_key, str(_time))  # set new info
    
            #----- Parse request -----
            _params = self._parse_request(path)
            if _params == 400:
                xml = """<error status_code="400"
                                description="Yêu cầu không hợp lệ"/>"""
                xml = __description__ % xml
                xml = pretty_xml(xml)
                response_headers = [('Content-type', 'text/xml'),
                                    ('Content-Length', str(len(xml)))]
                start_response(status, response_headers)
                return [xml]
            else:
                try:
                    key = 'api::api_key="%s"?last_call' % (_params['api_key'])
                except KeyError:
                    xml = self.error.authen_error("Thiếu api_key")
                    xml = __description__ % xml
                    xml = pretty_xml(xml)
                    response_headers = [('Content-type', 'text/xml'),
                                        ('Content-Length', str(len(xml)))]
                    start_response(status, response_headers)
                    return [xml]
                
                API_DB.set(key, _time)
                
                total_key = 'api::api_key="%s"?total_request_per_day' % (_params['api_key'])
                total = API_DB.get(total_key)
                if total is None:
                    xml = """<error status_code="401"
                                    description="api_key không hợp lệ"/>"""
                    xml = __description__ % xml
                    xml = pretty_xml(xml)
                    response_headers = [('Content-type', 'text/xml'),
                                        ('Content-Length', str(len(xml)))]
                    start_response(status, response_headers)
                    return [xml]
                
                delay_key = 'api::api_key="%s"?delay' % (_params['api_key'])
                limit = API_DB.get(delay_key)
                
                total_call_key = 'api::api_key="%s"?total_call' % (_params['api_key'])
                total_call = API_DB.get(total_call_key)
                delta = _time - last_request
                if delta.days != 0:
                    API_DB.set(total_call_key, 0)
                
                # Check sum requests
                if int(total_call) >= int(total) and int(total) != 0:
                    message = """
                    api_key này chỉ được phép sử dụng %s lần một ngày
                    """ % total
                    xml = """
                    <error status_code="403" description="%s"/>
                    """ % message
                    xml = __description__ % xml
                    xml = pretty_xml(xml)
                    response_headers = [('Content-type', 'text/xml'),
                                        ('Content-Length', str(len(xml)))]
                    start_response(status, response_headers)
                    return [xml]
                
                # Limit time per request
                elif (delta.seconds * 1e6 + delta.microseconds) < limit:
                    message = """
                    Khoảng thời gian tối thiểu giữa 2 lần request phải lớn hơn %s mili-giây
                    """ % (limit / 1000)
                    xml = """
                    <error status_code="403" description="%s"/>
                    """ % message
                    xml = __description__ % xml
                    xml = pretty_xml(xml)
                    response_headers = [('Content-type', 'text/xml'),
                                        ('Content-Length', str(len(xml)))]
                    start_response(status, response_headers)
                    return [xml]
                else:   # accept request
                    API_DB.set(total_call_key, int(total_call) + 1) # incr total call
                    environ['request'] = self._parse_request(path) 
                    xml = self.m.execute(environ)
                    xml = __description__ % xml
                    xml = pretty_xml(xml)
                    response_headers = [('Content-type', 'text/xml'),
                                        ('Content-Length', str(len(xml)))]
                    start_response(status, response_headers)
                    return [xml]
        
        # Debug off | (on when KeyboardInterrupt)
        except KeyboardInterrupt: # pylint: disable-msg=W0702
            message = """
            Hệ thống gặp một lỗi chưa rõ nguyên nhân. 
            Vui lòng báo lại cho bộ phận quản trị nếu gặp thông báo này
            """
            xml = """
            <error status_code="500" description="%s"/>
            """  % message
            xml = __description__ % xml
            response_headers = [('Content-type', 'text/xml'),
                                ('Content-Length', str(len(xml)))]
            start_response(status, response_headers)
            return [xml]
Exemplo n.º 2
0
class Course:
    def __init__(self):
        self.cache = KeyValueDatabase()
        client = connect(cassandra_hosts)
        self.u = ColumnFamily(client, cassandra_keyspace, 
                                            'Users', super=True)
        self.error = Error()
        
    def refresh(self):
        self.cache.flush()
    
    def _levels(self, lang='en'):
        key = 'levels_%s' % (lang)
        results = self.cache.get(key)
        if results:
            return results
        try:
            parent_folder = unicode(os.path.join(data_folder, lang))
            _levels = os.listdir(parent_folder)
            if _levels == []:
                return self.error.not_found("Chưa có dữ liệu")
            results = []
            # get only folder names
            for level in _levels:
                if os.path.isdir(os.path.join(parent_folder, level)):
                    results.append(level)
            results = sorted(results)
            self.cache.set(key, results)
            return results
        except OSError:
            return 404
    
    def _lessons(self, level, lang='en'):
        key = 'lessons_%s_%s' % (level, lang)
        results = self.cache.get(key)
        if results:
            return results
        try:
            parent_folder = unicode(os.path.join(data_folder, lang))
            parent_folder = os.path.join(parent_folder, level)
            _lessons = os.listdir(parent_folder)
            if _lessons == []:
                return self.error.not_found("Chưa có dữ liệu")
            results = []
            for lesson in _lessons:
                if os.path.isdir(os.path.join(parent_folder, lesson)):
                    results.append(lesson)
            results = sorted(results)
            self.cache.set(key, results)
            return results       
        except OSError:
            return 404
        
    def _listen(self, level, lesson, lang='en'):
        key = 'listen_%s_%s_%s' % (level, lesson, lang)
        results = self.cache.get(key)
        if results:
            return results
        try:
            parent_folder = unicode(os.path.join(data_folder, lang, level, lesson))
            audio = os.listdir(parent_folder)
            if audio == []:
                return self.error.not_found("Chưa có dữ liệu")
            results = []
            for i in audio:
                title = None
                description = None
                if i.endswith('.inf'):
                    # add '\t' to detect end string when replace
                    i = i + '\t'
                    amr = os.path.join(parent_folder, i.replace('.inf\t', '.amr'))
                    if not os.path.exists(amr): # check amr file exist
                        return 404
                    i = i.replace('\t', '') # restore i
                    # file inf chứa 2 biến là title và description
                    cmd = open(os.path.join(parent_folder, i))
                    exec(cmd)   # thực hiện chuỗi như là 1 lệnh
                    info = {'title': title,
                            'description': description,
                            'audio_file': amr.replace(data_folder, '')}
                    results.append(info)
            results = sorted(results)
            self.cache.set(key, results)
            return results
        except OSError:
            return 404  
        
    def levels(self, environ):
        try:
            lang = environ['request']['lang']
            if lang not in ('en', 'vi'):
                return self.error.param_error("Hệ thống chỉ hỗ trợ 2 ngôn ngữ là en và vi")
            session_id = environ['request']['session_id']
        except KeyError:
            return self.error.authen_error()
        try:
            self.u.get('session_id', super_column=session_id)
        except (NotFoundException, InvalidRequestException):
            return self.error.authen_error()
        results = self._levels(lang)
        if results == 404:
            return self.error.not_found("Cấu hình hệ thống sai")
        xml = ['<level name="%s"/>' % result for result in results]
        return '\n\t'.join(xml)
    
    def lessons(self, environ):
        try:
            level = environ['request']['level']
            lang = environ['request']['lang']
            if lang not in ('en', 'vi'):
                return self.error.param_error("Hệ thống chỉ hỗ trợ 2 ngôn ngữ là en và vi")
            session_id = environ['request']['session_id']
        except KeyError:
            return self.error.authen_error()
        try:
            self.u.get('session_id', super_column=session_id)
        except (NotFoundException, InvalidRequestException):
            return self.error.authen_error()
        results = self._lessons(level, lang)
        if results == 404:
            return self.error.not_found("Cấu hình hệ thống sai")
        xml = ['<lesson name="%s"/>' % result for result in results]
        return '\n\t'.join(xml)
        
    def listen(self, environ):
        try:
            level = environ['request']['level']
            lang = environ['request']['lang']
            if lang not in ('en', 'vi'):
                return self.error.param_error("Hệ thống chỉ hỗ trợ 2 ngôn ngữ là en và vi")
            lesson = environ['request']['lesson']
            session_id = environ['request']['session_id']
        except KeyError:
            return self.error.authen_error()
        try:
            self.u.get('session_id', super_column=session_id)
        except (NotFoundException, InvalidRequestException):
            return self.error.authen_error()
        results = self._listen(level, lesson, lang)
        if results == 404:
            return self.error.not_found("Cấu hình hệ thống sai")
        xml = ['<audio title="%s" description="%s" link="%s"/>' \
               % (x['title'], x['description'], audio_url_prefix + x['audio_file']) \
               for x in results]
        return '\n\t'.join(xml)