def write_timeline_to_db(self, msglist): logger.debug("acquiring lock") self.dblock.acquire() try: conn = sqlite3.connect(self.sqlitefile) cursor = conn.cursor() what_to_write = [] for msg in msglist: try: pickled_msg = obj2str(msg) sig = unicode(msg.digest()) cursor.execute( "SELECT * FROM home_timeline WHERE digest = ?", (sig, )) if not cursor.fetchone(): what_to_write.append( (unicode(pickled_msg), sig, msg.parsed.text, msg.parsed.username, msg.parsed.userid, msg.parsed.time)) except Exception, e: logger.warning("Error while checking message: %s" % (str(e))) try: logger.info("Writing %d messages" % (len(what_to_write))) cursor.executemany( "INSERT INTO home_timeline (pickled_object, digest, text, username, userid, time) VALUES(?, ?, ?, ?, ?, ?)", what_to_write) except Exception, e: logger.warning("Error %s" % (str(e)))
def like(self, message, channel=None): """ like a message """ if isinstance(message, snstype.Message): mID = message.ID elif isinstance(message, snstype.MessageID): mID = message else: logger.warning("unknown type: %s", type(message)) return {} if channel: if channel in self: # If the platforms are not identical, like method will surly fail if self[channel].platform != mID.platform: logger.warning("Inter-platform like method is not supported.") elif self[channel].is_expired(): logger.warning("channel '%s' is expired. Do nothing.", channel) else: re = self[channel].like(message) else: logger.warning("channel '%s' is not in pocket. Do nothing.", channel) else: for c in self.itervalues(): if self.__check_method(c, 'like') and not c.is_expired(): re = c.like(message) break logger.info("Like status '%s'. Result: %s",\ message.digest(), re) return re
def unlike(self, message, channel=None): """ unlike a message """ if channel: if channel in self: # If the platforms are not identical, unlike method will surly fail if self[channel].platform != mID.platform: logger.warning("Inter-platform unlike method is not supported.") elif self[channel].is_expired(): logger.warning("channel '%s' is expired. Do nothing.", channel) else: re = self[channel].unlike(message) else: logger.warning("channel '%s' is not in pocket. Do nothing.", channel) else: for c in self.itervalues(): if self.__check_method(c, 'unlike') and not c.is_expired(): re = c.unlike(message) break logger.info("UnLike status '%s'. Result: %s",\ message.digest(), re) return re
def load_config(self, fn_channel = DIR_DEFAULT_CONF_CHANNEL, fn_pocket = DIR_DEFAULT_CONF_POCKET): """ Read configs: * channel.conf * pocket.conf """ count_add_channel = 0 try: with open(path.abspath(fn_channel), "r") as fp: allinfo = json.load(fp) for site in allinfo: if self.add_channel(utils.JsonDict(site)): count_add_channel += 1 except IOError: #raise snserror.config.nofile(fn_channel) logger.warning("'%s' does not exist. Use default", fn_channel) except ValueError as e: raise snserror.config.load("file: %s; message: %s" % (fn_channel, e)) try: with open(path.abspath(fn_pocket), "r") as fp: allinfo = json.load(fp) self.jsonconf = allinfo except IOError: #raise snserror.config.nofile(fn_pocket) logger.warning("'%s' does not exist. Use default", fn_pocket) except ValueError as e: raise snserror.config.load("file: %s; message:%s" % (fn_channel, e)) logger.info("Read configs done. Add %d channels" % count_add_channel)
def save_config(self, fn_channel = DIR_DEFAULT_CONF_CHANNEL, fn_pocket = DIR_DEFAULT_CONF_POCKET): """ Save configs: reverse of load_config Configs can be modified during execution. snsapi components communicate with upper layer using Python objects. Pocket will be the unified place to handle file transactions. """ conf_channel = [] for c in self.itervalues(): conf_channel.append(c.jsonconf) conf_pocket = self.jsonconf try: json.dump(conf_channel, open(fn_channel, "w"), indent = 2) json.dump(conf_pocket, open(fn_pocket, "w"), indent = 2) except: raise snserror.config.save logger.info("save configs done")
def update(self, text, title=None): ''' Post a blog :param text: Blog post body. :param title: Blog post title. (optional) :return: success or not ''' if title is None: title = self._cat(20, [(text, 1)]) api_params = {'method': 'blog.addBlog', 'content': text, 'title': title} try: ret = self.renren_request(api_params) logger.debug("response: %s", ret) #TODO: # Preserve the id for further use? # Return it as multi-return-value? if 'id' in ret: logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception, e: logger.warning("Catch Exception %s", e)
def report_time_wrapper(*al, **ad): start = time.time() ret = func(*al, **ad) end = time.time() logger.info("Function '%s' execution time: %.2f", func.__name__, end - start) return ret
def get_saved_token(self): try: fname = self.auth_info.save_token_file if fname == "(default)" : fname = self.jsonconf.channel_name+".token.save" if fname != "(null)" : with open(fname, "r") as fp: token = utils.JsonObject(json.load(fp)) # check expire time if self.is_expired(token): logger.debug("Saved Access token is expired, try to get one through sns.auth() :D") return False #TODO: decrypt token self.token = token else: logger.debug("This channel is configured not to save token to file") return False except IOError: logger.debug("No access token saved, try to get one through sns.auth() :D") return False logger.info("Read saved token for '%s' successfully", self.jsonconf.channel_name) print self.token return True
def home_timeline(self, count=20): '''Get home timeline get statuses of yours and your friends' @param count: number of statuses ''' api_params = dict(method = "feed.get", type = 10, page = 1, count = count) try: jsonlist = self.renren_request(api_params) except Exception as e: logger.warning("catch expection: %s", e) jsonlist = [] statuslist = snstype.MessageList() for j in jsonlist: try: statuslist.append(self.Message(j,\ platform = self.jsonconf['platform'],\ channel = self.jsonconf['channel_name']\ )) except Exception as e: logger.warning("catch expection '%s' in parsing '%s'", e, j) logger.info("Read %d statuses from '%s'", len(statuslist), self.jsonconf.channel_name) return statuslist
def reply(self, mID, text): ''' Reply a renren blog :param mID: MessageID object :param text: string, the reply message :return: success or not ''' if mID.user_type == 'user': owner_key = 'uid' owner_value = mID.source_user_id else: # 'page' owner_key = 'page_id' owner_value = mID.source_page_id api_params = {'method': 'blog.addComment', 'content': text, 'id': mID.blog_id, owner_key: owner_value} logger.debug('request parameters: %s', api_params) try: ret = self.renren_request(api_params) if 'result' in ret and ret['result'] == 1: logger.info("Reply '%s' to status '%s' succeed", text, mID) return True except Exception, e: logger.warning("Catch Exception %s", e)
def save_config(self, fn_channel=DIR_DEFAULT_CONF_CHANNEL, fn_pocket=DIR_DEFAULT_CONF_POCKET): """ Save configs: reverse of load_config Configs can be modified during execution. snsapi components communicate with upper layer using Python objects. Pocket will be the unified place to handle file transactions. """ conf_channel = [] for c in self.itervalues(): conf_channel.append(c.jsonconf) conf_pocket = self.jsonconf try: json.dump(conf_channel, open(fn_channel, "w"), indent=2) json.dump(conf_pocket, open(fn_pocket, "w"), indent=2) except: raise snserror.config.save logger.info("save configs done")
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)]) if not pic: method = "t/add" else: method = "t/add_pic" try: if pic: ret = self.tencent_request(method, "POST", content=text, files={'pic': ('pic.jpg', pic)}) else: ret = self.tencent_request(method, "POST", content=text) if (ret['msg'] == "ok"): logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True else: return ret except Exception, e: logger.warning("Catch Exception: %s", e) return False
def home_timeline(self, count=None, channel=None): """ Route to home_timeline method of snsapi. :param channel: The channel name. Use None to read all channels """ status_list = snstype.MessageList() if channel: if channel in self: if self[channel].is_expired(): logger.warning("channel '%s' is expired. Do nothing.", channel) else: status_list.extend( self._home_timeline(count, self[channel])) else: logger.warning("channel '%s' is not in pocket. Do nothing.", channel) else: for c in self.itervalues(): if self.__check_method(c, 'home_timeline') and not c.is_expired(): status_list.extend(self._home_timeline(count, c)) logger.info("Read %d statuses", len(status_list)) return status_list
def update(self, text, title=None): ''' Post a blog :param text: Blog post body. :param title: Blog post title. (optional) :return: success or not ''' if title is None: title = self._cat(20, [(text, 1)]) api_params = { 'method': 'blog.addBlog', 'content': text, 'title': title } try: ret = self.renren_request(api_params) logger.debug("response: %s", ret) #TODO: # Preserve the id for further use? # Return it as multi-return-value? if 'id' in ret: logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception, e: logger.warning("Catch Exception %s", e)
def reply(self, statusID, text): ''' docstring placeholder ''' #"""reply status #@param status: StatusID object #@param text: string, the reply message #@return: success or not #""" api_params = dict(method = "share.addComment", content = text, \ share_id = statusID.status_id, user_id = statusID.source_user_id) try: ret = self.renren_request(api_params) logger.debug("Reply to status '%s' return: %s", statusID, ret) if 'result' in ret and ret['result'] == 1: logger.info("Reply '%s' to status '%s' succeed", text, statusID) return True else: return False except Exception, e: logger.warning("Reply failed: %s", e)
def home_timeline(self, count=20): '''Get home timeline get statuses of yours and your friends' @param count: number of statuses ''' api_params = dict(method="feed.get", type=10, page=1, count=count) try: jsonlist = self.renren_request(api_params) except Exception as e: logger.warning("catch expection: %s", e) jsonlist = [] statuslist = snstype.MessageList() for j in jsonlist: try: statuslist.append(self.Message(j,\ platform = self.jsonconf['platform'],\ channel = self.jsonconf['channel_name']\ )) except Exception as e: logger.warning("catch expection '%s' in parsing '%s'", e, j) logger.info("Read %d statuses from '%s'", len(statuslist), self.jsonconf.channel_name) return statuslist
def reply(self, statusID, text): ''' docstring placeholder ''' """reply status * parameter status: StatusID object * paramter text: string, the reply message * return: success or not """ api_params = dict(method = "share.addComment", content = text, \ share_id = statusID.status_id, user_id = statusID.source_user_id) try: ret = self.renren_request(api_params) logger.debug("Reply to status '%s' return: %s", statusID, ret) if 'result' in ret and ret['result'] == 1: logger.info("Reply '%s' to status '%s' succeed", text, statusID) return True else: return False except Exception, e: logger.warning("Reply failed: %s", e)
def update(self, text, channel=None, **kwargs): """ Route to update method of snsapi. :param channel: The channel name. Use None to update all channels """ re = {} if channel: if channel in self: if self[channel].is_expired(): logger.warning("channel '%s' is expired. Do nothing.", channel) else: re[channel] = self[channel].update(text) else: logger.warning("channel '%s' is not in pocket. Do nothing.", channel) else: for c in self.itervalues(): if self.__check_method(c, 'update') and not c.is_expired(): re[c.jsonconf['channel_name']] = c.update(text, **kwargs) logger.info("Update status '%s'. Result:%s", text, re) return re
def get_saved_token(self): try: fname = self.auth_info.save_token_file if fname == "(default)": fname = self.jsonconf.channel_name + ".token.save" if fname != "(null)": with open(fname, "r") as fp: token = utils.JsonObject(json.load(fp)) #check expire time if self.is_expired(token): logger.debug( "Saved Access token is expired, try to get one through sns.auth() :D" ) return False #TODO: decrypt token self.token = token else: logger.debug( "This channel is configured not to save token to file") return False except IOError: logger.debug( "No access token saved, try to get one through sns.auth() :D") return False logger.info("Read saved token for '%s' successfully", self.jsonconf.channel_name) return True
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)]) if not pic: method = "t/add" else: method = "t/add_pic" try: if pic: ret = self.tencent_request(method, "POST", content=text, files={'pic': ('pic.jpg', pic)}) else: ret = self.tencent_request(method, "POST", content=text) if(ret['msg'] == "ok"): logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True else: return ret except Exception, e: logger.warning("Catch Exception: %s", e) return False
def reply(self, mID, text): ''' Reply a renren blog :param mID: MessageID object :param text: string, the reply message :return: success or not ''' if mID.user_type == 'user': owner_key = 'uid' owner_value = mID.source_user_id else: # 'page' owner_key = 'page_id' owner_value = mID.source_page_id api_params = { 'method': 'blog.addComment', 'content': text, 'id': mID.blog_id, owner_key: owner_value } logger.debug('request parameters: %s', api_params) try: ret = self.renren_request(api_params) if 'result' in ret and ret['result'] == 1: logger.info("Reply '%s' to status '%s' succeed", text, mID) return True except Exception, e: logger.warning("Catch Exception %s", e)
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' # NOTE: # * With this pre-shortening, we can post potentially longer messages. # * It consumes one more API quota. text = self._replace_with_short_url(text) text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)], delim='//') try: if not pic: ret = self.weibo_request('statuses/update', 'POST', {'status': text}) else: ret = self.weibo_request('statuses/upload', 'POST', {'status': text}, files={'pic': ('pic.jpg', pic)}) self.Message(ret) logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception as e: logger.warning("Update status fail. Message: %s", e) return False
def load_config(self, fn_channel=DIR_DEFAULT_CONF_CHANNEL, fn_pocket=DIR_DEFAULT_CONF_POCKET): """ Read configs: * channel.conf * pocket.conf """ count_add_channel = 0 try: with open(path.abspath(fn_channel), "r") as fp: allinfo = json.load(fp) for site in allinfo: if self.add_channel(utils.JsonDict(site)): count_add_channel += 1 except IOError: #raise snserror.config.nofile(fn_channel) logger.warning("'%s' does not exist. Use default", fn_channel) except ValueError as e: raise snserror.config.load("file: %s; message: %s" % (fn_channel, e)) try: with open(path.abspath(fn_pocket), "r") as fp: allinfo = json.load(fp) self.jsonconf = allinfo except IOError: #raise snserror.config.nofile(fn_pocket) logger.warning("'%s' does not exist. Use default", fn_pocket) except ValueError as e: raise snserror.config.load("file: %s; message:%s" % (fn_channel, e)) logger.info("Read configs done. Add %d channels" % count_add_channel)
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' # NOTE: # * With this pre-shortening, we can post potentially longer messages. # * It consumes one more API quota. text = self._replace_with_short_url(text) text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)], delim='//') try: if not pic: ret = self.weibo_request('statuses/update', 'POST', {'status': text}) else: ret = self.weibo_request( 'statuses/upload', 'POST', {'status': text}, files={'pic': ('pic.jpg', pic)} ) self.Message(ret) logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception as e: logger.warning("Update status fail. Message: %s", e) return False
def auth(self): if self.get_saved_token(): return logger.info("Try to authenticate '%s' using OAuth2", self.jsonconf.channel_name) self.auth_first() self.auth_second() self.save_token() logger.debug("Authorized! access token is " + str(self.token)) logger.info("Channel '%s' is authorized", self.jsonconf.channel_name)
def reply(self, statusID, text): '''reply to a status * parameter text: the comment text * return: success or not ''' ret = self.tencent_request("t/reply", "POST", content=text, reid=statusID.reid) if(ret['msg'] == "ok"): return True logger.info("Reply '%s' to status '%s' fail: %s", text, self.jsonconf.channel_name, ret) return ret
def oauth2(self): ''' Authorizing using synchronized invocation of OAuth2. Users need to collect the code in the browser's address bar to this client. callback_url MUST be the same one you set when you apply for an app in openSNS platform. ''' logger.info("Try to authenticate '%s' using OAuth2", self.jsonconf.channel_name) self._oauth2_first() self._oauth2_second()
def reply(self, statusID, text): """reply to a status * parameter text: the comment text * return: success or not """ try: ret = self.weibo_request("comments/create", "POST", {"id": statusID.id, "comment": text}) ret["id"] return True except Exception as e: logger.info("Reply '%s' to status '%s' fail: %s", text, self.jsonconf.channel_name, e) return False
def home_timeline(self, count=20): ''' Return count ``Message`` for each uid configured. Configure 'friend_list' in your ``channel.json`` first. Or, it returns your own status list by default. ''' statuslist = snstype.MessageList() for user in self.jsonconf['friend_list']: userid = user['userid'] username = user['username'] statuslist.extend(self._get_user_status_list(count, userid, username)) logger.info("Read %d statuses from '%s'", len(statuslist), self.jsonconf['channel_name']) return statuslist
def _oauth2_second(self): ''' The second stage of oauth. Fetch authenticated code. ''' self.__init_oauth2_client() url = self.fetch_code() if url == "(null)" : raise snserror.auth self.token = self.parseCode(url) self.token.update(self.auth_client.request_access_token(self.token.code)) logger.debug("Authorized! access token is " + str(self.token)) logger.info("Channel '%s' is authorized", self.jsonconf.channel_name)
def home_timeline(self, count=20): ret = snstype.MessageList() logger.debug("acquiring lock") self.dblock.acquire() try: conn = sqlite3.connect(self.sqlitefile) c = conn.cursor() c.execute("SELECT pickled_object FROM home_timeline ORDER BY time DESC LIMIT 0, %d" % (count,)) p = c.fetchall() logger.info("%d messages read from database" % (len(p))) for i in p: ret.append(str2obj(str(i[0]))) except Exception, e: logger.warning("Error while reading database: %s" % (str(e)))
def like(self, message): '''like a status * parameter message: the message to be liked * return: success or not ''' ret = self.tencent_request("t/like", "POST", id=message.ID.reid, format="json") # errcode 6 means this status had been collected. # For the purpose of backward compatibility, we also view # it as a successful like if ret['msg'] == "ok" or ret["errcode"] == 6: return True logger.info("Like status '%s' fail: %s", self.jsonconf.channel_name, ret) return ret
def _oauth2_second(self): ''' The second stage of oauth. Fetch authenticated code. ''' self.__init_oauth2_client() url = self.fetch_code() if url == "(null)": raise snserror.auth self.token = self.parseCode(url) self.token.update( self.auth_client.request_access_token(self.token.code)) logger.debug("Authorized! access token is " + str(self.token)) logger.info("Channel '%s' is authorized", self.jsonconf.channel_name)
def unlike(self, message): '''unlike a status * parameter message: the message to be unliked * return: success or not ''' # errcode 6 means this status had never been collected. # For the purpose of backward compatibility, we also view # it as a successful like ret = self.tencent_request("t/unlike", "POST", id=message.ID.reid, format="json", favoriteId=random.randint(10, 20)) # Accordion to the API document, favoriteId can be a random number other than 0 if ret['msg'] == "ok" or ret["errcode"] == 6: return True logger.info("Unlike status '%s' fail: %s", self.jsonconf.channel_name, ret) return ret
def reply(self, statusID, text): '''reply to a status * parameter text: the comment text * return: success or not ''' try: ret = self.weibo_request('comments/create', 'POST', {'id': statusID.id, 'comment': text }) ret['id'] return True except Exception as e: logger.info("Reply '%s' to status '%s' fail: %s", text, self.jsonconf.channel_name, e) return False
def forward(self, message, text, channel=None): """ forward a message """ re = {} if channel and not self[channel].is_expired(): re = self[channel].forward(message, text) else: for c in self.itervalues(): if self.__check_method(c, "forward") and not c.is_expired(): re[c.jsonconf["channel_name"]] = c.forward(message, text) logger.info("Forward status '%s' with text '%s'. Result: %s", message.digest(), text, re) return re
def reply(self, statusID, text): '''reply to a status * parameter text: the comment text * return: success or not ''' ret = self.tencent_request("t/reply", "POST", content=text, reid=statusID.reid) if (ret['msg'] == "ok"): return True logger.info("Reply '%s' to status '%s' fail: %s", text, self.jsonconf.channel_name, ret) return ret
def reply(self, statusID, text): '''reply to a status * parameter text: the comment text * return: success or not ''' try: ret = self.weibo_request('comments/create', 'POST', {'id': statusID.id, 'comment': text}) ret['id'] return True except Exception as e: logger.info("Reply '%s' to status '%s' fail: %s", text, self.jsonconf.channel_name, e) return False
def reply(self, message, text, channel=None): """ Route to reply method of snsapi. :param channel: The channel name. Use None to automatically select one compatible channel. :param status: Message or MessageID object. :text: Reply text. """ if isinstance(message, snstype.Message): mID = message.ID elif isinstance(message, snstype.MessageID): mID = message else: logger.warning("unknown type: %s", type(message)) return {} re = {} if channel: if channel in self: # If the platforms are not identical, reply method will surly fail if self[channel].platform != mID.platform: logger.warning( "Inter-platform reply method is not supported.") elif self[channel].is_expired(): logger.warning("channel '%s' is expired. Do nothing.", channel) else: re = self[channel].reply(mID, text) else: logger.warning("channel '%s' is not in pocket. Do nothing.", channel) else: for c in self.itervalues(): if self.__check_method(c, 'reply') and not c.is_expired(): if c.jsonconf['platform'] == mID.platform: re = c.reply(mID, text) break logger.info("Reply to status '%s' with text '%s'. Result: %s",\ mID, text, re) return re
def home_timeline(self, count=20): ret = snstype.MessageList() logger.debug("acquiring lock") self.dblock.acquire() try: conn = sqlite3.connect(self.sqlitefile) c = conn.cursor() c.execute( "SELECT pickled_object FROM home_timeline ORDER BY time DESC LIMIT 0, %d" % (count, )) p = c.fetchall() logger.info("%d messages read from database" % (len(p))) for i in p: ret.append(str2obj(str(i[0]))) except Exception, e: logger.warning("Error while reading database: %s" % (str(e)))
def auth(self): ''' docstring placeholder ''' if self.get_saved_token(): return logger.info("Try to authenticate '%s' using OAuth2", self.jsonconf.channel_name) self.auth_first() self.auth_second() if not self.token: return False self.save_token() logger.debug("Authorized! access token is " + str(self.token)) logger.info("Channel '%s' is authorized", self.jsonconf.channel_name)
def forward(self, message, text, channel=None): """ forward a message """ re = {} if channel: re = self[channel].forward(message, text) else: for c in self.itervalues(): if self.__check_method(c, 'forward'): re[c.jsonconf['channel_name']] = c.forward(message, text) logger.info("Forward status '%s' with text '%s'. Result: %s",\ message.digest(), text, re) return re
def forward(self, message, text, channel = None): """ forward a message """ re = {} if channel: re = self[channel].forward(message, text) else: for c in self.itervalues(): if self.__check_method(c, 'forward'): re[c.jsonconf['channel_name']] = c.forward(message, text) logger.info("Forward status '%s' with text '%s'. Result: %s",\ message.digest(), text, re) return re
def update(self, text, channel=None): """ Route to update method of snsapi. :param channel: The channel name. Use None to update all channels """ re = {} if channel and not self[channel].is_expired(): re[channel] = self[channel].update(text) else: for c in self.itervalues(): if self.__check_method(c, "update") and not c.is_expired(): re[c.jsonconf["channel_name"]] = c.update(text) logger.info("Update status '%s'. Result:%s", text, re) return re
def home_timeline(self, count=20, channel=None): """ Route to home_timeline method of snsapi. :param channel: The channel name. Use None to read all channels """ status_list = snstype.MessageList() if channel: status_list.extend(self[channel].home_timeline(count)) else: for c in self.itervalues(): if self.__check_method(c, 'home_timeline'): status_list.extend(c.home_timeline(count)) logger.info("Read %d statuses", len(status_list)) return status_list
def update(self, text, channel=None): """ Route to update method of snsapi. :param channel: The channel name. Use None to update all channels """ re = {} if channel: re[channel] = self[channel].update(text) else: for c in self.itervalues(): if self.__check_method(c, 'update'): re[c.jsonconf['channel_name']] = c.update(text) logger.info("Update status '%s'. Result:%s", text, re) return re
def home_timeline(self, count = 20, channel = None): """ Route to home_timeline method of snsapi. :param channel: The channel name. Use None to read all channels """ status_list = snstype.MessageList() if channel and not self[channel].is_expired(): status_list.extend(self[channel].home_timeline(count)) else: for c in self.itervalues(): if self.__check_method(c, 'home_timeline') and not c.is_expired(): status_list.extend(c.home_timeline(count)) logger.info("Read %d statuses", len(status_list)) return status_list
def update(self, text): '''update a status @param text: the update message @return: success or not ''' text = self._cat(self.jsonconf['text_length_limit'], [(text,1)]) api_params = dict(method = "status.set", status = text) try: ret = self.renren_request(api_params) if 'result' in ret and ret['result'] == 1: logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception, e: logger.warning("Catch Exception %s", e)
def reply(self, message, text, channel = None): """ Route to reply method of snsapi. :param channel: The channel name. Use None to automatically select one compatible channel. :param status: Message or MessageID object. :text: Reply text. """ if isinstance(message, snstype.Message): mID = message.ID elif isinstance(message, snstype.MessageID): mID = message else: logger.warning("unknown type: %s", type(message)) return {} re = {} if channel: if channel in self: if self[channel].is_expired(): logger.warning("channel '%s' is expired. Do nothing.", channel) else: re = self[channel].reply(mID, text) else: logger.warning("channel '%s' is not in pocket. Do nothing.", channel) else: for c in self.itervalues(): if self.__check_method(c, 'reply') and not c.is_expired(): #TODO: # First try to match "channel_name". # If there is no match, try to match "platform". if c.jsonconf['platform'] == mID.platform: re = c.reply(mID, text) break logger.info("Reply to status '%s' with text '%s'. Result: %s",\ mID, text, re) return re
def reply(self, statusID, text): '''reply to a status @param text: the comment text @return: success or not ''' url = "https://api.weibo.com/2/comments/create.json" params = {} params['id'] = statusID.id params['comment'] = text params['access_token'] = self.token.access_token ret = self._http_post(url, params) try: ret['id'] return True except Exception as e: logger.info("Reply '%s' to status '%s' fail: %s", text, self.jsonconf.channel_name, ret) return False
def _oauth2_second(self): ''' The second stage of oauth. Fetch authenticated code. ''' try: self.__init_oauth2_client() url = self.fetch_code() logger.debug("get url: %s", url) if url == "(null)" : raise snserror.auth self.token = self.parseCode(url) self.token.update(self.auth_client.request_access_token(self.token.code)) logger.debug("Authorized! access token is " + str(self.token)) logger.info("Channel '%s' is authorized", self.jsonconf.channel_name) except Exception, e: logger.warning("Auth second fail. Catch exception: %s", e) self.token = None
def auth(self): ''' docstring placeholder ''' try: if self.get_saved_token(): return logger.info("Try to authenticate '%s' using OAuth2", self.jsonconf.channel_name) self.auth_first() self.auth_second() if not self.token: return False self.save_token() logger.debug("Authorized! access token is " + str(self.token)) logger.info("Channel '%s' is authorized", self.jsonconf.channel_name) except Exception, e: logger.warning("Auth second fail. Catch exception: %s", e)
def fetch_code(self): if self.auth_info.cmd_fetch_code == "(console_input)": utils.console_output( "Please input the whole url from Broswer's address bar:") return self.console_input().strip() elif self.auth_info.cmd_fetch_code == "(local_webserver)": try: self.httpd.handle_request() if 'code' in self.httpd.query_params: code = self.httpd.query_params['code'] logger.info("Get code from local server: %s", code) return "http://localhost/?%s" % urllib.urlencode( self.httpd.query_params) else: #TODO: # There is a non repeatable bug here. # When we have multiple platforms to authorize, # successive platforms may fail in this branch. # That means there is other HTTP request to the local HTTP server # before the call_back URL. # # Solution: # * Configure different port for different channels. # This is solved at upper layer. # * Support random port by default. raise snserror.auth.fetchcode finally: del self.httpd else: cmd = "%s %s" % (self.auth_info.cmd_fetch_code, self.__last_request_time) logger.debug("fetch_code command is: %s", cmd) ret = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).stdout.readline().rstrip() tries = 1 while ret == "(null)": tries += 1 if tries > self.__fetch_code_max_try: break time.sleep(self.__fetch_code_timeout) ret = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).stdout.read().rstrip() return ret
def auth(self): ''' docstring placeholder ''' try: if self.get_saved_token(): self.client.auth_with_token(self.token["access_token"]) return logger.info("Try to authenticate '%s' using OAuth2", self.jsonconf.channel_name) self.auth_first() self.auth_second() if not self.token: return False self.save_token() logger.debug("Authorized! access token is " + str(self.token)) logger.info("Channel '%s' is authorized", self.jsonconf.channel_name) except Exception, e: logger.warning("Auth second fail. Catch exception: %s", e)
def update(self, text): '''update a status @param text: the update message @return: success or not ''' text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)]) api_params = dict(method="status.set", status=text, place_id='RRAF04D95FA37892FFA88') try: ret = self.renren_request(api_params) if 'result' in ret and ret['result'] == 1: logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception, e: logger.warning("Catch Exception %s", e) return False
def home_timeline(self, count=20): '''Get home timeline :param count: number of statuses ''' statuslist = snstype.MessageList() try: jsonobj = self.weibo_request('statuses/home_timeline', 'GET', {'count': count}) if ("error" in jsonobj): logger.warning("error json object returned: %s", jsonobj) return [] for j in jsonobj['statuses']: statuslist.append(self.Message(j,\ platform = self.jsonconf['platform'],\ channel = self.jsonconf['channel_name']\ )) logger.info("Read %d statuses from '%s'", len(statuslist), self.jsonconf['channel_name']) except Exception, e: logger.warning("Catch exception: %s", e)