From 699e829e86e931130fa4f7f378baa89662b28f41 Mon Sep 17 00:00:00 2001 From: yashlamba Date: Mon, 11 Nov 2024 10:37:26 +0100 Subject: [PATCH] moderation: add rule results to dict and eval --- invenio.cfg | 6 ++--- site/zenodo_rdm/moderation/config.py | 26 ++++++++++----------- site/zenodo_rdm/moderation/handlers.py | 31 +++++++++++++++++--------- site/zenodo_rdm/moderation/tasks.py | 6 +++-- 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/invenio.cfg b/invenio.cfg index 8d595735..7604e975 100644 --- a/invenio.cfg +++ b/invenio.cfg @@ -74,7 +74,7 @@ from zenodo_rdm.github.schemas import CitationMetadataSchema from zenodo_rdm.legacy.resources import record_serializers from zenodo_rdm.metrics.config import METRICS_CACHE_UPDATE_INTERVAL from zenodo_rdm.moderation.errors import UserBlockedException -from zenodo_rdm.moderation.handlers import CommunityScoreHandler, RecordScoreHandler +from zenodo_rdm.moderation.handlers import CommunityModerationHandler, RecordModerationHandler from zenodo_rdm.openaire.records.components import OpenAIREComponent from zenodo_rdm.permissions import ( ZenodoCommunityPermissionPolicy, @@ -818,11 +818,11 @@ RDM_RECORDS_SERVICE_COMPONENTS = DefaultRecordsComponents + [ """Addd OpenAIRE component to records service.""" RDM_CONTENT_MODERATION_HANDLERS = [ - RecordScoreHandler(), + RecordModerationHandler(), ] """Records content moderation handlers.""" RDM_COMMUNITY_CONTENT_MODERATION_HANDLERS = [ - CommunityScoreHandler(), + CommunityModerationHandler(), ] """Community content moderation handlers.""" diff --git a/site/zenodo_rdm/moderation/config.py b/site/zenodo_rdm/moderation/config.py index 4c2af3ae..309e0008 100644 --- a/site/zenodo_rdm/moderation/config.py +++ b/site/zenodo_rdm/moderation/config.py @@ -45,21 +45,21 @@ MODERATION_EXEMPT_USERS = [] """List of users exempt from moderation.""" -MODERATION_RECORD_SCORE_RULES = [ - verified_user_rule, - links_rule, - files_rule, - text_sanitization_rule, - match_query_rule, -] +MODERATION_RECORD_SCORE_RULES = { + "verified_user_rule": verified_user_rule, + "links_rule": links_rule, + "files_rule": files_rule, + "text_sanitization_rule": text_sanitization_rule, + "match_query_rule": match_query_rule, +} """Scoring rules for record moderation.""" -MODERATION_COMMUNITY_SCORE_RULES = [ - links_rule, - text_sanitization_rule, - verified_user_rule, - match_query_rule, -] +MODERATION_COMMUNITY_SCORE_RULES = { + "links_rule": links_rule, + "text_sanitization_rule": text_sanitization_rule, + "verified_user_rule": verified_user_rule, + "match_query_rule": match_query_rule, +} """Scoring rules for communtiy moderation.""" MODERATION_PERCOLATOR_INDEX_PREFIX = "moderation-queries" diff --git a/site/zenodo_rdm/moderation/handlers.py b/site/zenodo_rdm/moderation/handlers.py index d57c3634..a924478d 100644 --- a/site/zenodo_rdm/moderation/handlers.py +++ b/site/zenodo_rdm/moderation/handlers.py @@ -44,7 +44,7 @@ from .uow import ExceptionOp -class BaseScoreHandler: +class BaseModerationHandler: """Base handler to calculate moderation scores based on rules.""" def __init__(self, rules=None): @@ -56,7 +56,11 @@ def rules(self): """Get scoring rules.""" if isinstance(self._rules, str): return current_app.config[self._rules] - return self._rules or [] + return self._rules or {} + + def evaluate_result(self, params): + """Evaluate aggregate result based on params.""" + return sum(params.values()) @property def should_apply_actions(self): @@ -77,17 +81,20 @@ def run(self, identity, draft=None, record=None, user=None, uow=None): ) return - score = 0 - for rule in self.rules: - score += rule(identity, draft=draft, record=record) + results = {} + for name, rule in self.rules.items(): + results[name] = rule(identity, draft=draft, record=record) + evaluation = self.evaluate_result(results) action_ctx = { "user_id": user.id, "record_pid": record.pid.pid_value, - "score": score, + "results": results, + "evaluation": evaluation, } current_app.logger.debug("Moderation score calculated", extra=action_ctx) - if score > current_scores.spam_threshold: + + if evaluation > current_scores.spam_threshold: action_ctx["action"] = "block" if self.should_apply_actions: # If user is verified, we need to (re)open the moderation @@ -102,9 +109,11 @@ def run(self, identity, draft=None, record=None, user=None, uow=None): "Block moderation action triggered", extra=action_ctx, ) - elif score < current_scores.ham_threshold: + + elif evaluation < current_scores.ham_threshold: action_ctx["action"] = "approve" + # If the user is already verified, we don't need to verify again if user.verified: current_app.logger.debug( "User is verified, skipping moderation actions", @@ -187,7 +196,7 @@ def _block(self, user, uow, action_ctx): raise UserBlockedException() -class RecordScoreHandler(BaseHandler, BaseScoreHandler): +class RecordModerationHandler(BaseHandler, BaseModerationHandler): """Handler for calculating scores for records.""" def __init__(self): @@ -222,7 +231,9 @@ def publish(self, identity, draft=None, record=None, uow=None, **kwargs): self.run(identity, record=record, user=user, uow=uow) -class CommunityScoreHandler(community_moderation.BaseHandler, BaseScoreHandler): +class CommunityModerationHandler( + community_moderation.BaseHandler, BaseModerationHandler +): """Handler for calculating scores for communities.""" def __init__(self): diff --git a/site/zenodo_rdm/moderation/tasks.py b/site/zenodo_rdm/moderation/tasks.py index 5b68efe6..3a50cfbb 100644 --- a/site/zenodo_rdm/moderation/tasks.py +++ b/site/zenodo_rdm/moderation/tasks.py @@ -90,7 +90,7 @@ def update_moderation_request(user_id, action_ctx): # TODO: Generate content/links in a cleaner way # Add a comment with the moderation context (score, etc.) - score = action_ctx["score"] + evaluation = action_ctx["evaluation"] content_pid = action_ctx.get("record_pid") or "" content = "" if content_pid.isdigit(): @@ -100,7 +100,9 @@ def update_moderation_request(user_id, action_ctx): f' (Community {content_pid})' ) - comment = dict(payload={"content": f"

Score: {score}{content}

"}) + comment = dict( + payload={"content": f"

Final evaluation: {evaluation}{content}

"} + ) events_service.create(system_identity, req, comment, CommentEventType, uow=uow) uow.commit()