def store_check(areaId):

    """ This is different with ireserve_ctrl.storeCheck.
    No matter which store and whatever the model is, this function will return
    true
    只是为了提供登录用的URL,以方便获取短信验证码。根据appleId所对应的城市,
    任何一家直营店的任何有库存的型号即可生成登录URL。
    :returns: TODO
    """
    availurl = configHelper.readURL("availURL")
    avail_json = requests.get(availurl).json()

    if len(avail_json) < 1:
        # Apple.com reservation is not available yet
        print(bcolors.FAIL + time.strftime('%d, %b %Y %H:%M:%S') +
                " - Data Unavailable.")
        return
    else:
        stores = dao.getStoresByArea(areaId)
        for item in stores:
            storeId = item[0]

            allModels = avail_json.get(storeId)
            for modelId in allModels:
                if allModels[modelId] == "ALL":
                    # 如果有货
                    reserve_info = {
                        "modelId": modelId,
                        "storeId": storeId,
                        "areaId": areaId,
                    }

                    return reserve_info
Example #2
0
    def storeCheck(self):

        # imp.reload(sys)

        availurl = configHelper.readURL("availURL")
        # response = urllib2.urlopen(availurl)
        # content = response.read()
        # avail_json = json.loads(content)
        headers = myutil.getHTMLHeaders()
        avail_json = requests.get(availurl, headers=headers).json()
        # Apple.com reservation is not available yet
        if len(avail_json) < 1:
            print(bcolors.FAIL + time.strftime('%d, %b %Y %H:%M:%S') +
                  " - Data Unavailable.")
            return

        # 组织好area-model-clients数据结构
        print("--------------- area-model-clients 数据结构 -----------------")
        print(bcolors.OKBLUE + myutil.format_dict(self.__maindict))

        # 遍历area-model-clients数据结构
        for areaId, areaDict in self.__maindict.items():
            stores = self.__dao.getStoresByArea(areaId)
            # 对于每一个地区的所有店铺遍历
            for item in stores:
                storeId = item[0]
                storeName = item[1]
                areaName = item[2]

                storeStr = storeName + ", " + areaName + ", " + storeId
                print(bcolors.OKGREEN + storeStr)

                # 过滤出当前店铺所有产品
                allModels = avail_json.get(storeId)
                for modelId in allModels:
                    # 如果当前产品id在顾客选择的产品范围之内,并且有库存的话
                    if modelId in areaDict and allModels[modelId] == "ALL":
                        reserve_info = {
                            "modelId": modelId,
                            "storeId": storeId,
                            "clientInfo": areaDict[modelId][0],
                            "areaId": areaId,
                            "storeStr": storeStr,
                        }
                        clientInfo = areaDict[modelId][0]
                        applog_info = {
                            "storeName": storeName,
                            "areaName": areaName,
                            "modelName": self.__models[modelId],
                            "fengId": clientInfo["fengId"],
                            "appleId": clientInfo["appleId"],
                        }
                        return reserve_info, applog_info

                print(bcolors.FAIL + "Nothing Available\n")
        print(bcolors.OKBLUE + "Updated: " +
              time.strftime('%d, %b %Y %H:%M:%S') + "\n")
Example #3
0
    def do_reserve(self, areaId, storeId, modelId, clientInfo, storeStr):
        # Get initial request URL
        modelSelectURL = configHelper.readURL("modelSelectURL")
        url = modelSelectURL + "&partNumber=" + modelId + "&store=" + storeId
        if not self.__test:
            print(bcolors.OKGREEN + modelId + " - " + self.__models[modelId])
            self.__logger.info(modelId + "   -   " + self.__models[modelId] +
                               "   -   " + storeStr)
            os.system('espeak "Congratulations!"')

        print(u"当前的预约信息: " + areaId + " " + storeId + " " + modelId)
        print(u"客户信息 -- " + myutil.format_dict(clientInfo, tab=1))

        IReserve = myutil.get_class(configHelper.readEngine())
        ir = IReserve()
        errorList = ir.reserve(url, clientInfo, self.__test)

        return errorList
def sms_update(clientInfo, lock):
    """
    Support reservation in different city with same appleId. As long as within
    half an hour, the same rcode can be used.Though different processed would
    be created based on records with same appleId in table 'rcode' still the
    same
    支持同一账号不同地区的预约。只要是同一账号验证码半小时内是通用的。
    虽然会根据rcode表中的相同的appleId启动不同的进程,但效果是一样的。
    """
    print("inside sms_update")
    while True:
        # 判断当前客户是否是active的, 如果已经是无效客户则立即退出子进程
        isActive = dao.getClientInfo(clientInfo["oid"])[9]
        if not isActive:
            return

        # 获得上一次更新rcode的时间, 计算出时间差
        phoneNumber = configHelper.readPhoneNumber(False)
        rcodeResult = dao.getRCode(phoneNumber, clientInfo["appleId"])
        if rcodeResult:
            last_time = datetime.datetime.strptime(
                    rcodeResult[0][4], "%Y-%m-%d %H:%M:%S")
            time_diff = round((datetime.datetime.now() - last_time)
                              .total_seconds() / 60, 2)
        else:
            time_diff = 999

        # 如果时间差超过30分钟,则需要更新rcode
        if time_diff >= 30:
            # 获得有效库存信息,用来生成登录URL
            reserve_info = store_check(clientInfo["area"])
            if reserve_info is None:
                print(u"当前区域 %s 已关闭预约" % clientInfo["area"])
                return
            storeId = reserve_info["storeId"]
            modelId = reserve_info["modelId"]

            # Get initial request URL
            modelSelectURL = configHelper.readURL("modelSelectURL")
            url = modelSelectURL + "&partNumber=" + modelId +\
                  "&store=" + storeId

            print (u"客户信息 -- " + myutil.format_dict(clientInfo, tab=1))

            # 获得当天已发短信数目和当天已成功预约数
            cellPhoneInfo = dao.getCellphoneInfo(phoneNumber)
            todayCount = cellPhoneInfo[2] + 1
            availCount = cellPhoneInfo[3]

            # There might be maximum limit for messages per day
            # if todayCount > 100:
                # os.system('espeak "already five messages"')
                # return

            ir = IReserveHTTP()
            rCode = None
            try:
                rCode = ir.get_avail_rcode(url, clientInfo, lock)
            except errors.IReserveLoginError as e:
                os.system('espeak "login or reserve error"')
                traceback.print_exc()
                ctrl = ireserve_ctrl.IReserveCtrl()
                ctrl.inactiveClient(clientInfo["oid"])
            except errors.IReserveLoginFastError as e:
                os.system('espeak "login too fast"')
                traceback.print_exc()
                print("sleeping 10 minutes")
                time.sleep(10 * 60)
            except errors.IReserveSMSError as e:
                os.system('espeak "phone number error"')
                raise e
            except errors.ISMSTimeoutError as e:
                os.system('espeak "SMS timeout"')
                traceback.print_exc()
                time.sleep(configHelper.readConfig("loginsleep"))

            if rCode:
                curTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                dao.insertOrUpdateRCode(
                        rCode, phoneNumber, clientInfo["appleId"], curTime)
                # 更新对应手机号的信息,其有效预约次数要减一
                dao.updateCellphoneInfo(phoneNumber, todayCount, availCount)

        else:
            sleep_min = 30.00 - time_diff
            print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            process_name = multiprocessing.current_process().name
            print(" Process[%s] sms_update() sleeping %s minutes..."
                    % (process_name, sleep_min))
            time.sleep(sleep_min * 60)
Example #5
0
class IReserveHTTP(ireserve.IReserve):
    """HTTP request reserving class"""
    signinWidgetURL = configHelper.readURL("signinWidgetURL")
    signinURL = configHelper.readURL("signinURL")
    mainFormURL = configHelper.readURL("mainFormURL")

    def __init__(self):
        super(IReserveHTTP, self).__init__()
        print("IReserveHTTP init")
        self.__session = requests.Session()
        self.__dao = dao.Dao(False)
        print("IReserveHTTP init")

    def __del__(self):
        self.__session.close()
        print("IReserveHTTP deleted")

    def reserve(self, url, clientDict, test):
        print("IReserveHTTP reserve")
        self.__test = test
        url = self.__stepModelSel(url)
        url = self.__stepSignin(url, clientDict)
        url = self.__stepRCode(url, clientDict["appleId"])
        errorList = self.__stepTimeSlot(url, clientDict["govid"],
                                        clientDict["govidType"],
                                        clientDict["quantity"])
        return errorList

    def get_avail_rcode(self, url, clientDict, lock):
        print("IReserveHTTP SMS udpate")
        url = self.__stepModelSel(url)
        url = self.__stepSignin(url, clientDict)
        with lock:
            rcode = self.__stepRCodeUpdate(url, clientDict["appleId"])
        return rcode

    def __getJSONHeaders(self):
        headers = {
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.6,en;q=0.4",
            "Connection": "keep-alive",
            "Content-Type": "application/json",
            "X-Requested-With": "XMLHttpRequest",
        }
        return headers

    # ==================== Step 1 : select your model ========================
    def __stepModelSel(self, url):
        print("================= Step 1 : select your model =================")
        print("-------- Step 1.1 select your model and submit ---------"), '\n'

        # Modify request headers
        headers = myutil.getHTMLHeaders()
        self.__session.headers = headers
        r = self.__session.get(url, allow_redirects=True)
        print(r.url), '\n'

        return r.url

    # ================== Step 2 : login submit ================================
    def __stepSignin(self, url, clientDict):
        print("================ Step 2 : login submit =======================")

        redirectedLoginURL = url

        print(" ----------- Step 2.2 display iframe login widget -----------")

        r = self.__session.get(IReserveHTTP.signinWidgetURL,
                               allow_redirects=True)

        print(" -------------- Step 2.3 OMG!!! LOGIN!!!!! --------------")

        # Refresh the headers
        self.__session.headers = self.__getJSONHeaders()
        self.__session.headers.update({
            "X-Apple-App-Id":
            "942",
            "X-Apple-Locale":
            "CN-ZH",
            "X-Apple-Widget-Key":
            "40692a3a849499c31657eac1ec8123aa",
        })

        payload = {
            "accountName": clientDict["appleId"],
            "password": clientDict["pwd"],
            "rememberMe": False
        }

        r = self.__session.post(IReserveHTTP.signinURL, json=payload)

        print(" ------LOGIN JSON RESULT-----" + r.text)
        error_str = self.__json_errmsg(r.text, "serviceErrors")
        print(error_str)
        if len(error_str) > 0:
            raise errors.IReserveLoginError(error_str)

        print(" -------------- Step 2.4 Submit main login form -------------")

        self.__session.headers = myutil.getHTMLHeaders()
        rs = urlparse.urlparse(redirectedLoginURL)
        q = urlparse.parse_qs(rs.query)

        data = {
            "rememberMe": False,
            "appIdKey": q["appIdKey"],
            "language": q["language"],
            "path": q["path"],
            "oAuthToken": "",
            "rv": q["rv"]
        }
        r = self.__session.post(IReserveHTTP.mainFormURL, data=data)
        print('main login form redirect ' + r.url, '\n')

        return r.url

    # ================== Step 3 : Registration Code ========================
    def __stepRCode(self, url, appleId):
        print("================= Step 3 : Registration Code ================")

        print('---------- step 3.1 Request SMS JSON  ------------------')
        rCodeURL = url + "&ajaxSource=true&_eventId=context"
        print(rCodeURL, '\n')

        self.__session.headers = self.__getJSONHeaders()
        print("request URL: " + rCodeURL), '\n'
        r = self.__session.get(rCodeURL)

        print('--------[SMS JSON RESULT]---' + r.text + '---------------')
        if not r.text:
            raise errors.IReserveLoginFastError("登录太快了,请等几秒钟")
        print('---------- step 3.2 Send SMS & get RCode ------------'), '\n'
        rCode = ""
        # If smscode is already sended
        print(json.loads(r.text)), '\n'

        rcDict = json.loads(r.text)

        smsCode = rcDict['keyword']
        print('SMS Code: ' + rcDict['keyword'])
        print(self.__test)

        p_ie = rcDict["p_ie"]
        flowExecutionKey = rcDict['_flowExecutionKey']
        firstTime = rcDict['firstTime']

        autosms = configHelper.readMode('autosms')
        if not self.__test or autosms:
            phoneNumber = configHelper.readPhoneNumber(False)
        else:
            phoneNumber = configHelper.readPhoneNumber(True)
        print("phone number: " + phoneNumber)

        if firstTime:
            if not self.__test or autosms:
                CMPhoneNumber = configHelper.readCMPhoneNumber(self.__test)
                # rCode = "new code"
                rCode = smsmode.getResrictionCode(CMPhoneNumber, smsCode)
            else:
                # Manually input rcode
                rCode = raw_input("please input registration code:")
            # configHelper.writeRCode(rCode, appleId)
            curTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self.__dao.insertOrUpdateRCode(rCode, phoneNumber, appleId,
                                           curTime)
        else:
            # Last rCode is still available
            # rCode = configHelper.readRCode()
            rCode = self.__dao.getRCode(phoneNumber, appleId)[0][1]

        print('registration code: ' + rCode)

        self.__session.headers = myutil.getHTMLHeaders()

        data = {
            "phoneNumber": phoneNumber,
            "selectedCountryCode": 86,
            "registrationCode": rCode,
            "submit": "",
            "_flowExecutionKey": flowExecutionKey,
            "_eventId": "next",
            "p_ie": p_ie,
            "dims": ""
        }
        print("request URL: " + url), '\n'
        r = self.__session.post(url, data=data)
        print(r.url), '\n'
        return r.url

    def __stepRCodeUpdate(self, url, appleId):
        print("================= Step 3 : Registration Code ================")

        print('---------- step 3.1 Request SMS JSON  ------------------')
        rCodeURL = url + "&ajaxSource=true&_eventId=context"
        print(rCodeURL, '\n')

        self.__session.headers = self.__getJSONHeaders()
        print("request URL: " + rCodeURL), '\n'
        r = self.__session.get(rCodeURL)

        print('--------[SMS JSON RESULT]---' + r.text + '---------------')
        if not r.text:
            raise errors.IReserveLoginFastError("登录太快了,请等几秒钟")
        print('---------- step 3.2 Send SMS & get RCode ------------'), '\n'
        rCode = ""
        # If smscode is already sended
        print(json.loads(r.text)), '\n'

        rcDict = json.loads(r.text)

        smsCode = rcDict['keyword']
        print('SMS Code: ' + rcDict['keyword'])

        firstTime = rcDict['firstTime']

        if firstTime:
            CMPhoneNumber = configHelper.readCMPhoneNumber(False)
            rCode = smsmode.getResrictionCode(CMPhoneNumber, smsCode)
            # configHelper.writeRCode(rCode, appleId)
            print('registration code: ' + rCode)
            return rCode

    # --------------- Step 4 : Select timeslot ------------------------
    def __stepTimeSlot(self, url, govid, govidType, quantity):
        print("------------- Step 4.1 Select TimeSlots ---------------"), '\n'
        timeSlotURL = url + "&ajaxSource=true&_eventId=context&dims="
        print("request URL:  " + timeSlotURL)
        self.__session.headers = self.__getJSONHeaders()
        r = self.__session.get(timeSlotURL)

        print('--------[timeslots JSON RESULT]---' + r.text + '-------', '\n')
        error_str = self.__json_errmsg(r.text, "errors")
        if len(error_str) > 0:
            raise errors.IReserveSMSError(error_str)

        reserveDict = json.loads(r.text)

        # Finde the right time
        # get current hour
        timeslots = reserveDict["timeslots"]

        curHour = datetime.datetime.now().hour
        selectedId = ""
        selectedTime = ""
        # for timeslot in timeslots:
        for i, option in enumerate(timeslots):
            text = option['formattedTime']
            curId = option['timeSlotId']
            # Format : 下午 1:30 - 下午 2:00
            arr = text.split(" ")
            hour = int(arr[1].split(":")[0])
            # format hour to 24 hours
            if arr[0] == u"下午" and hour < 12:
                hour += 12

            nightMode = configHelper.readMode("nightMode")
            if nightMode and curHour < 18:
                if hour >= 20:
                    selectedId = curId
                    selectedTime = text
                    break
            else:
                if hour >= curHour + 2:
                    selectedId = curId
                    selectedTime = text
                    break

            if i == len(timeslots) - 1:
                selectedId = curId
                selectedTime = text

        print(selectedId)
        print(selectedTime), '\n'
        # print (timeslots)

        print("-------------- Step 4.2 Submit Reserve ---------------"), '\n'
        data = {
            "selectedStoreNumber": reserveDict['selectedStoreNumber'],
            # "selectedPartNumber": partNumber,
            "selectedContractType": "UNLOCKED",
            "selectedQuantity": quantity,
            "selectedTimeSlotId": selectedId,
            "lastName": reserveDict["lastName"],
            "firstName": reserveDict["firstName"],
            "email": reserveDict["email"],
            "selectedGovtIdType": govidType,
            "govtId": govid,
            "p_ie": reserveDict["p_ie"],
            "_flowExecutionKey": reserveDict["_flowExecutionKey"],
            "_eventId": "next",
            "submit": "",
        }

        self.__session.headers = myutil.getHTMLHeaders()

        print(data), '\n'
        print("request URL: " + url), '\n'

        sleeptime = configHelper.readConfig('submitTimeSleep')
        print("current sleep time is : " + str(sleeptime))
        time.sleep(sleeptime)
        r = self.__session.post(url, data=data)

        r = self.__session.get(r.url)

        url = r.url + "&ajaxSource=true&_eventId=context&dims="
        print("request URL:  " + url), '\n'
        self.__session.headers = self.__getJSONHeaders()
        r = self.__session.get(url)
        print('--------[Sumit Error JSON RESULT]---' + r.text + '-----', '\n')
        error_str = self.__json_errmsg(r.text, "errors")
        if len(error_str) > 0:
            if error_str == "availabilityError":
                raise errors.IReserveAvailError(error_str)
            else:
                raise errors.IReserveReserveError(error_str)

    # --------------- Step 5 : Submit reservation ------------------------
    def __json_errmsg(self, jsonstr, errfield):
        print(jsonstr)
        jsonobj = json.loads(jsonstr)
        error_str = ""
        # If login failed
        if jsonobj.get(errfield):
            for error in jsonobj.get(errfield):
                if errfield == "serviceErrors":
                    error_str += error["message"]
                else:
                    error_str += error
        return error_str

    # TODO
    def __pp_json(json_thing, sort=True, indents=4):
        if type(json_thing) is str:
            print(
                json.dumps(json.loads(json_thing),
                           sort_keys=sort,
                           indent=indents))
        else:
            print(json.dumps(json_thing, sort_keys=sort, indent=indents))
        return None

    def __getCookieStr(self, cookies):
        cookieStr = ''
        if cookies is not None:
            for k, v in cookies.items():
                cookieStr += k + '=' + v + ';'
            length = len(cookieStr)
            if length > 0:
                cookieStr = cookieStr[0:(length - 1)]
        return cookieStr