Ejemplo n.º 1
0
def func(args):
    global rankinfo
    result = args

    q_dict = args['query']
    cur = shared_db.conn.cursor()

    if not 'res' in result:
        # 'replace_output'
        # access to /~lavalse/LR2IR/exrival
        # -> generate a page for managing exrival(s)
        # access to /~lavalse/LR2IR/getrankingxml.cgi
        # -> emulate getrankingxml.cgi using data of exrival

        if args['path'] == '/~lavalse/LR2IR/exrival':

            def append_exrivalbox(tmp_rt):
                # make a page listing exrival(s)
                write_et = tmp_rt.xpath('/html/body/div/div').pop()

                # set button to add a rival
                form_add = lxml.html.fromstring(u'<form><input type="hidden" name="mode" value="add">LR2ID : <input type="text" name="playerid" value=""><input type="submit" value="ライバル追加"></form>')
                write_et.append(form_add)

                # table for exrival(s)
                r_table = lxml.html.fromstring('<table border="0"></table>')
                r_table.append(lxml.html.fromstring(u'<tr><th>LR2ID</th><th>登録名</th><th>現在の名前</th><th>最終更新</th><th>アクティブ</th></tr>'))

                csr = shared_db.conn.cursor()
                csr.execute('''
                    SELECT lr2id,current_name,screen_name,lastupdate,active FROM exrival_rival ORDER BY lr2id ASC
                ''')
                rival_all = csr.fetchall()

                if rival_all:
                    # create exrival list

                    # button to change active state of each rival
                    form_active = lxml.html.fromstring(u'<form method="post"><input type="hidden" name="mode" value="active"><input type="submit" value="設定の更新"><br></form>')

                    for rival in rival_all:
                        rd = dict(rival)
                        rd['checked'] = 'checked' if rd['active'] else ''
                        rd['active'] = u'<input type="checkbox" name="active_{lr2id}" value="1" {checked}>'.format(**rd)
                        rd['lr2id_link'] = u'<a href="search.cgi?mode=mypage&playerid={lr2id}">{lr2id}</a>'.format(**rd)
                        rd['current_name'] = '' if rd['current_name'] is None else unicode(rd['current_name'])
                        rd['screen_name'] = u'未設定' if rd['screen_name'] is None else unicode(rd['screen_name'])
                        rd['lastupdate'] = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(int(rd['lastupdate'])))
                        rd['active'] = u'<input type="checkbox" name="active_{lr2id}" value="1" {checked}>'.format(**rd)
                        r_table.append(lxml.html.fromstring(u'<tr><td>{lr2id_link}</td><td>{screen_name}</td><td>{current_name}</td><td>{lastupdate}</td><td>{active}</td></tr>'.format(**rd)))

                    form_active.append(r_table)
                    write_et.append(form_active)

                else:
                    # only header
                    write_et.append(r_table)

                return tmp_rt


            # to prepare template page of exrival, GET blank mypage with cookies if exists
            tmp_req = dpi_sock.DPIReqMsg('GET','/~lavalse/LR2IR/search.cgi?mode=mypage')
            if args['req'].msg.getheader('cookie'):
                tmp_req.msg['cookie'] = args['req'].msg.getheader('cookie')

            res, body = tmp_req.send_and_recv()
            rt = lxml.html.fromstring(body.decode('cp932',errors='ignore'))

            if args['req'].method == 'GET':
                # GET access to exrival
                # mode=add : add rival

                if q_dict.get('mode') and 'add' in q_dict.get('mode'):
                    try:
                        # page for adding a new rival
                        if q_dict['playerid'] and q_dict['playerid'][0].isdigit():
                            plid = int(q_dict['playerid'][0])
                            cur.execute('SELECT lr2id FROM exrival_rival WHERE lr2id=?',(plid,))
                            if cur.fetchall():
                                raise('requested LR2ID is already in exrival list')
                            preq = dpi_sock.DPIReqMsg('GET','/~lavalse/LR2IR/search.cgi?mode=mypage&playerid=%d' % plid)
                            res,resbody = preq.send_and_recv()
                            pinfo = lxml.html.fromstring(resbody.decode('cp932',errors="ignore"))
                            nameline = pinfo.xpath('/html/body/div/div/h3')
                            if pinfo and len(nameline):
                                nameline = nameline[0]
                                nm = nameline.text[:nameline.text.rfind(u'のマイページ')]
                                box = lxml.html.fromstring(u'<span>LR2ID:%d 現在の名前:%s<br></span>' % (plid,nm,))
                                form = lxml.html.fromstring('<form method="post" action="exrival"></form>')
                                form.append(lxml.html.fromstring(u'固定表示名(任意):<input type="text" name="scrname"><input type="hidden" name="mode" value="add"><input type="hidden" name="lr2id" value="%d"><input type="submit" value="ライバル追加">' % (plid,)))
                                box.append(form)
                                rt.xpath('/html/body/div/div')[0].append(box)
                            else:
                                raise AddRivalError('requested LR2ID does not exist')
                        else:
                            raise AddRivalError('requested LR2ID is invalid')
                    except AddRivalError as e:
                        rt.xpath('/html/body/div/div').pop().text += unicode(e)
                        rt = append_exrivalbox(rt)

                else:
                    # listing all exrival(s)
                    rt = append_exrivalbox(rt)
            else:
                # method == 'POST'

                body_dict = args['req'].body

                if body_dict.get('mode') and 'active' in body_dict.get('mode'):
                    # refresh active states
                    cur.execute('SELECT lr2id FROM exrival_rival')
                    id_all = [int(row['lr2id']) for row in cur.fetchall()]
                    active_list = []

                    for key in body_dict:
                        if key.startswith('active_') and key[7:].isdigit() and body_dict[key][0] == '1':
                            active_list.append(int(key[7:]))

                    try:
                        # UPDATE new active states
                        cur.execute('UPDATE exrival_rival SET active=0')
                        for a_id in active_list:
                            cur.execute('UPDATE exrival_rival SET active=1 WHERE lr2id=?', (a_id,))
                        shared_db.conn.commit()
                        outmsg = u'[exrival] active state was refreshed successfully'
                    except Exception as e:
                        shared_db.conn.rollback()
                        outmsg = u'[exrival] some error occured during changing active state(%s)' % unicode(e)

                    rt.xpath('/html/body/div/div').pop().text += outmsg

                elif body_dict.get('mode') and 'add' in body_dict['mode']:
                    # create new rival to exrival list and import rival score
                    try:
                        lr2id=None
                        if body_dict.get('lr2id') and body_dict['lr2id'][0].isdigit():
                            lr2id = int(body_dict['lr2id'][0])
                        else:
                            raise AddRivalError('requested LR2ID is invalid')

                        if body_dict.get('scrname') and body_dict['scrname']:
                            screen_name = body_dict['scrname'][0].decode('cp932',errors="ignore")
                        else:
                            screen_name = None

                        rivalinfo = dpi_sock.getplayerscore(lr2id)
                        rscores = rivalinfo.xpath('/dummyroot/scorelist/score')
                        current_name = rivalinfo.find('rivalname').text
                        # current_name must not be NoneType
                        if current_name is None: current_name = ''

                        try:
                            # add rival to exrival_rival
                            cur.execute(u'''
                                INSERT INTO exrival_rival(lr2id,current_name,screen_name,lastupdate,active)
                                VALUES(?,?,?,0,1)
                            ''', (lr2id,current_name,screen_name,))
                            shared_db.conn.commit()
                        except Exception as e:
                            shared_db.conn.rollback()
                            raise AddRivalError('SQL error during adding a new rival(%s)' % unicode(e))

                        try:
                            # import rival score
                            time_now = int(time.time())
                            register_scores(lr2id)
                            cur.execute('''
                                UPDATE exrival_rival SET lastupdate=? WHERE lr2id=?
                            ''',(time_now,lr2id,))
                            shared_db.conn.commit()
                        except Exception as e:
                            shared_db.conn.rollback()
                            raise AddRivalError('SQL error during registering score(s)(%s)' % str(e))

                        # all operations succeeded
                        rt.xpath('/html/body/div/div').pop().text += u'Successfully added new rival: (LR2ID:%d)' % (lr2id)

                    except AddRivalError as e:
                        rt.xpath('/html/body/div/div').pop().text += unicode(e)

                rt = append_exrivalbox(rt)

            result['res'] = res
            result['res_etree'] = rt

            result = extend_link.func(result)

        elif args['path'] == '/~lavalse/LR2IR/getrankingxml.cgi':
            # emulate getraningxml.cgi using data in exrival_score table in shared_db
            res = simpleres.SimpleHTTPResponse()
            res.msg['content-type'] = 'text/plain'

            if args['req'].method == 'POST':
                # request from LR2body.exe only has content-types header...
                try:
                    q_dict = parse_qs(args['req'].body)
                except:
                    pass

            bmsmd5 = q_dict.get('songmd5')[0] if q_dict.get('songmd5') else ''
            if not bmsmd5 or len(bmsmd5)>32:
                # getplayerxml does not get course score and '' score
                # if given those, return default getrankingxml.cgi value
                raw = dpi_sock.DPIReqMsg('GET','/~lavalse/LR2IR/getrankingxml.cgi?songmd5=%s' % bmsmd5)
                res, res_body = raw.send_and_recv()
                result['res'] = res
                result['res_body'] = res_body
                return result

            # request body from LR2body.exe contains lr2id of current user
            # use it to get latest score of given bmsmd5
            mylr2id = q_dict.get('id')[0] if q_dict.get('id') else ''
            mylr2id = int(mylr2id) if mylr2id.isdigit() else 0

            # active rivals' scores who played the song of given bmsmd5
            cur.execute('''
                SELECT er.lr2id AS id,current_name,screen_name,
                       clear,notes,combo,pg,gr,minbp
                FROM exrival_rival AS er
                INNER JOIN exrival_score AS es ON er.lr2id=es.lr2id
                WHERE er.active!=0 AND es.hash=? AND er.lr2id!=?
            ''',(bmsmd5,mylr2id,))
            played = cur.fetchall()

            # blank scores for other active rivals
            cur.execute('''
                SELECT lr2id AS id,current_name,screen_name,
                       0 AS clear, 0 AS notes, 0 AS combo, 0 AS pg, 0 AS gr, 0 AS minbp
                FROM exrival_rival
                WHERE active!=0 AND lr2id!=? AND NOT id IN (
                    SELECT lr2id FROM exrival_score WHERE hash=?
                )
            ''',(mylr2id,bmsmd5,))
            notplayed = cur.fetchall()


            # add my best score to ranking from local db
            myscore = []
            if mylr2id > 0 and str(mylr2id) in lr2files.id_db_dict:
                # use local score database
                scdb_cur = lr2files.id_db_dict[str(mylr2id)].cursor()
                scdb_cur.execute('SELECT irid AS id,name FROM player')
                mydata = dict(scdb_cur.fetchone())
                if rankinfo['bmsmd5'] == bmsmd5 and rankinfo['name']:
                    # rankinfo consist of info of this song
                    # rankinfo['name'] contains player's IR rank
                    mydata['name'] = rankinfo['name']
                # after overwriting, initialize rankinfo
                rankinfo['bmsmd5'] = ''
                rankinfo['name'] = ''
                # if already have local score, use it
                # if not, do nothing
                scdb_cur.execute('''
                    SELECT {id} AS id, '{name}' AS name,
                           clear, totalnotes AS notes, maxcombo AS combo,
                           perfect AS pg, great AS gr, minbp
                    FROM score WHERE hash=?
                '''.format(**mydata), (bmsmd5,))
                # len(myscore) = 0 or 1
                myscore = scdb_cur.fetchall()


            # create rankingxml body
            rt = lxml.etree.fromstring('<ranking>\n</ranking>')
            elem_keys = ['name','id','clear','notes','combo','pg','gr','minbp']
            score_template = u'<score>\n%s\t</score>' % (''.join(['\t\t<%s>{%s}</%s>\n' % (key,key,key,) for key in elem_keys]),)
            for score in played + notplayed + myscore:
                sc = dict(score)
                if not 'name' in sc:
                    # myscore already has 'name' element
                    sc['name'] = sc['current_name'] if sc['screen_name'] is None else sc['screen_name']
                sc_et = lxml.etree.fromstring(score_template.format(**sc))
                sc_et.tail = '\n\t'
                rt.append(sc_et)
            rt.text = '\n\t'
            rt[-1].tail = '\n'

            # important: response of getrankingxml.cgi is not xml
            # 1. it starts from '#'
            # 2. xml 'ranking' follows
            # 3. 'lastupdate' element inserted at the end of body
            res_body = '#'
            res_body += lxml.etree.tostring(rt,encoding='cp932').replace('cp932','shift_jis')
            res_body += '\n<lastupdate>%s</lastupdate>' % time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(int(time.time())))

            result['res'] = res
            result['res_body'] = res_body

    else:
        # 'res' in args == True
        # 'edit_response'
        if args['path'] == '/~lavalse/LR2IR/score.cgi':
            # import my rank in IR by parsing response of score.cgi
            if args['req'].method == 'POST':
                try:
                    q_dict = parse_qs(args['req'].body)
                except Exception as e:
                    pass

            try:
                # if score.cgi succeed, ginven body is
                # #{myrank},{the number of total players in IR},{clear rate(not failed)},
                score_res = args['res_body'].split(',')
                if len(score_res) < 4:
                    raise Exception
                rankinfo['bmsmd5'] = q_dict['songmd5'][0]
                rankinfo['name'] = 'IR'+score_res[0]+'/'+score_res[1]
            except Exception as e:
                rankinfo['bmsmd5'] = ''
                rankinfo['name'] = ''

    return result
Ejemplo n.º 2
0
def func(args):
    global rankinfo
    result = args

    q_dict = args['query']
    cur = shared_db.conn.cursor()

    if not 'res' in result:
        # 'replace_output'
        # access to /~lavalse/LR2IR/exrival
        # -> generate a page for managing exrival(s)
        # access to /~lavalse/LR2IR/getrankingxml.cgi
        # -> emulate getrankingxml.cgi using data of exrival

        if args['path'] == '/~lavalse/LR2IR/exrival':

            def append_exrivalbox(tmp_rt):
                # make a page listing exrival(s)
                write_et = tmp_rt.xpath('/html/body/div/div').pop()

                # set button to add a rival
                form_add = lxml.html.fromstring(
                    u'<form><input type="hidden" name="mode" value="add">LR2ID : <input type="text" name="playerid" value=""><input type="submit" value="ライバル追加"></form>'
                )
                write_et.append(form_add)

                # table for exrival(s)
                r_table = lxml.html.fromstring('<table border="0"></table>')
                r_table.append(
                    lxml.html.fromstring(
                        u'<tr><th>LR2ID</th><th>登録名</th><th>現在の名前</th><th>最終更新</th><th>アクティブ</th></tr>'
                    ))

                csr = shared_db.conn.cursor()
                csr.execute('''
                    SELECT lr2id,current_name,screen_name,lastupdate,active FROM exrival_rival ORDER BY lr2id ASC
                ''')
                rival_all = csr.fetchall()

                if rival_all:
                    # create exrival list

                    # button to change active state of each rival
                    form_active = lxml.html.fromstring(
                        u'<form method="post"><input type="hidden" name="mode" value="active"><input type="submit" value="設定の更新"><br></form>'
                    )

                    for rival in rival_all:
                        rd = dict(rival)
                        rd['checked'] = 'checked' if rd['active'] else ''
                        rd['active'] = u'<input type="checkbox" name="active_{lr2id}" value="1" {checked}>'.format(
                            **rd)
                        rd['lr2id_link'] = u'<a href="search.cgi?mode=mypage&playerid={lr2id}">{lr2id}</a>'.format(
                            **rd)
                        rd['current_name'] = '' if rd[
                            'current_name'] is None else unicode(
                                rd['current_name'])
                        rd['screen_name'] = u'未設定' if rd[
                            'screen_name'] is None else unicode(
                                rd['screen_name'])
                        rd['lastupdate'] = time.strftime(
                            '%Y/%m/%d %H:%M:%S',
                            time.localtime(int(rd['lastupdate'])))
                        rd['active'] = u'<input type="checkbox" name="active_{lr2id}" value="1" {checked}>'.format(
                            **rd)
                        r_table.append(
                            lxml.html.fromstring(
                                u'<tr><td>{lr2id_link}</td><td>{screen_name}</td><td>{current_name}</td><td>{lastupdate}</td><td>{active}</td></tr>'
                                .format(**rd)))

                    form_active.append(r_table)
                    write_et.append(form_active)

                else:
                    # only header
                    write_et.append(r_table)

                return tmp_rt

            # to prepare template page of exrival, GET blank mypage with cookies if exists
            tmp_req = dpi_sock.DPIReqMsg(
                'GET', '/~lavalse/LR2IR/search.cgi?mode=mypage')
            if args['req'].msg.getheader('cookie'):
                tmp_req.msg['cookie'] = args['req'].msg.getheader('cookie')

            res, body = tmp_req.send_and_recv()
            rt = lxml.html.fromstring(body.decode('cp932', errors='ignore'))

            if args['req'].method == 'GET':
                # GET access to exrival
                # mode=add : add rival

                if q_dict.get('mode') and 'add' in q_dict.get('mode'):
                    try:
                        # page for adding a new rival
                        if q_dict['playerid'] and q_dict['playerid'][
                                0].isdigit():
                            plid = int(q_dict['playerid'][0])
                            cur.execute(
                                'SELECT lr2id FROM exrival_rival WHERE lr2id=?',
                                (plid, ))
                            if cur.fetchall():
                                raise (
                                    'requested LR2ID is already in exrival list'
                                )
                            preq = dpi_sock.DPIReqMsg(
                                'GET',
                                '/~lavalse/LR2IR/search.cgi?mode=mypage&playerid=%d'
                                % plid)
                            res, resbody = preq.send_and_recv()
                            pinfo = lxml.html.fromstring(
                                resbody.decode('cp932', errors="ignore"))
                            nameline = pinfo.xpath('/html/body/div/div/h3')
                            if pinfo and len(nameline):
                                nameline = nameline[0]
                                nm = nameline.text[:nameline.text.
                                                   rfind(u'のマイページ')]
                                box = lxml.html.fromstring(
                                    u'<span>LR2ID:%d 現在の名前:%s<br></span>' % (
                                        plid,
                                        nm,
                                    ))
                                form = lxml.html.fromstring(
                                    '<form method="post" action="exrival"></form>'
                                )
                                form.append(
                                    lxml.html.fromstring(
                                        u'固定表示名(任意):<input type="text" name="scrname"><input type="hidden" name="mode" value="add"><input type="hidden" name="lr2id" value="%d"><input type="submit" value="ライバル追加">'
                                        % (plid, )))
                                box.append(form)
                                rt.xpath('/html/body/div/div')[0].append(box)
                            else:
                                raise AddRivalError(
                                    'requested LR2ID does not exist')
                        else:
                            raise AddRivalError('requested LR2ID is invalid')
                    except AddRivalError as e:
                        rt.xpath('/html/body/div/div').pop().text += unicode(e)
                        rt = append_exrivalbox(rt)

                else:
                    # listing all exrival(s)
                    rt = append_exrivalbox(rt)
            else:
                # method == 'POST'

                body_dict = args['req'].body

                if body_dict.get('mode') and 'active' in body_dict.get('mode'):
                    # refresh active states
                    cur.execute('SELECT lr2id FROM exrival_rival')
                    id_all = [int(row['lr2id']) for row in cur.fetchall()]
                    active_list = []

                    for key in body_dict:
                        if key.startswith('active_') and key[7:].isdigit(
                        ) and body_dict[key][0] == '1':
                            active_list.append(int(key[7:]))

                    try:
                        # UPDATE new active states
                        cur.execute('UPDATE exrival_rival SET active=0')
                        for a_id in active_list:
                            cur.execute(
                                'UPDATE exrival_rival SET active=1 WHERE lr2id=?',
                                (a_id, ))
                        shared_db.conn.commit()
                        outmsg = u'[exrival] active state was refreshed successfully'
                    except Exception as e:
                        shared_db.conn.rollback()
                        outmsg = u'[exrival] some error occured during changing active state(%s)' % unicode(
                            e)

                    rt.xpath('/html/body/div/div').pop().text += outmsg

                elif body_dict.get('mode') and 'add' in body_dict['mode']:
                    # create new rival to exrival list and import rival score
                    try:
                        lr2id = None
                        if body_dict.get(
                                'lr2id') and body_dict['lr2id'][0].isdigit():
                            lr2id = int(body_dict['lr2id'][0])
                        else:
                            raise AddRivalError('requested LR2ID is invalid')

                        if body_dict.get('scrname') and body_dict['scrname']:
                            screen_name = body_dict['scrname'][0].decode(
                                'cp932', errors="ignore")
                        else:
                            screen_name = None

                        rivalinfo = dpi_sock.getplayerscore(lr2id)
                        rscores = rivalinfo.xpath('/dummyroot/scorelist/score')
                        current_name = rivalinfo.find('rivalname').text
                        # current_name must not be NoneType
                        if current_name is None: current_name = ''

                        try:
                            # add rival to exrival_rival
                            cur.execute(
                                u'''
                                INSERT INTO exrival_rival(lr2id,current_name,screen_name,lastupdate,active)
                                VALUES(?,?,?,0,1)
                            ''', (
                                    lr2id,
                                    current_name,
                                    screen_name,
                                ))
                            shared_db.conn.commit()
                        except Exception as e:
                            shared_db.conn.rollback()
                            raise AddRivalError(
                                'SQL error during adding a new rival(%s)' %
                                unicode(e))

                        try:
                            # import rival score
                            time_now = int(time.time())
                            register_scores(lr2id)
                            cur.execute(
                                '''
                                UPDATE exrival_rival SET lastupdate=? WHERE lr2id=?
                            ''', (
                                    time_now,
                                    lr2id,
                                ))
                            shared_db.conn.commit()
                        except Exception as e:
                            shared_db.conn.rollback()
                            raise AddRivalError(
                                'SQL error during registering score(s)(%s)' %
                                str(e))

                        # all operations succeeded
                        rt.xpath('/html/body/div/div').pop(
                        ).text += u'Successfully added new rival: (LR2ID:%d)' % (
                            lr2id)

                    except AddRivalError as e:
                        rt.xpath('/html/body/div/div').pop().text += unicode(e)

                rt = append_exrivalbox(rt)

            result['res'] = res
            result['res_etree'] = rt

            result = extend_link.func(result)

        elif args['path'] == '/~lavalse/LR2IR/getrankingxml.cgi':
            # emulate getraningxml.cgi using data in exrival_score table in shared_db
            res = simpleres.SimpleHTTPResponse()
            res.msg['content-type'] = 'text/plain'

            if args['req'].method == 'POST':
                # request from LR2body.exe only has content-types header...
                try:
                    q_dict = parse_qs(args['req'].body)
                except:
                    pass

            bmsmd5 = q_dict.get('songmd5')[0] if q_dict.get('songmd5') else ''
            if not bmsmd5 or len(bmsmd5) > 32:
                # getplayerxml does not get course score and '' score
                # if given those, return default getrankingxml.cgi value
                raw = dpi_sock.DPIReqMsg(
                    'GET',
                    '/~lavalse/LR2IR/getrankingxml.cgi?songmd5=%s' % bmsmd5)
                res, res_body = raw.send_and_recv()
                result['res'] = res
                result['res_body'] = res_body
                return result

            # request body from LR2body.exe contains lr2id of current user
            # use it to get latest score of given bmsmd5
            mylr2id = q_dict.get('id')[0] if q_dict.get('id') else ''
            mylr2id = int(mylr2id) if mylr2id.isdigit() else 0

            # active rivals' scores who played the song of given bmsmd5
            cur.execute(
                '''
                SELECT er.lr2id AS id,current_name,screen_name,
                       clear,notes,combo,pg,gr,minbp
                FROM exrival_rival AS er
                INNER JOIN exrival_score AS es ON er.lr2id=es.lr2id
                WHERE er.active!=0 AND es.hash=? AND er.lr2id!=?
            ''', (
                    bmsmd5,
                    mylr2id,
                ))
            played = cur.fetchall()

            # blank scores for other active rivals
            cur.execute(
                '''
                SELECT lr2id AS id,current_name,screen_name,
                       0 AS clear, 0 AS notes, 0 AS combo, 0 AS pg, 0 AS gr, 0 AS minbp
                FROM exrival_rival
                WHERE active!=0 AND lr2id!=? AND NOT id IN (
                    SELECT lr2id FROM exrival_score WHERE hash=?
                )
            ''', (
                    mylr2id,
                    bmsmd5,
                ))
            notplayed = cur.fetchall()

            # add my best score to ranking from local db
            myscore = []
            if mylr2id > 0 and str(mylr2id) in lr2files.id_db_dict:
                # use local score database
                scdb_cur = lr2files.id_db_dict[str(mylr2id)].cursor()
                scdb_cur.execute('SELECT irid AS id,name FROM player')
                mydata = dict(scdb_cur.fetchone())
                if rankinfo['bmsmd5'] == bmsmd5 and rankinfo['name']:
                    # rankinfo consist of info of this song
                    # rankinfo['name'] contains player's IR rank
                    mydata['name'] = rankinfo['name']
                # after overwriting, initialize rankinfo
                rankinfo['bmsmd5'] = ''
                rankinfo['name'] = ''
                # if already have local score, use it
                # if not, do nothing
                scdb_cur.execute(
                    '''
                    SELECT {id} AS id, '{name}' AS name,
                           clear, totalnotes AS notes, maxcombo AS combo,
                           perfect AS pg, great AS gr, minbp
                    FROM score WHERE hash=?
                '''.format(**mydata), (bmsmd5, ))
                # len(myscore) = 0 or 1
                myscore = scdb_cur.fetchall()

            # create rankingxml body
            rt = lxml.etree.fromstring('<ranking>\n</ranking>')
            elem_keys = [
                'name', 'id', 'clear', 'notes', 'combo', 'pg', 'gr', 'minbp'
            ]
            score_template = u'<score>\n%s\t</score>' % (''.join([
                '\t\t<%s>{%s}</%s>\n' % (
                    key,
                    key,
                    key,
                ) for key in elem_keys
            ]), )
            for score in played + notplayed + myscore:
                sc = dict(score)
                if not 'name' in sc:
                    # myscore already has 'name' element
                    sc['name'] = sc['current_name'] if sc[
                        'screen_name'] is None else sc['screen_name']
                sc_et = lxml.etree.fromstring(score_template.format(**sc))
                sc_et.tail = '\n\t'
                rt.append(sc_et)
            rt.text = '\n\t'
            rt[-1].tail = '\n'

            # important: response of getrankingxml.cgi is not xml
            # 1. it starts from '#'
            # 2. xml 'ranking' follows
            # 3. 'lastupdate' element inserted at the end of body
            res_body = '#'
            res_body += lxml.etree.tostring(rt, encoding='cp932').replace(
                'cp932', 'shift_jis')
            res_body += '\n<lastupdate>%s</lastupdate>' % time.strftime(
                '%Y/%m/%d %H:%M:%S', time.localtime(int(time.time())))

            result['res'] = res
            result['res_body'] = res_body

    else:
        # 'res' in args == True
        # 'edit_response'
        if args['path'] == '/~lavalse/LR2IR/score.cgi':
            # import my rank in IR by parsing response of score.cgi
            if args['req'].method == 'POST':
                try:
                    q_dict = parse_qs(args['req'].body)
                except Exception as e:
                    pass

            try:
                # if score.cgi succeed, ginven body is
                # #{myrank},{the number of total players in IR},{clear rate(not failed)},
                score_res = args['res_body'].split(',')
                if len(score_res) < 4:
                    raise Exception
                rankinfo['bmsmd5'] = q_dict['songmd5'][0]
                rankinfo['name'] = 'IR' + score_res[0] + '/' + score_res[1]
            except Exception as e:
                rankinfo['bmsmd5'] = ''
                rankinfo['name'] = ''

    return result
Ejemplo n.º 3
0
def func(args):
    result = args

    q_dict = args['query']
    cur = shared_db.conn.cursor()

    if not 'res' in result:
        # 'replace_output'
        # access to /~lavalse/LR2IR/exgrade
        # generate a page for managing exgrade(s)

        def append_exgradebox(tmp_rt):
            # make a page listing exgrade set(s)
            write_et = tmp_rt.xpath('/html/body/div/div').pop()

            # set button to add exgrade set
            form_add = lxml.html.fromstring(u'<form><input type="hidden" name="mode" value="add"><input type="submit" value="追加"></form>')
            write_et.append(form_add)

            # table for exgrade sets
            gs_table = lxml.html.fromstring('<table border="0"></table>')
            gs_table.append(lxml.html.fromstring(u'<tr><th>ID</th><th>段位セット</th><th>最終更新</th><th>アクティブ</th></tr>'))

            csr = shared_db.conn.cursor()
            csr.execute('''
                SELECT id,name,lastupdate,active FROM exgrade_set ORDER BY id ASC
            ''')
            gradeset_all = csr.fetchall()

            if gradeset_all:
                # create exgrade sets list

                # button to change active state of each grade set
                form_active = lxml.html.fromstring(u'<form method="post"><input type="hidden" name="mode" value="active"><input type="submit" value="アクティブ状態更新"><br></form>')

                for gradeset in gradeset_all:
                    gs = dict(gradeset)
                    gs['name'] = u'<a href="exgrade?setid={id}">{name}</a>'.format(**gs)
                    gs['lastupdate'] = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(int(gs['lastupdate'])))
                    gs['checked'] = 'checked' if gs['active'] else ''
                    gs['active'] = u'<input type="checkbox" name="active_{id}" value="1" {checked}>'.format(**gs)
                    gs_table.append(lxml.html.fromstring(u'<tr><td>{id}</td><td>{name}</td><td>{lastupdate}</td><td>{active}</td></tr>'.format(**gs)))

                form_active.append(gs_table)
                write_et.append(form_active)

            else:
                # only header
                write_et.append(gs_table)

            return tmp_rt


        # to prepare template page of exgrade, GET blank mypage with cookies if exists
        tmp_req = dpi_sock.DPIReqMsg('GET','/~lavalse/LR2IR/search.cgi?mode=mypage')
        if args['req'].msg.getheader('cookie'):
            tmp_req.msg['cookie'] = args['req'].msg.getheader('cookie')

        res, body = tmp_req.send_and_recv()
        rt = lxml.html.fromstring(body.decode('cp932',errors='ignore'))

        if args['req'].method == 'GET':
            # GET access to exgrade
            # mode  = add : add exgrade set from json
            # setid = n   : view info(all courses) of each exgrade set

            if q_dict.get('mode') and 'add' in q_dict.get('mode'):
                # page for adding a new exgrade

                box = lxml.html.fromstring('<form id="addgradeset" method="post" action="exgrade" enctype="multipart/form-data"></form>')
                box.append(lxml.html.fromstring('<span><input id="r_web" type="radio" name="ags" onchange="selectData();"><label for="r_web">from json on web</label><br></span>'))
                box.append(lxml.html.fromstring('<span><input id="r_loc" type="radio" name="ags" onchange="selectData();"><label for="r_loc">from local json</label><br></span>'))
                box.append(lxml.html.fromstring('<span id="ags_data"></span>'))
                script_str =\
'''
function selectData() {
      ch_web = document.getElementById("r_web").checked;
      ch_loc = document.getElementById("r_loc").checked;

      target = document.getElementById("ags_data");

      if (ch_web == true) {
        target.innerHTML = "<input type=\\"text\\" name=\\"jsonurl\\"> <input type=\\"submit\\">";
      }
      else if (ch_loc == true) {
        target.innerHTML = "<input type=\\"file\\" name=\\"json\\"> <input type=\\"submit\\">";
      }
    }
'''
                script = lxml.html.fromstring('<script type="text/javascript" language="javascript">%s</script>' % script_str)

                rt.xpath('/html/body/div/div')[0].append(box)
                rt.xpath('/html/head')[0].append(script.xpath('//script')[0])

            elif q_dict.get('setid') and q_dict.get('setid')[0].isdigit():
                # view info(all courses) of each exgrade set

                cur.execute('''
                    SELECT expr,name,courseid
                    FROM exgrade_grade
                    WHERE set_id=?
                    ORDER BY level ASC
                ''', (int(q_dict.get('setid')[0]),))
                grades = cur.fetchall()

                box = lxml.html.fromstring('<table border="0"></table>')
                box.append(lxml.html.fromstring(u'<tr><th>段位</th><th>コース名</th></tr>'))

                for grade in grades:
                    gd = dict(grade)
                    gd['name'] = u'<a href="search.cgi?mode=ranking&courseid={courseid}">{name}</a>'.format(**gd)
                    box.append(lxml.html.fromstring(u'<tr><td>{expr}</td><td>{name}</td></tr>'.format(**gd)))

                rt.xpath('/html/body/div/div')[0].append(box)

            else:
                # listing all exgrade(s)
                rt = append_exgradebox(rt)
        else:
            # method == 'POST'

            body_dict = args['req'].body

            if body_dict.get('mode') and 'active' in body_dict.get('mode'):
                # change active state of grade sets
                cur.execute('SELECT id FROM exgrade_set')
                id_all = [int(row['id']) for row in cur.fetchall()]
                active_list = []

                for key in body_dict:
                    if key.startswith('active_') and key[7:].isdigit() and body_dict[key][0] == '1':
                        active_list.append(int(key[7:]))

                try:
                    # UPDATE new active states
                    cur.execute('UPDATE exgrade_set SET active=0')
                    for a_id in active_list:
                        cur.execute('UPDATE exgrade_set SET active=1 WHERE id=?', (a_id,))
                    shared_db.conn.commit()
                    outmsg = u'[exgrade] active state was refreshed successfully'
                except Exception as e:
                    shared_db.conn.rollback()
                    outmsg = u'[exgrade] some error occured during changing active state(%s)' % unicode(e)

                rt.xpath('/html/body/div/div').pop().text += outmsg

            else:
                # create new exgrade set from json
                gset = None
                try:
                    # import json
                    if body_dict.get('jsonurl'):
                        try:
                            jsonres = urllib2.urlopen(unquote(body_dict['jsonurl'].pop()))
                            gset = json.loads(jsonres.read())
                        except urllib2.URLError as e:
                            raise AddGradeError('failed to get json on web(%s)' % unicode(e))
                        except ValueError as e:
                            raise AddGradeError('invalid json file')
                    elif body_dict.get('json'):
                        try:
                            gset = json.loads(body_dict['json'].pop())
                        except:
                            raise AddGradeError('failed to load local json')
                    else:
                        raise AddGradeError('invalid request')

                    # json loaded successfully
                    # check json
                    try:
                        gset_name = unicode(gset['name'])
                        if type(gset['order']) == types.ListType:
                            gset_order = gset['order']
                        else:
                            raise AddGradeError('value "order" is not a list')
                    except KeyError as e:
                        raise AddGradeError(u'JSON does not contain "%s" key.' % e.args[0])

                    try:
                        gset_order_new = []
                        for grade in gset_order:
                            if type(grade) != types.ListType:raise TypeError

                            grade_d = {}
                            grade_d['courseid'] = int(grade[0])
                            grade_d['expr'] = unicode(grade[1])

                            crsinfo = dpi_sock.getcourseinfo(grade_d['courseid'])
                            if crsinfo == None:
                                raise Exception('could not get course infomation, check courseid %d' % grade_d['courseid'])
                            crs_et = crsinfo.xpath('/courselist/course').pop()

                            grade_d['name'] = crs_et.find('title').text
                            grade_d['hash'] = crs_et.find('hash').text

                            gset_order_new.append(grade_d)
                    except TypeError:
                        raise AddGradeError('course entry must be a list contains at least 2 elements [int courseid, string repr].')
                    except IndexError:
                        raise AddGradeError('course entry must be a list contains at least 2 elements [int courseid, string repr].')
                    except AttributeError:
                        raise AddGradeError('invalid course infomation')
                    except Exception as e:
                        raise AddGradeError('error(%s)' % unicode(e))

                    try:
                        # add grade set and all grades to shared db
                        cur.execute(u'''
                            INSERT INTO exgrade_set(name,lastupdate,active)
                            VALUES(?,0,1)
                        ''', (gset_name,))
                        cur.execute(u'''
                            SELECT id FROM exgrade_set WHERE name=?
                        ''',(gset_name,))
                        set_id = cur.fetchone()['id']
                        level = 1.
                        for grade in gset_order_new:
                            params_dict = dict([('set_id',set_id), ('level', level)] + grade.items())
                            cur.execute('''
                                INSERT INTO exgrade_grade(set_id,level,courseid,hash,name,expr)
                                VALUES(:set_id,:level,:courseid,:hash,:name,:expr)
                            ''',params_dict)
                            level += 1.
                        shared_db.conn.commit()
                    except Exception as e:
                        shared_db.conn.rollback()
                        raise AddGradeError('SQL error during adding courses(%s)' % unicode(e))

                    try:
                        # import data of achiever(s) for each grade(s)
                        time_now = int(time.time())
                        register_achiever(gset_order_new)
                        cur.execute('''
                            UPDATE exgrade_set SET lastupdate=? WHERE id=?
                        ''',(time_now,set_id,))
                        shared_db.conn.commit()
                    except:
                        shared_db.conn.rollback()
                        raise AddGradeError('SQL error during registering achiever(s)')

                    # all operations succeeded
                    rt.xpath('/html/body/div/div').pop().text += u'Successfully imported: %s' % (gset_name)

                except AddGradeError as e:
                    rt.xpath('/html/body/div/div').pop().text += unicode(e)

            rt = append_exgradebox(rt)

        result['res'] = res
        result['res_etree'] = rt

    else:
        # 'edit_response'
        if not 'res_etree' in result:
            result['res_etree'] = lxml.html.fromstring(result['res_body'].decode('cp932',errors='ignore'))
        rt = result['res_etree']

        if q_dict.get('mode') and 'ranking' in q_dict.get('mode'):
            # access to /~lavalse/LR2IR/search.cgi with query 'mode=ranking'
            # adds exgrade(s) info to each user
            ranking_table = rt.xpath('/html/body/div/div/table')[-1]
            try:
                ranking_lr2id = [(int(parse_qs(tr[1][0].get('href'))['playerid'].pop()),) for tr in ranking_table[1::2]]
            except:
                ranking_lr2id = []
            exgrades = []
            for lr2id in ranking_lr2id:
                cur.execute('''
                    SELECT expr FROM exgrade_grade AS eg
                    INNER JOIN (
                        SELECT set_id, MAX(level) AS maxlv FROM exgrade_grade
                        WHERE courseid IN (SELECT crs_id FROM exgrade_achiever WHERE lr2id=?)
                              AND set_id IN (SELECT id FROM exgrade_set WHERE active != 0)
                        GROUP BY set_id
                    ) AS bg ON eg.set_id=bg.set_id AND eg.level=bg.maxlv
                    ORDER BY eg.set_id ASC
                    ''', lr2id)
                exgrades.append(cur.fetchall())
            def update_text(s):
                if s[0]:
                    s[1][2].append(lxml.html.fromstring('<br>'))
                    s[1][2][0].tail = '/'.join([exg['expr'] for exg in s[0]])
                return s
            map(update_text, zip(exgrades,ranking_table[1::2]))

        if (q_dict.get('mode') and 'mypage' in q_dict.get('mode')) and (q_dict.get('playerid')):
            # access to /~lavalse/LR2IR/search.cgi with query 'mode=ranking'
            # adds exgrade(s) info to mypage
            try:
                playerid = int(q_dict.get('playerid')[0])
                grade_cell = rt.xpath('/html/body/div/div/table[@border="0"]/tr/td')
            except:
                playerid = 0
            if playerid and len(grade_cell) > 2:
                grade_cell = grade_cell[2]
                cur.execute('''
                    SELECT expr FROM exgrade_grade AS eg
                    INNER JOIN (
                        SELECT set_id, MAX(level) AS maxlv FROM exgrade_grade
                        WHERE courseid IN (SELECT crs_id FROM exgrade_achiever WHERE lr2id=?)
                              AND set_id IN (SELECT id FROM exgrade_set WHERE active!=0)
                        GROUP BY set_id
                    ) AS bg ON eg.set_id=bg.set_id AND eg.level=bg.maxlv
                    ORDER BY eg.set_id ASC
                    ''', (playerid,))
                exgrades = cur.fetchall()
                if exgrades:
                    grade_cell.text += ' / ' + ' / '.join([exg['expr'] for exg in exgrades])

    return extend_link.func(result)