def sync_user_profile_with_wk(user): ''' Hits the WK api with user information in order to synchronize user metadata such as level and gravatar information. :param user: The user to sync their profile with WK. :return: boolean indicating the success of the API call. ''' api_string = build_user_information_api_string(user.profile.api_key) try: json_data = make_api_call(api_string) except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() return False user_info = json_data["user_information"] user.profile.title = user_info["title"] user.profile.join_date = datetime.utcfromtimestamp(user_info["creation_date"]) user.profile.topics_count = user_info["topics_count"] user.profile.posts_count = user_info["posts_count"] user.profile.about = user_info["about"] user.profile.set_website(user_info["website"]) user.profile.set_twitter_account(user_info["twitter"]) user.profile.gravatar = user_info["gravatar"] user.profile.last_wanikani_sync_date = timezone.now() user.profile.api_valid = True if user.profile.follow_me: user.profile.unlocked_levels.get_or_create(level=user_info["level"]) user.profile.handle_wanikani_level_change(user_info["level"]) user.profile.save() logger.info("Synced {}'s Profile.".format(user.username)) return True
def sync_user_profile_with_wk(user): """ Hits the WK api with user information in order to synchronize user metadata such as level and gravatar information. :param user: The user to sync their profile with WK. :return: boolean indicating the success of the API call. """ api_string = build_user_information_api_string(user.profile.api_key) try: json_data = make_api_call(api_string) except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() return False user_info = json_data["user_information"] user.profile.title = user_info["title"] user.profile.join_date = datetime.utcfromtimestamp(user_info["creation_date"]) user.profile.topics_count = user_info["topics_count"] user.profile.posts_count = user_info["posts_count"] user.profile.about = user_info["about"] user.profile.set_website(user_info["website"]) user.profile.set_twitter_account(user_info["twitter"]) user.profile.gravatar = user_info["gravatar"] user.profile.last_wanikani_sync_date = timezone.now() user.profile.api_valid = True if user.profile.follow_me: user.profile.unlocked_levels.get_or_create(level=user_info["level"]) user.profile.handle_wanikani_level_change(user_info["level"]) user.profile.save() logger.info("Synced {}'s Profile.".format(user.username)) return True
def one_time_merge_level(level, user=None): api_call = "https://www.wanikani.com/api/user/{}/vocabulary/{}".format( constants.API_KEY, level) response = make_api_call(api_call) vocab_list = response['requested_information'] print("Vocab found:{}".format(len(vocab_list))) for vocabulary_json in vocab_list: print("**************************************************************") print("Analyzing vocab with kanji:[{}]\tCanonical meaning is:[{}]". format(vocabulary_json['character'], vocabulary_json['meaning'])) found_vocabulary = Vocabulary.objects.filter( readings__character=vocabulary_json['character']) print("found [{}] vocabulary on the server with kanji [{}]".format( found_vocabulary.count(), vocabulary_json['character'])) if found_vocabulary.count( ) == 1 and found_vocabulary[0].meaning == vocabulary_json['meaning']: print( "No conflict found. Precisely 1 vocab on server, and meaning matches." ) elif found_vocabulary.count() > 1: print( "Conflict found. Precisely [{}] vocab on server for meaning [{}]." .format(found_vocabulary.count(), vocabulary_json['meaning'])) handle_merger(vocabulary_json, found_vocabulary) elif found_vocabulary.count() == 0: create_new_vocabulary(vocabulary_json) else: print("No conflict, but meaning has changed. Changing meaning!") to_be_edited = found_vocabulary[0] to_be_edited.meaning = vocabulary_json['meaning'] to_be_edited.save()
def sync_unlocked_vocab_with_wk(user): if user.profile.unlocked_levels_list(): pages = get_level_pages(user.profile.unlocked_levels_list()) new_review_count = new_synonym_count = 0 for page in pages: request_string = build_API_sync_string_for_user_for_levels(user, page) logger.info( "Creating sync string for user {}: {}".format( user.username, user.profile.api_key ) ) try: response = make_api_call(request_string) current_page_review_count, current_page_synonym_count = process_vocabulary_response_for_user( user, response ) new_review_count += current_page_review_count new_synonym_count += current_page_synonym_count except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() except exceptions.WanikaniAPIException as e: logger.error( "Couldn't sync recent vocab for {}".format(user.username), e ) return new_review_count, new_synonym_count else: return 0, 0
def get_wanikani_level(self): api_string = self.build_user_information_api_string( self.profile.api_key) json_data = make_api_call(api_string) user_info = json_data["user_information"] return user_info["level"]
def sync_recent_unlocked_vocab(self): if self.profile.unlocked_levels_list(): levels = [ level for level in range(self.profile.level - 2, self.profile.level + 1) if level in self.profile.unlocked_levels_list() ] if levels: logger.info( f"Target levels: {','.join([str(level) for level in levels])}" ) request_string = self.build_API_sync_string_for_levels(levels) try: logger.info(f"About to make recent vocab sync request") json_data = make_api_call(request_string) new_review_count, new_synonym_count = self.process_vocabulary_response_for_user_classic( json_data) logger.info( f"Successfully did a recent sync for {self.profile.user.username}" ) return new_review_count, new_synonym_count except exceptions.InvalidWaniKaniKey: self.profile.api_valid = False self.profile.save() except exceptions.WanikaniAPIException as e: logger.warning( f"Couldn't sync recent vocab for {self.profile.user.username}:, {e}" ) return 0, 0 pass
def get_wanikani_level_by_api_key(api_key): api_string = "https://www.wanikani.com/api/user/{}/user-information".format( api_key) response = make_api_call(api_string) user_info = response["user_information"] level = user_info["level"] return level
def sync_unlocked_vocab_with_wk(user): if user.profile.unlocked_levels_list(): pages = get_level_pages(user.profile.unlocked_levels_list()) new_review_count = new_synonym_count = 0 for page in pages: request_string = build_API_sync_string_for_user_for_levels( user, page) logger.info("Creating sync string for user {}: {}".format( user.username, user.profile.api_key)) try: response = make_api_call(request_string) current_page_review_count, current_page_synonym_count = process_vocabulary_response_for_user( user, response) new_review_count += current_page_review_count new_synonym_count += current_page_synonym_count except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() except exceptions.WanikaniAPIException as e: logger.error( "Couldn't sync recent vocab for {}".format(user.username), e) return new_review_count, new_synonym_count else: return 0, 0
def sync_unlocked_vocab_with_wk(user): if user.profile.unlocked_levels_list(): request_string = build_API_sync_string_for_user(user) response = make_api_call(request_string) new_review_count, new_synonym_count = process_vocabulary_response_for_user( user, response) return new_review_count, new_synonym_count else: return 0, 0
def unlock_eligible_vocab_from_levels(user, levels): """ I don't like duplicating code like this, but its for the purpose of reducing API call load on WaniKani. It's a hassle if the user caps out. :param user: user to add vocab to. :param levels: requested level unlock. This can also be a list. :return: unlocked count, locked count """ api_call_string = build_API_sync_string_for_user_for_levels(user, levels) response = make_api_call(api_call_string) unlocked_this_request, total_unlocked, locked = process_vocabulary_response_for_unlock(user, response) return unlocked_this_request, total_unlocked, locked
def sync_user_profile_with_wk(self): """ Hits the WK api in order to synchronize user metadata such as level and gravatar information. :param user: The user to sync their profile with WK. :return: boolean indicating the success of the API call. """ api_string = self.build_user_information_api_string( self.profile.api_key) logger.info( f"About to attempt profile update for {self.profile.user.username}: {api_string} " ) try: json_data = make_api_call(api_string) except exceptions.InvalidWaniKaniKey: self.profile.api_valid = False self.profile.save() return False logger.info( f"Successfully fetched profile information for {self.profile.user.username}" ) user_info = json_data["user_information"] self.profile.title = user_info["title"] self.profile.join_date = datetime.utcfromtimestamp( user_info["creation_date"]) self.profile.topics_count = user_info["topics_count"] self.profile.posts_count = user_info["posts_count"] self.profile.about = user_info["about"] self.profile.set_website(user_info["website"]) self.profile.set_twitter_account(user_info["twitter"]) self.profile.gravatar = user_info["gravatar"] self.profile.last_wanikani_sync_date = timezone.now() self.profile.api_valid = True if self.profile.follow_me: self.profile.unlocked_levels.get_or_create( level=user_info["level"]) self.profile.handle_wanikani_level_change(user_info["level"]) if self._wanikani_has_lapsed(user_info["level"]): logger.info( f"Looks like {self.profile.user.username}'s Wanikani account has lapsed, we are hibernating their syncing" ) self.profile.has_lapsed_wanikani = True self.profile.save() logger.info(f"Synced {self.profile.user.username}'s Profile.") return True
def unlock_vocab(self, levels): """ I don't like duplicating code like this, but its for the purpose of reducing API call load on WaniKani. It's a hassle if the user caps out. :param user: user to add vocab to. :param levels: requested level unlock. This can also be a list. :return: unlocked count, locked count """ logger.info(f"About to begin level unlock ") api_call_string = self.build_API_sync_string_for_levels(levels) response = make_api_call(api_call_string) unlocked_this_request, total_unlocked, locked = self.process_vocabulary_response_for_unlock( response) return unlocked_this_request, total_unlocked, locked
def pull_user_synonyms_by_level(self, level): """ Retrieves vocabulary list from the WK API, specifically searching to pull in synonyms. :param user: User to pull WK synonyms or :param level: The level for synonyms that should be pulled :return: None """ request_string = self.build_API_sync_string_for_user_for_levels(level) try: logger.info(f"Pulling down user synonyms: {request_string}") json_data = make_api_call(request_string) vocabulary_list = json_data["requested_information"] for vocabulary in vocabulary_list: meaning = vocabulary["meaning"] if (vocabulary["user_specific"] and vocabulary["user_specific"]["user_synonyms"]): try: review = UserSpecific.objects.get( user=self.profile.user, vocabulary__meaning=meaning) for synonym in vocabulary["user_specific"][ "user_synonyms"]: review.meaning_synonyms.get_or_create(text=synonym) review.save() except UserSpecific.DoesNotExist as e: logger.error( f"Couldn't pull review during a synonym sync: {e}") except KeyError: logger.error( f"No user_specific or synonyms?: {json_data}") except UserSpecific.MultipleObjectsReturned: reviews = UserSpecific.objects.filter( user=self.profile.user, vocabulary__meaning=meaning) for review in reviews: logger.error( f"Found something janky! Multiple reviews under 1 vocab meaning?!?: {review}" ) except exceptions.InvalidWaniKaniKey as e: logger.warning("Invalid api key! {}", e) self.profile.api_valid = False self.profile.save() except exceptions.WanikaniAPIException as e: logger.warning( f"Couldnt pull user synonyms for {self.profile.user.username}", e, )
def repopulate(): ''' A task that uses my personal API key in order to re-sync the database. Koichi often decides to switch things around on a level-per-level basis, or add synonyms, or change which readings are allowed. This method attempts to synchronize our data sets. :return: ''' url = "https://www.wanikani.com/api/user/" + constants.API_KEY + "/vocabulary/{}" logger.info("Staring DB Repopulation from WaniKani") for level in range(constants.LEVEL_MIN, constants.LEVEL_MAX + 1): json_data = make_api_call(url.format(level)) vocabulary_list = json_data['requested_information'] for vocabulary in vocabulary_list: sync_single_vocabulary_item_by_json(vocabulary)
def sync_recent_unlocked_vocab_with_wk(user): if user.profile.unlocked_levels_list(): levels = [ level for level in range(user.profile.level - 2, user.profile.level + 1) if level in user.profile.unlocked_levels_list() ] if levels: request_string = build_API_sync_string_for_user_for_levels( user, levels) json_data = make_api_call(request_string) new_review_count, new_synonym_count = process_vocabulary_response_for_user( user, json_data) return new_review_count, new_synonym_count return 0, 0
def repopulate(): """ A task that uses my personal API key in order to re-sync the database. Koichi often decides to switch things around on a level-per-level basis, or add synonyms, or change which readings are allowed. This method attempts to synchronize our data sets. :return: """ url = "https://www.wanikani.com/api/user/" + constants.API_KEY + "/vocabulary/{}" logger.info("Starting DB Repopulation from WaniKani") for level in range(constants.LEVEL_MIN, constants.LEVEL_MAX + 1): json_data = make_api_call(url.format(level)) vocabulary_list = json_data["requested_information"] for vocabulary in vocabulary_list: import_vocabulary_from_json(vocabulary)
def sync_recent_unlocked_vocab_with_wk(user): if user.profile.unlocked_levels_list(): levels = [level for level in range(user.profile.level - 2, user.profile.level + 1) if level in user.profile.unlocked_levels_list()] if levels: request_string = build_API_sync_string_for_user_for_levels(user, levels) try: json_data = make_api_call(request_string) new_review_count, new_synonym_count = process_vocabulary_response_for_user(user, json_data) return new_review_count, new_synonym_count except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() except exceptions.WanikaniAPIException as e: logger.warn("Couldn't sync recent vocab for {}".format(user.username), e) return 0, 0
def pull_user_synonyms_by_level(user, level): """ Retrieves vocabulary list from the WK API, specifically searching to pull in synonyms. :param user: User to pull WK synonyms or :param level: The level for synonyms that should be pulled :return: None """ request_string = build_API_sync_string_for_user_for_levels(user, level) try: json_data = make_api_call(request_string) vocabulary_list = json_data["requested_information"] for vocabulary in vocabulary_list: meaning = vocabulary["meaning"] if ( vocabulary["user_specific"] and vocabulary["user_specific"]["user_synonyms"] ): try: review = UserSpecific.objects.get( user=user, vocabulary__meaning=meaning ) for synonym in vocabulary["user_specific"]["user_synonyms"]: review.meaning_synonyms.get_or_create(text=synonym) review.save() except UserSpecific.DoesNotExist as e: logger.error( "Couldn't pull review during a synonym sync: {}".format(e) ) except KeyError as e: logger.error("No user_specific or synonyms?: {}".format(json_data)) except UserSpecific.MultipleObjectsReturned: reviews = UserSpecific.objects.filter( user=user, vocabulary__meaning=meaning ) for review in reviews: logger.error( "Found something janky! Multiple reviews under 1 vocab meaning?!?: {}".format( review ) ) except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() except exceptions.WanikaniAPIException as e: logger.warning("Couldnt pull user synonyms for {}".format(user.username), e)
def sync_unlocked_vocab_with_wk(user): if user.profile.unlocked_levels_list(): pages = get_level_pages(user.profile.unlocked_levels_list()) new_review_count = new_synonym_count = 0 for page in pages: request_string = build_API_sync_string_for_user_for_levels( user, page) logger.info("Creating sync string for user {}: {}".format( user.username, user.profile.api_key)) response = make_api_call(request_string) current_page_review_count, current_page_synonym_count = process_vocabulary_response_for_user( user, response) new_review_count += current_page_review_count new_synonym_count += current_page_synonym_count return new_review_count, new_synonym_count else: return 0, 0
def one_time_merge_level(level, user=None): api_call = "https://www.wanikani.com/api/user/{}/vocabulary/{}".format( constants.API_KEY, level ) response = make_api_call(api_call) vocab_list = response["requested_information"] print("Vocab found:{}".format(len(vocab_list))) for vocabulary_json in vocab_list: print("**************************************************************") print( "Analyzing vocab with kanji:[{}]\tCanonical meaning is:[{}]".format( vocabulary_json["character"], vocabulary_json["meaning"] ) ) found_vocabulary = Vocabulary.objects.filter( readings__character=vocabulary_json["character"] ) print( "found [{}] vocabulary on the server with kanji [{}]".format( found_vocabulary.count(), vocabulary_json["character"] ) ) if ( found_vocabulary.count() == 1 and found_vocabulary[0].meaning == vocabulary_json["meaning"] ): print( "No conflict found. Precisely 1 vocab on server, and meaning matches." ) elif found_vocabulary.count() > 1: print( "Conflict found. Precisely [{}] vocab on server for meaning [{}].".format( found_vocabulary.count(), vocabulary_json["meaning"] ) ) handle_merger(vocabulary_json, found_vocabulary) elif found_vocabulary.count() == 0: create_new_vocabulary(vocabulary_json) else: print("No conflict, but meaning has changed. Changing meaning!") to_be_edited = found_vocabulary[0] to_be_edited.meaning = vocabulary_json["meaning"] to_be_edited.save()
def pull_user_synonyms_by_level(user, level): ''' Retrieves vocabulary list from the WK API, specifically searching to pull in synonyms. :param user: User to pull WK synonyms or :param level: The level for synonyms that should be pulled :return: None ''' request_string = build_API_sync_string_for_user_for_levels(user, level) try: json_data = make_api_call(request_string) vocabulary_list = json_data['requested_information'] for vocabulary in vocabulary_list: meaning = vocabulary["meaning"] if vocabulary['user_specific'] and vocabulary['user_specific'][ 'user_synonyms']: try: review = UserSpecific.objects.get( user=user, vocabulary__meaning=meaning) for synonym in vocabulary['user_specific'][ 'user_synonyms']: review.meaning_synonyms.get_or_create(text=synonym) review.save() except UserSpecific.DoesNotExist as e: logger.error( "Couldn't pull review during a synonym sync: {}". format(e)) except KeyError as e: logger.error( "No user_specific or synonyms?: {}".format(json_data)) except UserSpecific.MultipleObjectsReturned: reviews = UserSpecific.objects.filter( user=user, vocabulary__meaning=meaning) for review in reviews: logger.error( "Found something janky! Multiple reviews under 1 vocab meaning?!?: {}" .format(review)) except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() except exceptions.WanikaniAPIException as e: logger.warning( "Couldnt pull user synonyms for {}".format(user.username), e)
def unlock_eligible_vocab_from_levels(user, levels): """ I don't like duplicating code like this, but its for the purpose of reducing API call load on WaniKani. It's a hassle if the user caps out. :param user: user to add vocab to. :param levels: requested level unlock. This can also be a list. :return: unlocked count, locked count """ api_call_string = build_API_sync_string_for_user_for_levels(user, levels) try: response = make_api_call(api_call_string) unlocked_this_request, total_unlocked, locked = process_vocabulary_response_for_unlock(user, response) return unlocked_this_request, total_unlocked, locked except exceptions.InvalidWaniKaniKey: logger.error("Invalid key found for user {}".format(user.username)) user.profile.api_valid = False user.profile.save() except exceptions.WanikaniAPIException as e: logger.error("Non-invalid key error found during API call. ", e)
def sync_recent_unlocked_vocab_with_wk(user): if user.profile.unlocked_levels_list(): levels = [ level for level in range(user.profile.level - 2, user.profile.level + 1) if level in user.profile.unlocked_levels_list() ] if levels: request_string = build_API_sync_string_for_user_for_levels(user, levels) try: json_data = make_api_call(request_string) new_review_count, new_synonym_count = process_vocabulary_response_for_user( user, json_data ) return new_review_count, new_synonym_count except exceptions.InvalidWaniKaniKey: user.profile.api_valid = False user.profile.save() except exceptions.WanikaniAPIException as e: logger.warn( "Couldn't sync recent vocab for {}".format(user.username), e ) return 0, 0
def sync_unlocked_vocab(self): if self.profile.unlocked_levels_list(): new_review_count = new_synonym_count = 0 request_string = self.build_API_sync_string_for_levels( self.profile.unlocked_levels_list()) logger.info( f"Creating sync string for user {self.profile.user.username}: {request_string}" ) try: response = make_api_call(request_string) current_page_review_count, current_page_synonym_count = self.process_vocabulary_response_for_user_classic( response) new_review_count += current_page_review_count new_synonym_count += current_page_synonym_count except exceptions.InvalidWaniKaniKey: self.profile.api_valid = False self.profile.save() except exceptions.WanikaniAPIException as e: logger.warning( f"Couldn't sync vocab for {self.profile.user.username}: {e}" ) return new_review_count, new_synonym_count else: return 0, 0
def get_wanikani_level_by_api_key(api_key): api_string = "https://www.wanikani.com/api/user/{}/user-information".format(api_key) response = make_api_call(api_string) user_info = response["user_information"] level = user_info["level"] return level