Skip to content

Commit cbff71f

Browse files
authored
[ENG-7873] CLONE - SPAM - When Hamming a Spammed user, preprints and registrations remain private (#11125)
## Purpose fix was_public state when flag spam ## Changes - correct check if node was public when flag_spam - use earliest confirm/flag spam log to check if node was public instead of the latest one --- - fix TypeError when check archiving status for stuck registrations (not related to ticket ENG-7873, but it's just one line `permissible_addons = set(permissible_addons)`, so no additional testing is required) ## QA Notes I couldn't reproduce this issue via UI, but combination `confirm_spam()` -> `flag_spam()` -> `...` breaks this feature. I'm not sure if it's exactly what's happening in our case, but since `flag_spam()` is used with automatic spam checks during node/preprint updates, it's quite possible. ## Ticket https://openscience.atlassian.net/browse/ENG-7873
1 parent 2328dd6 commit cbff71f

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

osf/models/mixins.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,6 +2081,22 @@ def log_class(self):
20812081
def log_params(self):
20822082
return NotImplementedError()
20832083

2084+
@property
2085+
def was_public_at_spam(self):
2086+
was_public = self.is_public
2087+
try:
2088+
latest_privacy_edit = self.logs.filter(
2089+
action__in=[self.log_class.MADE_PRIVATE, self.log_class.MADE_PUBLIC]
2090+
).latest('created')
2091+
first_spam_log = self.logs.filter(
2092+
action__in=[self.log_class.FLAG_SPAM, self.log_class.CONFIRM_SPAM],
2093+
created__gt=latest_privacy_edit.created
2094+
).earliest('created')
2095+
2096+
return first_spam_log.params.get('was_public', was_public)
2097+
except ObjectDoesNotExist:
2098+
return was_public
2099+
20842100
def get_spam_fields(self, saved_fields=None):
20852101
return NotImplementedError()
20862102

@@ -2110,15 +2126,8 @@ def confirm_spam(self, domains=None, save=True, train_spam_services=True):
21102126
"""
21112127
super().confirm_spam(save=save, domains=domains or [], train_spam_services=train_spam_services)
21122128
self.deleted = timezone.now()
2113-
was_public = self.is_public
2114-
# the approach below helps to update to public true on ham just the objects that were public before were spammed
2115-
is_public_changings = self.logs.filter(action__in=['made_public', 'made_private'])
2116-
if is_public_changings:
2117-
latest_privacy_edit_time = is_public_changings.latest('created').created
2118-
last_spam_log = self.logs.filter(action__in=['confirm_spam', 'flag_spam'],
2119-
created__gt=latest_privacy_edit_time)
2120-
if last_spam_log:
2121-
was_public = last_spam_log.latest().params.get('was_public', was_public)
2129+
was_public = self.was_public_at_spam
2130+
21222131
self.set_privacy('private', auth=None, log=False, save=False, force=True, should_hide=True)
21232132

21242133
log = self.add_log(
@@ -2221,7 +2230,6 @@ def suspend_spam_user(self, user):
22212230
if user.is_hammy:
22222231
return False
22232232
self.confirm_spam(save=True, train_spam_services=False)
2224-
self.set_privacy('private', log=False, save=True)
22252233

22262234
# Suspend the flagged user for spam.
22272235
user.flag_spam()
@@ -2240,20 +2248,18 @@ def suspend_spam_user(self, user):
22402248
for node in user.all_nodes:
22412249
if self._id != node._id and len(node.contributors) == 1 and node.is_public and not node.is_quickfiles:
22422250
node.confirm_spam(save=True, train_spam_services=False)
2243-
node.set_privacy('private', log=False, save=True, force=True)
22442251

22452252
# Make preprints private from this contributor
22462253
for preprint in user.preprints.all():
22472254
if self._id != preprint._id and len(preprint.contributors) == 1 and preprint.is_public:
22482255
preprint.confirm_spam(save=True, train_spam_services=False)
2249-
preprint.set_privacy('private', log=False, save=True)
22502256

22512257
def flag_spam(self):
22522258
""" Overrides SpamMixin#flag_spam.
22532259
"""
22542260
super().flag_spam()
22552261
if settings.SPAM_FLAGGED_MAKE_NODE_PRIVATE:
2256-
was_public = self.is_public
2262+
was_public = self.was_public_at_spam
22572263
self.set_privacy('private', auth=None, log=False, save=False, check_addons=False, force=True, should_hide=True)
22582264
log = self.add_log(
22592265
action=self.log_class.FLAG_SPAM,

osf/models/user.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -995,10 +995,8 @@ def deactivate_account(self):
995995
)
996996
except mailchimp_utils.OSFError as error:
997997
sentry.log_exception(error)
998-
sentry.log_message(error)
999998
except Exception as error:
1000999
sentry.log_exception(error)
1001-
sentry.log_message(error)
10021000
# Call to `unsubscribe` above saves, and can lead to stale data
10031001
self.reload()
10041002
self.is_disabled = True
@@ -1022,10 +1020,8 @@ def reactivate_account(self):
10221020
subscribe_on_confirm(self)
10231021
except OSFError as error:
10241022
sentry.log_exception(error)
1025-
sentry.log_message(error)
10261023
except Exception as error:
10271024
sentry.log_exception(error)
1028-
sentry.log_message(error)
10291025
signals.user_account_reactivated.send(self)
10301026

10311027
def update_is_active(self):

osf_tests/test_node.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,6 +2428,42 @@ def test_confirm_spam_makes_node_private(self, project):
24282428
assert project.is_spammy
24292429
assert project.is_public is False
24302430

2431+
@mock.patch.object(settings, 'SPAM_FLAGGED_MAKE_NODE_PRIVATE', True)
2432+
def test_project_remains_recoverable_after_multiple_spam_flags(self, project):
2433+
project.set_privacy('public')
2434+
assert project.is_public
2435+
2436+
project.confirm_spam()
2437+
assert project.is_public is False
2438+
assert project.was_public_at_spam is True
2439+
2440+
project.flag_spam()
2441+
assert project.is_public is False
2442+
assert project.was_public_at_spam is True
2443+
2444+
project.confirm_spam()
2445+
assert project.is_public is False
2446+
assert project.was_public_at_spam is True
2447+
2448+
def test_multiple_privacy_changing(self, project):
2449+
project.set_privacy('public')
2450+
assert project.is_public
2451+
2452+
project.confirm_spam()
2453+
assert not project.is_public
2454+
2455+
project.confirm_ham()
2456+
assert project.is_public
2457+
2458+
project.set_privacy('private')
2459+
assert not project.is_public
2460+
2461+
project.confirm_spam()
2462+
assert not project.is_public
2463+
2464+
project.confirm_ham()
2465+
assert not project.is_public
2466+
24312467

24322468
# copied from tests/test_models.py
24332469
class TestPrivateLinks:

0 commit comments

Comments
 (0)