Compare commits
6 Commits
4ab98ec12b
...
06843812c8
Author | SHA1 | Date |
---|---|---|
db0 | 06843812c8 | |
db0 | cd6375cd2c | |
db0 | f0b53af3d2 | |
Divided by Zer0 | 6d44604f99 | |
db0 | b44529242d | |
db0 | d380f34364 |
|
@ -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
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FEDISEER_VERSION = "0.20.0"
|
||||
FEDISEER_VERSION = "0.22.0"
|
||||
SUPPORTED_SOFTWARE = {
|
||||
"lemmy",
|
||||
"mastodon",
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -8,6 +8,7 @@ class ReportType(enum.Enum):
|
|||
CLAIM = 4
|
||||
SOLICITATION = 5
|
||||
FLAG = 6
|
||||
REBUTTAL = 7
|
||||
|
||||
class ReportActivity(enum.Enum):
|
||||
ADDED = 0
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ALTER TYPE reporttype ADD VALUE 'REBUTTAL';
|
Loading…
Reference in New Issue