def handle(self, *args, **options): wp_editcount_updated = now() if options["datetime"]: wp_editcount_updated = datetime.fromisoformat(options["datetime"]) # Getting all editors that are currently eligible or are staff or are superusers editors = Editor.objects.filter(wp_bundle_eligible=True) for editor in editors: if options["global_userinfo"]: global_userinfo = options["global_userinfo"] else: global_userinfo = editor_global_userinfo( editor.wp_username, editor.wp_sub, True) if global_userinfo: ( editor.wp_editcount_prev_updated, editor.wp_editcount_prev, editor.wp_editcount_recent, editor.wp_enough_recent_edits, ) = editor_recent_edits( global_userinfo["editcount"], editor.wp_editcount_updated, editor.wp_editcount_prev_updated, editor.wp_editcount_prev, editor.wp_editcount_recent, editor.wp_enough_recent_edits, ) editor.wp_editcount = global_userinfo["editcount"] editor.wp_editcount_updated = wp_editcount_updated editor.wp_enough_edits = editor_enough_edits( editor.wp_editcount) editor.wp_not_blocked = editor_not_blocked( global_userinfo["merged"]) editor.wp_valid = editor_valid( editor.wp_enough_edits, # We could recalculate this, but we would only need to do that if upped the minimum required account age. editor.wp_account_old_enough, # editor.wp_not_blocked can only be rechecked on login, so we're going with the existing value. editor.wp_not_blocked, editor.ignore_wp_blocks, ) editor.wp_bundle_eligible = editor_bundle_eligible(editor) editor.save() editor.update_bundle_authorization()
def update_from_wikipedia(self, identity, lang): """ Given the dict returned from the Wikipedia OAuth /identify endpoint, update the instance accordingly. This assumes that we have used wp_sub to match the Editor and the Wikipedia info. Expected identity data: { 'username': identity['username'], # wikipedia username 'sub': identity['sub'], # wikipedia ID 'rights': identity['rights'], # user rights on-wiki 'groups': identity['groups'], # user groups on-wiki 'editcount': identity['editcount'], 'email': identity['email'], # Date registered: YYYYMMDDHHMMSS 'registered': identity['registered'] } We could attempt to harvest real name, but we won't; we'll let users enter it if required by partners, and avoid knowing the data otherwise. """ try: assert self.wp_sub == identity["sub"] except AssertionError: logger.exception( "Was asked to update Editor data, but the " "WP sub in the identity passed in did not match the wp_sub on " "the instance. Not updating.") raise global_userinfo = self.get_global_userinfo(identity) self.wp_username = identity["username"] self.wp_rights = json.dumps(identity["rights"]) self.wp_groups = json.dumps(identity["groups"]) if global_userinfo: ( self.wp_editcount_prev_updated, self.wp_editcount_prev, self.wp_editcount_recent, self.wp_enough_recent_edits, ) = editor_recent_edits( global_userinfo["editcount"], self.wp_editcount_updated, self.wp_editcount_prev_updated, self.wp_editcount_prev, self.wp_editcount_recent, self.wp_enough_recent_edits, ) self.wp_editcount = global_userinfo["editcount"] self.wp_not_blocked = editor_not_blocked(global_userinfo["merged"]) self.wp_editcount_updated = now() self.wp_registered = editor_reg_date(identity, global_userinfo) self.wp_account_old_enough = editor_account_old_enough( self.wp_registered) self.wp_enough_edits = editor_enough_edits(self.wp_editcount) self.wp_valid = editor_valid( self.wp_enough_edits, self.wp_account_old_enough, self.wp_not_blocked, self.ignore_wp_blocks, ) self.wp_bundle_eligible = editor_bundle_eligible(self) self.save() self.update_bundle_authorization() # This will be True the first time the user logs in, since use_wp_email # defaults to True. Therefore we will initialize the email field if # they have an email at WP for us to initialize it with. if self.user.userprofile.use_wp_email: try: self.user.email = identity["email"] except KeyError: # Email isn't guaranteed to be present in identity - don't do # anything if we can't find it. logger.exception( "Unable to get Editor email address from Wikipedia.") self.user.save() # Add language if the user hasn't selected one if not self.user.userprofile.lang: self.user.userprofile.lang = lang self.user.userprofile.save()
def update_from_wikipedia( self, identity: dict, lang: str, global_userinfo: dict = None, current_datetime: timezone = None, ): """ Given the dict returned from the Wikipedia OAuth /identify endpoint, update the instance accordingly. This assumes that we have used wp_sub to match the Editor and the Wikipedia info. Parameters ---------- identity : dict { 'username': identity['username'], # wikipedia username 'sub': identity['sub'], # wikipedia ID 'rights': identity['rights'], # user rights on-wiki 'groups': identity['groups'], # user groups on-wiki 'editcount': identity['editcount'], 'email': identity['email'], # Date registered: YYYYMMDDHHMMSS 'registered': identity['registered'] } We could attempt to harvest real name, but we won't; we'll let users enter it if required by partners, and avoid knowing the data otherwise. lang : str global_userinfo : dict Optional override currently used for tests only. Defaults to fetching from global_userinfo API. { "home": str, # SUL home wiki "id": int, # Same as identity['sub'] "registration": datetime.datetime, # Wikipedia account registration date. "name": str, # Same as identity['username'] "editcount": int, # Same as identity['editcount'] "merged": [ # List of wiki accounts attached to the SUL account { "wiki": str, # Wiki name "url": str, # Wiki URL "timestamp": datetime.datetime, "method": str, "editcount": int, "registration": datetime.datetime, # Wiki registration date. "groups": list, # user groups on-wiki. }, ... ], } current_datetime : timezone optional timezone-aware timestamp override that represents now() Returns ------- None """ if not current_datetime: current_datetime = timezone.now() if global_userinfo: self.check_sub(global_userinfo["id"]) else: global_userinfo = self.get_global_userinfo(identity) self.wp_username = identity["username"] self.wp_rights = json.dumps(identity["rights"]) self.wp_groups = json.dumps(identity["groups"]) if global_userinfo: self.update_editcount(global_userinfo["editcount"], current_datetime=current_datetime) self.wp_not_blocked = editor_not_blocked(global_userinfo["merged"]) if self.wp_registered is None: self.wp_registered = editor_reg_date(identity, global_userinfo) # if the account is already old enough, we shouldn't run this check everytime # since this flag should never return back to False if not self.wp_account_old_enough: self.wp_account_old_enough = editor_account_old_enough( self.wp_registered) self.wp_enough_edits = editor_enough_edits(self.wp_editcount) self.wp_valid = editor_valid( self.wp_enough_edits, self.wp_account_old_enough, self.wp_not_blocked, self.ignore_wp_blocks, ) self.wp_bundle_eligible = editor_bundle_eligible(self) self.save() self.update_bundle_authorization() # This will be True the first time the user logs in, since use_wp_email # defaults to True. Therefore we will initialize the email field if # they have an email at WP for us to initialize it with. if self.user.userprofile.use_wp_email: try: self.user.email = identity["email"] except KeyError: # Email isn't guaranteed to be present in identity - don't do # anything if we can't find it. logger.exception( "Unable to get Editor email address from Wikipedia.") self.user.save() # Add language if the user hasn't selected one if not self.user.userprofile.lang: self.user.userprofile.lang = lang self.user.userprofile.save()
def handle(self, *args, **options): """ Updates editor info and Bundle eligibility for currently-eligible Editors. Parameters ---------- args options Returns ------- None """ # Default behavior is to use current datetime for timestamps to check all editors. now_or_datetime = now() datetime_override = None timedelta_days = 0 wp_username = None editors = Editor.objects.all() # This may be overridden so that values may be treated as if they were valid for an arbitrary datetime. # This is also passed to the model method. if options["datetime"]: datetime_override = now_or_datetime.fromisoformat( options["datetime"]) now_or_datetime = datetime_override # These are used to limit the set of editors updated by the command. # Nothing is passed to the model method. if options["timedelta_days"]: timedelta_days = int(options["timedelta_days"]) # Get editors that haven't been updated in the specified time range, with an option to limit on wp_username. if timedelta_days: editors = editors.exclude( editorlogs__timestamp__gt=now_or_datetime - timedelta(days=timedelta_days), ) # Optional wp_username filter. if options["wp_username"]: editors = editors.filter(wp_username=str(options["wp_username"])) for editor in editors: # `global_userinfo` data may be overridden. if options["global_userinfo"]: global_userinfo = options["global_userinfo"] editor.check_sub(global_userinfo["id"]) # Default behavior is to fetch live `global_userinfo` else: global_userinfo = editor_global_userinfo(editor.wp_sub) if global_userinfo: editor.update_editcount(global_userinfo["editcount"], datetime_override) # Determine editor validity. editor.wp_enough_edits = editor_enough_edits( editor.wp_editcount) editor.wp_not_blocked = editor_not_blocked( global_userinfo["merged"]) editor.wp_valid = editor_valid( editor.wp_enough_edits, # We could recalculate this, but we would only need to do that if upped the minimum required account age. editor.wp_account_old_enough, # editor.wp_not_blocked can only be rechecked on login, so we're going with the existing value. editor.wp_not_blocked, editor.ignore_wp_blocks, ) # Determine Bundle eligibility. editor.wp_bundle_eligible = editor_bundle_eligible(editor) # Save editor. editor.save() # Prune EditorLogs, with daily_prune_range set to only check the previous day to improve performance. editor.prune_editcount(current_datetime=datetime_override, daily_prune_range=2) # Update bundle authorizations. editor.update_bundle_authorization()