Compare commits

...

6 Commits

Author SHA1 Message Date
db0 06843812c8 fix: endorsements 2023-10-15 20:26:26 +02:00
db0 cd6375cd2c fix: massive speed up retrieval of _given 2023-10-15 20:25:37 +02:00
db0 f0b53af3d2 feat: don't show rebuttals from muted instances 2023-10-15 19:28:50 +02:00
Divided by Zer0 6d44604f99
Merge pull request #54 from Fediseer/rebuttals
Feat: Rebuttals
2023-10-15 19:22:36 +02:00
db0 b44529242d fix: Increase speed on censures and hesitations GET 2023-10-15 19:18:06 +02:00
db0 d380f34364 feat: Rebuttals 2023-10-15 17:54:25 +02:00
12 changed files with 308 additions and 56 deletions

View File

@ -1,5 +1,10 @@
# Changelog
# 0.21.0
* Added rebuttals
* Improved speed of GET on /hesitations and /censures
# 0.20.1
* Allow filtering by software

View File

@ -62,6 +62,7 @@ class Models:
self.response_model_instances_censured = api.inherit('CensuredInstanceDetails', self.response_model_instances, {
'censure_reasons': fields.List(fields.String(description="The reasons instances have given for censuring this instance")),
'censure_evidence': fields.List(fields.String(description="Evidence justifying this censure, typically should be one or more URLs.")),
'rebuttal': fields.List(fields.String(description="Counter argument by the target instance.", example="Nuh uh!")),
'censure_count': fields.Integer(description="The amount of censures this instance has received from the reference instances"),
})
self.response_model_model_Censures_get = api.model('CensuredInstances', {
@ -80,6 +81,7 @@ class Models:
self.response_model_dubious_instances = api.inherit('DubiousInstanceDetails', self.response_model_instances, {
'hesitation_reasons': fields.List(fields.String(description="The reasons instances have given for hesitating against this instance")),
'hesitation_evidence': fields.List(fields.String(description="Evidence justifying this hesitation, typically should be one or more URLs.")),
'rebuttal': fields.List(fields.String(description="Counter argument by the target instance.", example="Nuh uh!")),
'hesitation_count': fields.Integer(description="The amount of hesitations this instance has received from the reference instances"),
})
self.response_model_model_Hesitations_get = api.model('DubiousInstances', {
@ -94,6 +96,9 @@ class Models:
'reason': fields.String(required=False, description="The reason for this censure/hesitation. No profanity or hate speech allowed!", example="csam"),
'evidence': fields.String(required=False, description="The evidence for this censure/hesitation. Typically URL but can be a long form of anything you feel appropriate.", example="https://link.to/your/evidence", max_length=1000),
})
self.input_rebuttals_modify = api.model('ModifyRebuttals', {
'rebuttal': fields.String(required=False, description="The counter-argument for this censure/hesitation.", example="Nuh uh!", max_length=1000),
})
self.response_model_api_key_reset = api.model('ApiKeyReset', {
"message": fields.String(default='OK',required=True, description="The result of this operation."),
"new_key": fields.String(default=None,required=False, description="The new API key"),

View File

@ -4,6 +4,7 @@ import fediseer.apis.v1.solicitations as solicitations
import fediseer.apis.v1.endorsements as endorsements
import fediseer.apis.v1.censures as censures
import fediseer.apis.v1.hesitations as hesitations
import fediseer.apis.v1.rebuttals as rebuttals
import fediseer.apis.v1.guarantees as guarantees
import fediseer.apis.v1.activitypub as activitypub
import fediseer.apis.v1.badges as badges
@ -27,6 +28,7 @@ api.add_resource(endorsements.BatchEndorsements, "/batch/endorsements")
api.add_resource(censures.Censures, "/censures/<string:domain>")
api.add_resource(censures.CensuresGiven, "/censures_given/<string:domains_csv>")
api.add_resource(censures.BatchCensures, "/batch/censures")
api.add_resource(rebuttals.Rebuttals, "/rebuttals/<string:domain>")
api.add_resource(hesitations.Hesitations, "/hesitations/<string:domain>")
api.add_resource(hesitations.HesitationsGiven, "/hesitations_given/<string:domains_csv>")
api.add_resource(hesitations.BatchHesitations, "/batch/hesitations")

View File

@ -65,37 +65,42 @@ class CensuresGiven(Resource):
limit = None
if self.args.min_censures and self.args.min_censures != 1:
limit = None
censures = database.get_all_censures_from_censuring_id([instance.id for instance in instances])
if self.args.reasons_csv:
reasons_filter = [r.strip().lower() for r in self.args.reasons_csv.split(',')]
reasons_filter = set(reasons_filter)
if "__all_pedos__" in reasons_filter:
reasons_filter.add("csam")
reasons_filter.add("loli")
reasons_filter.add("shota")
reasons_filter.add("pedophil")
if "__all_bigots__" in reasons_filter:
reasons_filter.add("racism")
reasons_filter.add("sexism")
reasons_filter.add("transphobia")
reasons_filter.add("homophobia")
reasons_filter.add("islamophobia")
reasons_filter.add("nazi")
reasons_filter.add("fascist")
reasons_filter.add("hate speech")
reasons_filter.add("bigotry")
for c_instance in database.get_all_censured_instances_by_censuring_id(
censuring_ids = [instance.id for instance in instances],
page=self.args.page,
limit=limit,
):
censures = database.get_all_censure_reasons_for_censured_id(c_instance.id, [instance.id for instance in instances])
censure_count = len(censures)
censures = [c for c in censures if c.reason is not None]
c_instance_details = c_instance.get_details()
c_censures = [c for c in censures if c.censured_id == c_instance.id]
censure_count = len(c_censures)
r_censures = [c for c in c_censures if c.reason is not None]
if self.args.csv or self.args.domains:
c_instance_details = {"domain": c_instance.domain}
else:
c_instance_details = c_instance.get_details()
skip_instance = True
if self.args.reasons_csv:
reasons_filter = [r.strip().lower() for r in self.args.reasons_csv.split(',')]
reasons_filter = set(reasons_filter)
if "__all_pedos__" in reasons_filter:
reasons_filter.add("csam")
reasons_filter.add("loli")
reasons_filter.add("shota")
reasons_filter.add("pedophil")
if "__all_bigots__" in reasons_filter:
reasons_filter.add("racism")
reasons_filter.add("sexism")
reasons_filter.add("transphobia")
reasons_filter.add("homophobia")
reasons_filter.add("islamophobia")
reasons_filter.add("nazi")
reasons_filter.add("fascist")
reasons_filter.add("hate speech")
reasons_filter.add("bigotry")
for r in reasons_filter:
reason_filter_counter = 0
for censure in censures:
for censure in r_censures:
if r in censure.reason.lower():
reason_filter_counter += 1
if reason_filter_counter >= self.args.min_censures:
@ -105,8 +110,8 @@ class CensuresGiven(Resource):
skip_instance = False
if skip_instance:
continue
c_instance_details["censure_reasons"] = [censure.reason for censure in censures]
c_instance_details["censure_evidence"] = [censure.evidence for censure in censures if censure.evidence is not None]
c_instance_details["censure_reasons"] = [censure.reason for censure in r_censures]
c_instance_details["censure_evidence"] = [censure.evidence for censure in r_censures if censure.evidence is not None]
c_instance_details["censure_count"] = censure_count
instance_details.append(c_instance_details)
if self.args.csv:
@ -154,13 +159,17 @@ class Censures(Resource):
if p_instance != get_instance:
continue
instances.append(p_instance)
censures = database.get_all_censure_reasons_for_censured_id(instance.id, [c.id for c in instances])
rebuttals = database.get_all_rebuttals_from_source_instance_id(instance.id,[c.id for c in instances])
for c_instance in instances:
censures = database.get_all_censure_reasons_for_censured_id(instance.id, [c_instance.id])
censures = [c for c in censures if c.reason is not None]
censures = [c for c in censures if c.reason is not None and c.censuring_id == c_instance.id]
c_instance_details = c_instance.get_details()
if len(censures) > 0:
c_instance_details["censure_reasons"] = [censure.reason for censure in censures]
c_instance_details["censure_evidence"] = [censure.evidence for censure in censures if censure.evidence is not None]
rebuttals = [r.rebuttal for r in rebuttals if r.target_id == c_instance.id]
if len(rebuttals) > 0 and not database.instance_has_flag(c_instance.id,enums.InstanceFlags.MUTED):
c_instance_details["rebuttal"] = rebuttals
instance_details.append(c_instance_details)
if self.args.csv:
return {"csv": ",".join([instance["domain"] for instance in instance_details])},200

View File

@ -60,22 +60,26 @@ class Approvals(Resource):
if self.args.min_endorsements > len(instances):
raise e.BadRequest(f"You cannot request more endorsements than the amount of reference domains")
instance_details = []
endorsements = database.get_all_endorsements_from_approving_id([instance.id for instance in instances])
for e_instance in database.get_all_endorsed_instances_by_approving_id(
approving_ids=[instance.id for instance in instances],
page=self.args.page,
limit=self.args.limit,
):
endorsements = database.get_all_endorsement_reasons_for_endorsed_id(e_instance.id, [instance.id for instance in instances])
endorsement_count = len(endorsements)
endorsements = [e for e in endorsements if e.reason is not None]
e_instance_details = e_instance.get_details()
e_endorsements = [e for e in endorsements if e.endorsed_id == e_instance.id]
endorsement_count = len(e_endorsements)
r_endorsements = [e for e in e_endorsements if e.reason is not None]
if self.args.csv or self.args.domains:
e_instance_details = {"domain": e_instance.domain}
else:
e_instance_details = e_instance.get_details()
skip_instance = True
if self.args.reasons_csv:
reasons_filter = [r.strip().lower() for r in self.args.reasons_csv.split(',')]
reasons_filter = set(reasons_filter)
for r in reasons_filter:
reason_filter_counter = 0
for endorsement in endorsements:
for endorsement in r_endorsements:
if r in endorsement.reason.lower():
reason_filter_counter += 1
if reason_filter_counter >= self.args.min_endorsements:
@ -85,7 +89,7 @@ class Approvals(Resource):
skip_instance = False
if skip_instance:
continue
e_instance_details["endorsement_reasons"] = [endorsement.reason for endorsement in endorsements]
e_instance_details["endorsement_reasons"] = [endorsement.reason for endorsement in r_endorsements]
instance_details.append(e_instance_details)
if self.args.csv:
return {"csv": ",".join([instance["domain"] for instance in instance_details])},200

View File

@ -65,22 +65,26 @@ class HesitationsGiven(Resource):
limit = None
if self.args.min_hesitations and self.args.min_hesitations != 1:
limit = None
hesitations = database.get_all_hesitations_from_hesitant_id([instance.id for instance in instances])
for c_instance in database.get_all_dubious_instances_by_hesitant_id(
hesitant_ids=[instance.id for instance in instances],
page=self.args.page,
limit=limit,
):
hesitations = database.get_all_hesitation_reasons_for_dubious_id(c_instance.id, [instance.id for instance in instances])
hesitation_count = len(hesitations)
hesitations = [c for c in hesitations if c.reason is not None]
c_instance_details = c_instance.get_details()
h_hesitations = [c for c in hesitations if c.dubious_id == c_instance.id]
hesitation_count = len(h_hesitations)
r_hesitations = [c for c in h_hesitations if c.reason is not None]
if self.args.csv or self.args.domains:
c_instance_details = {"domain": c_instance.domain}
else:
c_instance_details = c_instance.get_details()
skip_instance = True
if self.args.reasons_csv:
reasons_filter = [r.strip().lower() for r in self.args.reasons_csv.split(',')]
reasons_filter = set(reasons_filter)
for r in reasons_filter:
reason_filter_counter = 0
for hesitation in hesitations:
for hesitation in r_hesitations:
if r in hesitation.reason.lower():
reason_filter_counter += 1
if reason_filter_counter >= self.args.min_hesitations:
@ -90,8 +94,8 @@ class HesitationsGiven(Resource):
skip_instance = False
if skip_instance:
continue
c_instance_details["hesitation_reasons"] = [hesitation.reason for hesitation in hesitations]
c_instance_details["hesitation_evidence"] = [hesitation.evidence for hesitation in hesitations if hesitation.evidence is not None]
c_instance_details["hesitation_reasons"] = [hesitation.reason for hesitation in r_hesitations]
c_instance_details["hesitation_evidence"] = [hesitation.evidence for hesitation in r_hesitations if hesitation.evidence is not None]
c_instance_details["hesitation_count"] = hesitation_count
instance_details.append(c_instance_details)
if self.args.csv:
@ -140,13 +144,15 @@ class Hesitations(Resource):
continue
instances.append(p_instance)
instance_details = []
hesitations = database.get_all_hesitation_reasons_for_dubious_id(instance.id, [c.id for c in instances])
rebuttals = database.get_all_rebuttals_from_source_instance_id(instance.id,[c.id for c in instances])
for c_instance in instances:
hesitations = database.get_all_hesitation_reasons_for_dubious_id(instance.id, [c_instance.id])
hesitations = [c for c in hesitations if c.reason is not None]
hesitations = [c for c in hesitations if c.reason is not None and c.hesitant_id == c_instance.id]
c_instance_details = c_instance.get_details()
if len(hesitations) > 0:
c_instance_details["hesitation_reasons"] = [hesitation.reason for hesitation in hesitations]
c_instance_details["hesitation_evidence"] = [hesitation.evidence for hesitation in hesitations if hesitation.evidence is not None]
c_instance_details["rebuttal"] = [r.rebuttal for r in rebuttals if r.target_id == c_instance.id]
instance_details.append(c_instance_details)
if self.args.csv:
return {"csv": ",".join([instance["domain"] for instance in instance_details])},200

View File

@ -0,0 +1,162 @@
from fediseer.apis.v1.base import *
from fediseer.classes.instance import Rebuttal
from fediseer.utils import sanitize_string
from fediseer.classes.reports import Report
from fediseer import enums
class Rebuttals(Resource):
decorators = [limiter.limit("45/minute"), limiter.limit("30/minute", key_func = get_request_path)]
put_parser = reqparse.RequestParser()
put_parser.add_argument("apikey", type=str, required=True, help="The sending instance's API key.", location='headers')
put_parser.add_argument("Client-Agent", default="unknown:0:unknown", type=str, required=False, help="The client name and version.", location="headers")
put_parser.add_argument("rebuttal", default=None, type=str, required=True, location="json")
@api.expect(put_parser,models.input_rebuttals_modify, validate=True)
@api.marshal_with(models.response_model_simple_response, code=200, description='Rebut Censure or Hesitation against your instance')
@api.response(400, 'Bad Request', models.response_model_error)
@api.response(401, 'Invalid API Key', models.response_model_error)
@api.response(403, 'Access Denied', models.response_model_error)
@api.response(404, 'Instance not registered', models.response_model_error)
def put(self, domain):
'''Rebut a Censure or Hesitation against your instance
Use this to provide evidence against, or to initiate discussion
'''
self.args = self.put_parser.parse_args()
if not self.args.apikey:
raise e.Unauthorized("You must provide the API key that was PM'd to your admin account")
instance = database.find_instance_by_api_key(self.args.apikey)
if not instance:
raise e.NotFound(f"No Instance found matching provided API key and domain. Have you remembered to register it?")
if len(instance.guarantors) == 0:
raise e.Forbidden("Only guaranteed instances can rebut.")
if database.instance_has_flag(instance.id,enums.InstanceFlags.RESTRICTED):
raise e.Forbidden("You cannot take this action as your instance is restricted")
if database.has_too_many_actions_per_min(instance.domain):
raise e.TooManyRequests("Your instance is doing more than 20 actions per minute. Please slow down.")
unbroken_chain, chainbreaker = database.has_unbroken_chain(instance.id)
if not unbroken_chain:
raise e.Forbidden(f"Guarantee chain for this instance has been broken. Chain ends at {chainbreaker.domain}!")
target_instance = database.find_instance_by_domain(domain)
if not target_instance:
raise e.NotFound(f"Instance {domain} is not registered on the fediseer.")
if database.get_rebuttal(target_instance.id,instance.id):
return {"message":'OK'}, 200
censure = database.get_censure(instance.id, target_instance.id)
if not censure or target_instance.visibility_censures != enums.ListVisibility.OPEN:
hesitation = database.get_hesitation(instance.id, target_instance.id)
if not hesitation or target_instance.visibility_hesitations != enums.ListVisibility.OPEN:
raise e.BadRequest(f"Either no censure or hesitation from {domain} found towards {instance.domain}, or they are not openly visible.")
rebuttal_value = self.args.rebuttal
if rebuttal_value is not None:
rebuttal_value = sanitize_string(rebuttal_value)
new_rebuttal = Rebuttal(
source_id=instance.id,
target_id=target_instance.id,
rebuttal=rebuttal_value,
)
db.session.add(new_rebuttal)
target_domain = target_instance.domain
new_report = Report(
source_domain=instance.domain,
target_domain=target_domain,
report_type=enums.ReportType.REBUTTAL,
report_activity=enums.ReportActivity.ADDED,
)
db.session.add(new_report)
db.session.commit()
logger.info(f"{instance.domain} Rebutted {domain}")
return {"message":'Changed'}, 200
decorators = [limiter.limit("20/minute", key_func = get_request_path)]
patch_parser = reqparse.RequestParser()
patch_parser.add_argument("apikey", type=str, required=True, help="The sending instance's API key.", location='headers')
patch_parser.add_argument("Client-Agent", default="unknown:0:unknown", type=str, required=False, help="The client name and version.", location="headers")
patch_parser.add_argument("rebuttal", default=None, type=str, required=False, location="json")
@api.expect(patch_parser,models.input_rebuttals_modify, validate=True)
@api.marshal_with(models.response_model_simple_response, code=200, description='Modify Rebuttal')
@api.response(400, 'Bad Request', models.response_model_error)
@api.response(401, 'Invalid API Key', models.response_model_error)
@api.response(403, 'Not Guaranteed', models.response_model_error)
@api.response(404, 'Instance not registered', models.response_model_error)
def patch(self, domain):
'''Modify a Rebuttal
'''
self.args = self.patch_parser.parse_args()
if not self.args.apikey:
raise e.Unauthorized("You must provide the API key that was PM'd to your admin account")
instance = database.find_instance_by_api_key(self.args.apikey)
if not instance:
raise e.NotFound(f"No Instance found matching provided API key and domain. Have you remembered to register it?")
if database.has_too_many_actions_per_min(instance.domain):
raise e.TooManyRequests("Your instance is doing more than 20 actions per minute. Please slow down.")
target_instance = database.find_instance_by_domain(domain=domain)
if not target_instance:
raise e.BadRequest("Instance from which to modify censure not found")
rebuttal = database.get_rebuttal(target_instance.id,instance.id)
if not rebuttal:
raise e.BadRequest(f"No Rebuttal found for {domain} from {instance.domain}")
changed = False
rebuttal_value = self.args.rebuttal
if rebuttal_value is not None:
rebuttal_value = sanitize_string(rebuttal_value)
if rebuttal.rebuttal != rebuttal_value:
rebuttal.rebuttal = rebuttal_value
changed = True
if changed is False:
return {"message":'OK'}, 200
target_domain = target_instance.domain
if instance.visibility_censures != enums.ListVisibility.OPEN:
target_domain = '[REDACTED]'
new_report = Report(
source_domain=instance.domain,
target_domain=target_domain,
report_type=enums.ReportType.REBUTTAL,
report_activity=enums.ReportActivity.MODIFIED,
)
db.session.add(new_report)
db.session.commit()
logger.info(f"{instance.domain} modified rebuttal about {domain}")
return {"message":'Changed'}, 200
decorators = [limiter.limit("20/minute", key_func = get_request_path)]
delete_parser = reqparse.RequestParser()
delete_parser.add_argument("apikey", type=str, required=True, help="The sending instance's API key.", location='headers')
delete_parser.add_argument("Client-Agent", default="unknown:0:unknown", type=str, required=False, help="The client name and version.", location="headers")
@api.expect(delete_parser)
@api.marshal_with(models.response_model_simple_response, code=200, description='Delete Rebuttal')
@api.response(400, 'Bad Request', models.response_model_error)
@api.response(401, 'Invalid API Key', models.response_model_error)
@api.response(404, 'Instance not registered', models.response_model_error)
def delete(self,domain):
'''Delete a rebuttal
'''
self.args = self.delete_parser.parse_args()
if not self.args.apikey:
raise e.Unauthorized("You must provide the API key that was PM'd to your admin account")
instance = database.find_instance_by_api_key(self.args.apikey)
if not instance:
raise e.NotFound(f"No Instance found matching provided API key and domain. Have you remembered to register it?")
target_instance = database.find_instance_by_domain(domain=domain)
if not target_instance:
raise e.BadRequest("Instance from which to withdraw censure not found")
rebuttal = database.get_rebuttal(target_instance.id,instance.id)
if not rebuttal:
return {"message":'OK'}, 200
db.session.delete(rebuttal)
target_domain = target_instance.domain
new_report = Report(
source_domain=instance.domain,
target_domain=target_domain,
report_type=enums.ReportType.REBUTTAL,
report_activity=enums.ReportActivity.DELETED,
)
db.session.add(new_report)
db.session.commit()
logger.info(f"{instance.domain} delete rebuttal about {domain}")
return {"message":'Changed'}, 200

View File

@ -72,6 +72,17 @@ class Hesitation(db.Model):
dubious_instance = db.relationship("Instance", back_populates="hesitations_received", foreign_keys=[dubious_id])
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
class Rebuttal(db.Model):
__tablename__ = "rebuttals"
__table_args__ = (UniqueConstraint('source_id', 'target_id', name='rebuttal_source_id_target_id'),)
id = db.Column(db.Integer, primary_key=True)
rebuttal = db.Column(db.Text, unique=False, nullable=False, index=False)
source_id = db.Column(db.Integer, db.ForeignKey("instances.id", ondelete="CASCADE"), nullable=False, index=True)
source_instance = db.relationship("Instance", back_populates="rebuttals_given", foreign_keys=[source_id])
target_id = db.Column(db.Integer, db.ForeignKey("instances.id", ondelete="CASCADE"), nullable=False, index=True)
target_instance = db.relationship("Instance", back_populates="rebuttals_received", foreign_keys=[target_id])
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
class Solicitation(db.Model):
__tablename__ = "solicitations"
__table_args__ = (UniqueConstraint('source_id', 'target_id', name='solicitations_source_id_target_id'),)
@ -134,6 +145,8 @@ class Instance(db.Model):
censures_received = db.relationship("Censure", back_populates="censured_instance", cascade="all, delete-orphan", foreign_keys=[Censure.censured_id])
hesitations_given = db.relationship("Hesitation", back_populates="hesitating_instance", cascade="all, delete-orphan", foreign_keys=[Hesitation.hesitant_id])
hesitations_received = db.relationship("Hesitation", back_populates="dubious_instance", cascade="all, delete-orphan", foreign_keys=[Hesitation.dubious_id])
rebuttals_given = db.relationship("Rebuttal", back_populates="source_instance", cascade="all, delete-orphan", foreign_keys=[Rebuttal.source_id])
rebuttals_received = db.relationship("Rebuttal", back_populates="target_instance", cascade="all, delete-orphan", foreign_keys=[Rebuttal.target_id])
solicitations_requested = db.relationship("Solicitation", back_populates="source_instance", cascade="all, delete-orphan", foreign_keys=[Solicitation.source_id])
solicitations_received = db.relationship("Solicitation", back_populates="target_instance", cascade="all, delete-orphan", foreign_keys=[Solicitation.target_id])
guarantees = db.relationship("Guarantee", back_populates="guarantor_instance", cascade="all, delete-orphan", foreign_keys=[Guarantee.guarantor_id])
@ -196,7 +209,6 @@ class Instance(db.Model):
if not guarantee:
return None
return guarantee.guarantor_instance
return Instance.query.filter_by(id=guarantee.guarantor_id).first()
def get_guarantor_domain(self):
guarantor = self.get_guarantor()

View File

@ -1,4 +1,4 @@
FEDISEER_VERSION = "0.20.0"
FEDISEER_VERSION = "0.22.0"
SUPPORTED_SOFTWARE = {
"lemmy",
"mastodon",

View File

@ -4,7 +4,7 @@ from sqlalchemy import func, or_, and_, not_, Boolean
from fediseer.flask import db
from fediseer.utils import hash_api_key
from sqlalchemy.orm import joinedload
from fediseer.classes.instance import Instance, Endorsement, Guarantee, RejectionRecord, Censure, Hesitation, Solicitation, InstanceFlag, InstanceTag
from fediseer.classes.instance import Instance, Endorsement, Guarantee, RejectionRecord, Censure, Hesitation, Solicitation, InstanceFlag, InstanceTag, Rebuttal
from fediseer.classes.user import Claim, User
from fediseer.classes.reports import Report
from fediseer import enums
@ -26,6 +26,9 @@ def get_all_instances(
).options(
joinedload(Instance.guarantors),
joinedload(Instance.endorsements),
joinedload(Instance.admins),
joinedload(Instance.guarantors),
joinedload(Instance.tags)
).group_by(
Instance.id
).filter(
@ -84,6 +87,9 @@ def get_all_approving_instances_by_endorsed_id(endorsed_id):
Instance.approvals,
).options(
joinedload(Instance.approvals),
joinedload(Instance.endorsements),
joinedload(Instance.admins),
joinedload(Instance.guarantors)
).filter(
Endorsement.endorsed_id == endorsed_id
).group_by(
@ -93,15 +99,20 @@ def get_all_approving_instances_by_endorsed_id(endorsed_id):
def get_all_endorsement_reasons_for_endorsed_id(endorsed_id, approving_ids):
query = Endorsement.query.filter(
and_(
Endorsement.endorsed_id == endorsed_id,
Endorsement.approving_id.in_(approving_ids),
)
Endorsement.endorsed_id == endorsed_id,
Endorsement.approving_id.in_(approving_ids),
).with_entities(
Endorsement.reason,
)
return query.all()
def get_all_endorsements_from_approving_id(approving_ids):
query = Endorsement.query.filter(
Endorsement.approving_id.in_(approving_ids)
)
return query.all()
def query_all_censured_instances_by_censuring_id(censuring_ids):
return db.session.query(
@ -110,6 +121,10 @@ def query_all_censured_instances_by_censuring_id(censuring_ids):
Instance.censures_received,
).options(
joinedload(Instance.censures_received),
joinedload(Instance.endorsements),
joinedload(Instance.approvals),
joinedload(Instance.admins),
joinedload(Instance.guarantors)
).filter(
Censure.censuring_id.in_(censuring_ids)
).group_by(
@ -146,16 +161,21 @@ def get_all_censuring_instances_by_censured_id(censured_id):
def get_all_censure_reasons_for_censured_id(censured_id, censuring_ids):
query = Censure.query.filter(
and_(
Censure.censured_id == censured_id,
Censure.censuring_id.in_(censuring_ids),
)
Censure.censured_id == censured_id,
Censure.censuring_id.in_(censuring_ids),
).with_entities(
Censure.censuring_id,
Censure.reason,
Censure.evidence,
)
return query.all()
def get_all_censures_from_censuring_id(censuring_ids):
query = Censure.query.filter(
Censure.censuring_id.in_(censuring_ids)
)
return query.all()
def query_all_dubious_instances_by_hesitant_id(hesitant_ids):
return db.session.query(
@ -164,6 +184,10 @@ def query_all_dubious_instances_by_hesitant_id(hesitant_ids):
Instance.hesitations_received,
).options(
joinedload(Instance.hesitations_received),
joinedload(Instance.endorsements),
joinedload(Instance.approvals),
joinedload(Instance.admins),
joinedload(Instance.guarantors)
).filter(
Hesitation.hesitant_id.in_(hesitant_ids)
).group_by(
@ -200,17 +224,38 @@ def get_all_hesitant_instances_by_dubious_id(dubious_id):
def get_all_hesitation_reasons_for_dubious_id(dubious_id, hesitant_ids):
query = Hesitation.query.filter(
and_(
Hesitation.dubious_id == dubious_id,
Hesitation.hesitant_id.in_(hesitant_ids),
)
Hesitation.dubious_id == dubious_id,
Hesitation.hesitant_id.in_(hesitant_ids),
).with_entities(
Hesitation.hesitant_id,
Hesitation.reason,
Hesitation.evidence,
)
return query.all()
def get_all_hesitations_from_hesitant_id(hesitant_ids):
query = Hesitation.query.filter(
Hesitation.hesitant_id.in_(hesitant_ids)
)
return query.all()
def get_rebuttal(target_instance_id, source_instance_id):
query = Rebuttal.query.filter_by(
target_id=target_instance_id,
source_id=source_instance_id,
)
return query.first()
def get_all_rebuttals_from_source_instance_id(source_instance_id, target_ids = None):
query = Rebuttal.query.filter(
Rebuttal.source_id == source_instance_id,
).with_entities(
Rebuttal.rebuttal,
Rebuttal.target_id,
)
if target_ids is not None:
query = query.filter(Rebuttal.target_id.in_(target_ids))
return query.all()
def get_all_guaranteed_instances_by_guarantor_id(guarantor_id):
query = db.session.query(

View File

@ -8,6 +8,7 @@ class ReportType(enum.Enum):
CLAIM = 4
SOLICITATION = 5
FLAG = 6
REBUTTAL = 7
class ReportActivity(enum.Enum):
ADDED = 0

View File

@ -0,0 +1 @@
ALTER TYPE reporttype ADD VALUE 'REBUTTAL';