Skip to content

Commit

Permalink
moderation:added cli command to add queries
Browse files Browse the repository at this point in the history
  • Loading branch information
0einstein0 authored and slint committed Nov 11, 2024
1 parent 63812a5 commit 6210c61
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 24 deletions.
13 changes: 8 additions & 5 deletions site/tests/moderation/test_moderation_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
"""Test ModerationQuery model class."""

from invenio_db import db
from invenio_search import current_search_client

from zenodo_rdm.moderation.models import ModerationQuery
from zenodo_rdm.moderation.rules import match_query_rule
from zenodo_rdm.api import ZenodoRDMRecord


def test_moderation_query_creation(app):
"""Test to create and index a ModerationQuery."""
Expand All @@ -22,7 +21,10 @@ def test_moderation_query_creation(app):
active = True

query = ModerationQuery.create(
query_string, ZenodoRDMRecord, notes=notes, score=score, active=active
query_string,
notes=notes,
score=score,
active=active,
)
db.session.commit()

Expand All @@ -36,4 +38,5 @@ def test_moderation_query_creation(app):
]
)

#TODO: Add test for matching query

# TODO: Add test for matching query
91 changes: 91 additions & 0 deletions site/zenodo_rdm/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
# under the terms of the MIT License; see LICENSE file for more details.
"""Zenodo RDM cli commands."""

import csv
import os

import click
from flask.cli import with_appcontext
from invenio_access.permissions import system_identity
Expand All @@ -27,9 +30,11 @@
from invenio_requests.records.models import RequestMetadata

from zenodo_rdm.api import ZenodoRDMRecord
from zenodo_rdm.moderation.models import ModerationQuery
from zenodo_rdm.moderation.percolator import (
create_percolator_index,
get_percolator_index,
index_percolate_query,
)


Expand Down Expand Up @@ -279,3 +284,89 @@ def create_index(record_cls):
click.secho(f"Percolator index '{index_name}' created successfully.")
except Exception as e:
click.secho(f"Error creating percolator index: {e}")


@moderation.command("add-query")
@click.option(
"-r",
"--record-cls",
type=click.Choice(["records", "communities"], case_sensitive=False),
default="records",
help="Record class to base the query on (default: records).",
)
@click.option(
"-q",
"--query-string",
help="The query string for the moderation query (optional if loading from CSV).",
)
@click.option(
"-n",
"--notes",
default="Example note",
help="Additional notes for the moderation query (optional if loading from CSV).",
)
@click.option(
"-s",
"--score",
default=10,
type=int,
help="The score for the moderation query (optional if loading from CSV).",
)
@click.option(
"-a",
"--active",
default=True,
type=bool,
help="Whether the query is active (optional if loading from CSV).",
)
@click.option(
"-f",
"--file",
type=click.Path(exists=True, readable=True),
help="Path to CSV file containing queries.",
)
@with_appcontext
def add_query(record_cls, query_string, notes, score, active, file):
"""Command to add a moderation query from CSV or directly and index it."""
record_cls = ZenodoRDMRecord if record_cls == "records" else Community

try:
if file:
add_queries_from_csv(file, record_cls)
else:
create_and_index_query(record_cls, query_string, notes, score, active)

click.secho("Queries added and indexed successfully.")
except Exception as e:
click.secho(f"Error adding or indexing query: {e}")


def add_queries_from_csv(file_path, record_cls=ZenodoRDMRecord):
"""Load queries from a CSV file, add them to the database, and index them."""
with open(file_path, mode="r", newline="", encoding="utf-8") as csvfile:
csvreader = csv.reader(csvfile)

for row in csvreader:
if row:
query_string = row[0].strip().strip("'")
notes = row[1].strip().strip("'") if len(row) > 1 else None
score = int(row[2].strip()) if len(row) > 2 else 10 # Default score 10
active = (
row[3].strip().lower() == "true" if len(row) > 3 else True
) # Default to True

# Ensure to add query only if there's a query string
if query_string:
create_and_index_query(
record_cls, query_string, notes, score, active
)


def create_and_index_query(record_cls, query_string, notes, score, active):
"""Create and index a single moderation query."""
query = ModerationQuery.create(
query_string=query_string, notes=notes, score=score, active=active
)

db.session.commit()
index_percolate_query(record_cls, query.id, query_string, active, score, notes)
19 changes: 3 additions & 16 deletions site/zenodo_rdm/moderation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,9 @@
import enum
from urllib.parse import urlparse

from flask import current_app
from invenio_db import db
from invenio_search import current_search_client
from sqlalchemy_utils import ChoiceType, Timestamp

from zenodo_rdm.api import ZenodoRDMRecord

from .percolator import index_percolate_query


class LinkDomainStatus(enum.Enum):
"""Link domain status."""
Expand Down Expand Up @@ -86,7 +80,7 @@ class ModerationQuery(db.Model):

__tablename__ = "moderation_queries"

id = db.Column(db.Integer, primary_key=True, autoincrement=True)
id = db.Column(db.Integer, primary_key=True)
"""Primary key identifier for the moderation query."""

score = db.Column(db.Integer, default=0)
Expand All @@ -102,26 +96,19 @@ class ModerationQuery(db.Model):
"""Indicates whether the moderation query is currently active."""

@classmethod
def create(
cls, query_string, record_cls=ZenodoRDMRecord, notes=None, score=0, active=True
):
def create(cls, query_string, notes=None, score=0, active=True):
"""Create a new moderation query with a configurable record class."""
query = cls(query_string=query_string, notes=notes, score=score, active=active)
db.session.add(query)

index_percolate_query(record_cls, query_string, active, score, notes)

return query

@classmethod
def get(cls, query_id=None):
"""Retrieve a moderation query by ID or return all queries if no ID is provided."""
if query_id is not None:
return cls.query.filter_by(id=query_id).one_or_none()
return cls.query.all()

def __repr__(self):
"""Get a string representation of the moderation query."""
return (
f"<ModerationQuery id={self.id}, score={self.score}, active={self.active}>"
)
return f"<ModerationQuery id={self.id}, query_string={self.query_string}, score={self.score}, active={self.active}>"
8 changes: 5 additions & 3 deletions site/zenodo_rdm/moderation/percolator.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
#
# This file is part of Invenio.
# Copyright (C) 2017-2024 CERN.
# Copyright (C) 2022 Graz University of Technology.
# Copyright (C) 2024 CERN.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -74,12 +73,15 @@ def create_percolator_index(record_cls):
current_app.logger.exception(e)


def index_percolate_query(record_cls, query_string, active=True, score=1, notes=None):
def index_percolate_query(
record_cls, query_id, query_string, active=True, score=1, notes=None
):
"""Index a percolate query."""
try:
current_search_client.index(
index=get_percolator_index(record_cls),
body={
"id": query_id,
"query": {"query_string": {"query": query_string}},
"active": active,
"score": score,
Expand Down

0 comments on commit 6210c61

Please sign in to comment.