feat: Hesitations
parent
92bc2a66df
commit
861d9f72bd
|
@ -1,5 +1,8 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
# 0.12.0
|
||||||
|
|
||||||
|
* Added hesitations, which signify mistrust against instances. A softer form of censure, to use in silencing or closer attention instead of blocking.
|
||||||
# 0.11.1
|
# 0.11.1
|
||||||
|
|
||||||
* Fixed censure filtering reasons using "AND" instead of "OR" as join
|
* Fixed censure filtering reasons using "AND" instead of "OR" as join
|
||||||
|
|
|
@ -54,9 +54,19 @@ class Models:
|
||||||
'domains': fields.List(fields.String(description="The instance domains as a list.")),
|
'domains': fields.List(fields.String(description="The instance domains as a list.")),
|
||||||
'csv': fields.String(description="The instance domains as a csv."),
|
'csv': fields.String(description="The instance domains as a csv."),
|
||||||
})
|
})
|
||||||
self.input_censures_modify = api.model('ModifyCensure', {
|
self.response_model_dubious_instances = api.inherit('DubiousInstanceDetails', self.response_model_instances, {
|
||||||
'reason': fields.String(required=False, description="The reason for this censure. No profanity or hate speech allowed!", example="csam"),
|
'hesitation_reasons': fields.List(fields.String(description="The reasons instances have given for hesitating against this instance")),
|
||||||
'evidence': fields.String(required=False, description="The evidence for this censure. Typically URL but can be a long form of anything you feel appropriate.", example="https://link.to/your/evidence", max_length=1000),
|
'hesitation_evidence': fields.List(fields.String(description="Evidence justifying this hesitation, typically should be one or more URLs.")),
|
||||||
|
'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', {
|
||||||
|
'instances': fields.List(fields.Nested(self.response_model_dubious_instances)),
|
||||||
|
'domains': fields.List(fields.String(description="The instance domains as a list.")),
|
||||||
|
'csv': fields.String(description="The instance domains as a csv."),
|
||||||
|
})
|
||||||
|
self.input_censures_modify = api.model('ModifyCensureHesitations', {
|
||||||
|
'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.response_model_api_key_reset = api.model('ApiKeyReset', {
|
self.response_model_api_key_reset = api.model('ApiKeyReset', {
|
||||||
"message": fields.String(default='OK',required=True, description="The result of this operation."),
|
"message": fields.String(default='OK',required=True, description="The result of this operation."),
|
||||||
|
|
|
@ -2,6 +2,7 @@ import fediseer.apis.v1.base as base
|
||||||
import fediseer.apis.v1.whitelist as whitelist
|
import fediseer.apis.v1.whitelist as whitelist
|
||||||
import fediseer.apis.v1.endorsements as endorsements
|
import fediseer.apis.v1.endorsements as endorsements
|
||||||
import fediseer.apis.v1.censures as censures
|
import fediseer.apis.v1.censures as censures
|
||||||
|
import fediseer.apis.v1.hesitations as hesitations
|
||||||
import fediseer.apis.v1.guarantees as guarantees
|
import fediseer.apis.v1.guarantees as guarantees
|
||||||
import fediseer.apis.v1.activitypub as activitypub
|
import fediseer.apis.v1.activitypub as activitypub
|
||||||
import fediseer.apis.v1.badges as badges
|
import fediseer.apis.v1.badges as badges
|
||||||
|
@ -19,6 +20,8 @@ api.add_resource(endorsements.Endorsements, "/endorsements/<string:domain>")
|
||||||
api.add_resource(endorsements.Approvals, "/approvals/<string:domains_csv>")
|
api.add_resource(endorsements.Approvals, "/approvals/<string:domains_csv>")
|
||||||
api.add_resource(censures.Censures, "/censures/<string:domain>")
|
api.add_resource(censures.Censures, "/censures/<string:domain>")
|
||||||
api.add_resource(censures.CensuresGiven, "/censures_given/<string:domains_csv>")
|
api.add_resource(censures.CensuresGiven, "/censures_given/<string:domains_csv>")
|
||||||
|
api.add_resource(hesitations.Hesitations, "/hesitations/<string:domain>")
|
||||||
|
api.add_resource(hesitations.HesitationsGiven, "/hesitations_given/<string:domains_csv>")
|
||||||
api.add_resource(guarantees.Guarantors, "/guarantors/<string:domain>")
|
api.add_resource(guarantees.Guarantors, "/guarantors/<string:domain>")
|
||||||
api.add_resource(guarantees.Guarantees, "/guarantees/<string:domain>")
|
api.add_resource(guarantees.Guarantees, "/guarantees/<string:domain>")
|
||||||
api.add_resource(badges.GuaranteeBadge, "/badges/guarantees/<string:domain>.svg")
|
api.add_resource(badges.GuaranteeBadge, "/badges/guarantees/<string:domain>.svg")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from fediseer.apis.v1.base import *
|
from fediseer.apis.v1.base import *
|
||||||
from fediseer.classes.instance import Censure,Endorsement
|
from fediseer.classes.instance import Censure
|
||||||
from fediseer.utils import sanitize_string
|
from fediseer.utils import sanitize_string
|
||||||
from fediseer.classes.reports import Report
|
from fediseer.classes.reports import Report
|
||||||
from fediseer import enums
|
from fediseer import enums
|
||||||
|
@ -116,7 +116,7 @@ class Censures(Resource):
|
||||||
|
|
||||||
|
|
||||||
@api.expect(put_parser,models.input_censures_modify, validate=True)
|
@api.expect(put_parser,models.input_censures_modify, validate=True)
|
||||||
@api.marshal_with(models.response_model_simple_response, code=200, description='Endorse Instance')
|
@api.marshal_with(models.response_model_simple_response, code=200, description='Censure Instance')
|
||||||
@api.response(400, 'Bad Request', models.response_model_error)
|
@api.response(400, 'Bad Request', models.response_model_error)
|
||||||
@api.response(401, 'Invalid API Key', 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(403, 'Not Guaranteed', models.response_model_error)
|
||||||
|
@ -181,7 +181,7 @@ class Censures(Resource):
|
||||||
|
|
||||||
|
|
||||||
@api.expect(patch_parser,models.input_censures_modify, validate=True)
|
@api.expect(patch_parser,models.input_censures_modify, validate=True)
|
||||||
@api.marshal_with(models.response_model_simple_response, code=200, description='Endorse Instance')
|
@api.marshal_with(models.response_model_simple_response, code=200, description='Modify Instance Censure')
|
||||||
@api.response(400, 'Bad Request', models.response_model_error)
|
@api.response(400, 'Bad Request', models.response_model_error)
|
||||||
@api.response(401, 'Invalid API Key', 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(403, 'Not Guaranteed', models.response_model_error)
|
||||||
|
@ -233,7 +233,7 @@ class Censures(Resource):
|
||||||
delete_parser.add_argument("Client-Agent", default="unknown:0:unknown", type=str, required=False, help="The client name and version.", 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.expect(delete_parser)
|
||||||
@api.marshal_with(models.response_model_simple_response, code=200, description='Withdraw Instance Endorsement')
|
@api.marshal_with(models.response_model_simple_response, code=200, description='Withdraw Instance Censure')
|
||||||
@api.response(400, 'Bad Request', models.response_model_error)
|
@api.response(400, 'Bad Request', models.response_model_error)
|
||||||
@api.response(401, 'Invalid API Key', models.response_model_error)
|
@api.response(401, 'Invalid API Key', models.response_model_error)
|
||||||
@api.response(404, 'Instance not registered', models.response_model_error)
|
@api.response(404, 'Instance not registered', models.response_model_error)
|
||||||
|
|
|
@ -0,0 +1,250 @@
|
||||||
|
from fediseer.apis.v1.base import *
|
||||||
|
from fediseer.classes.instance import Hesitation
|
||||||
|
from fediseer.utils import sanitize_string
|
||||||
|
from fediseer.classes.reports import Report
|
||||||
|
from fediseer import enums
|
||||||
|
|
||||||
|
class HesitationsGiven(Resource):
|
||||||
|
get_parser = reqparse.RequestParser()
|
||||||
|
get_parser.add_argument("Client-Agent", default="unknown:0:unknown", type=str, required=False, help="The client name and version.", location="headers")
|
||||||
|
get_parser.add_argument("csv", required=False, type=bool, help="Set to true to return just the domains as a csv. Mutually exclusive with domains", location="args")
|
||||||
|
get_parser.add_argument("domains", required=False, type=bool, help="Set to true to return just the domains as a list. Mutually exclusive with csv", location="args")
|
||||||
|
get_parser.add_argument("min_hesitations", required=False, default=1, type=int, help="Limit to this amount of hesitations of more", location="args")
|
||||||
|
get_parser.add_argument("reasons_csv", required=False, type=str, help="Only retrieve hesitations where their reasons include any of the text in this csv", location="args")
|
||||||
|
|
||||||
|
@api.expect(get_parser)
|
||||||
|
@cache.cached(timeout=10, query_string=True)
|
||||||
|
@api.marshal_with(models.response_model_model_Hesitations_get, code=200, description='Instances', skip_none=True)
|
||||||
|
@api.response(404, 'Instance not registered', models.response_model_error)
|
||||||
|
def get(self, domains_csv):
|
||||||
|
'''Display all hesitations given out by one or more domains
|
||||||
|
You can pass a comma-separated list of domain names
|
||||||
|
and the results will be a set of all their hesitations together.
|
||||||
|
'''
|
||||||
|
self.args = self.get_parser.parse_args()
|
||||||
|
domains_list = domains_csv.split(',')
|
||||||
|
instances = database.find_multiple_instance_by_domains(domains_list)
|
||||||
|
if not instances:
|
||||||
|
raise e.NotFound(f"No Instances found matching any of the provided domains. Have you remembered to register them?")
|
||||||
|
if self.args.min_hesitations > len(domains_list):
|
||||||
|
raise e.BadRequest(f"You cannot request more hesitations than the amount of reference domains")
|
||||||
|
instance_details = []
|
||||||
|
for c_instance in database.get_all_dubious_instances_by_hesitant_id([instance.id for instance in instances]):
|
||||||
|
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()
|
||||||
|
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:
|
||||||
|
if r in hesitation.reason.lower():
|
||||||
|
reason_filter_counter += 1
|
||||||
|
if reason_filter_counter >= self.args.min_hesitations:
|
||||||
|
skip_instance = False
|
||||||
|
break
|
||||||
|
elif hesitation_count >= self.args.min_hesitations:
|
||||||
|
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_count"] = hesitation_count
|
||||||
|
instance_details.append(c_instance_details)
|
||||||
|
if self.args.csv:
|
||||||
|
return {"csv": ",".join([instance["domain"] for instance in instance_details])},200
|
||||||
|
if self.args.domains:
|
||||||
|
return {"domains": [instance["domain"] for instance in instance_details]},200
|
||||||
|
|
||||||
|
return {"instances": instance_details},200
|
||||||
|
|
||||||
|
class Hesitations(Resource):
|
||||||
|
get_parser = reqparse.RequestParser()
|
||||||
|
get_parser.add_argument("Client-Agent", default="unknown:0:unknown", type=str, required=False, help="The client name and version.", location="headers")
|
||||||
|
get_parser.add_argument("csv", required=False, type=bool, help="Set to true to return just the domains as a csv. Mutually exclusive with domains", location="args")
|
||||||
|
get_parser.add_argument("domains", required=False, type=bool, help="Set to true to return just the domains as a list. Mutually exclusive with csv", location="args")
|
||||||
|
|
||||||
|
@api.expect(get_parser)
|
||||||
|
@cache.cached(timeout=10, query_string=True)
|
||||||
|
@api.marshal_with(models.response_model_model_Hesitations_get, code=200, description='Instances', skip_none=True)
|
||||||
|
@api.response(404, 'Instance not registered', models.response_model_error)
|
||||||
|
def get(self, domain):
|
||||||
|
'''Display all hesitations received by a specific domain
|
||||||
|
'''
|
||||||
|
self.args = self.get_parser.parse_args()
|
||||||
|
instance = database.find_instance_by_domain(domain)
|
||||||
|
if not instance:
|
||||||
|
raise e.NotFound(f"No Instance found matching provided domain. Have you remembered to register it?")
|
||||||
|
instance_details = []
|
||||||
|
for c_instance in database.get_all_hesitant_instances_by_dubious_id(instance.id):
|
||||||
|
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]
|
||||||
|
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]
|
||||||
|
instance_details.append(c_instance_details)
|
||||||
|
if self.args.csv:
|
||||||
|
return {"csv": ",".join([instance["domain"] for instance in instance_details])},200
|
||||||
|
if self.args.domains:
|
||||||
|
return {"domains": [instance["domain"] for instance in instance_details]},200
|
||||||
|
return {"instances": instance_details},200
|
||||||
|
|
||||||
|
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("reason", default=None, type=str, required=False, location="json")
|
||||||
|
put_parser.add_argument("evidence", default=None, type=str, required=False, location="json")
|
||||||
|
|
||||||
|
|
||||||
|
@api.expect(put_parser,models.input_censures_modify, validate=True)
|
||||||
|
@api.marshal_with(models.response_model_simple_response, code=200, description='Mistrust Instance')
|
||||||
|
@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 put(self, domain):
|
||||||
|
'''Hesitate against an instance
|
||||||
|
A hesitation signifies a mistrust from your instance to how that instance is being run.
|
||||||
|
'''
|
||||||
|
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 hesitation others.")
|
||||||
|
if instance.domain == domain:
|
||||||
|
raise e.BadRequest("You're a mad lad, but you can't hesitation yourself.")
|
||||||
|
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, nodeinfo, admin_usernames = ensure_instance_registered(domain, allow_unreachable=True)
|
||||||
|
if not target_instance:
|
||||||
|
raise e.NotFound(f"Something went wrong trying to register this instance.")
|
||||||
|
if not target_instance:
|
||||||
|
raise e.BadRequest("Instance to hesitation not found")
|
||||||
|
if database.get_endorsement(target_instance.id,instance.id):
|
||||||
|
raise e.BadRequest("You can't hesitate against an instance you've endorsed! Please withdraw the endorsement first.")
|
||||||
|
if database.get_hesitation(target_instance.id,instance.id):
|
||||||
|
return {"message":'OK'}, 200
|
||||||
|
|
||||||
|
reason = self.args.reason
|
||||||
|
if reason is not None:
|
||||||
|
reason = sanitize_string(reason)
|
||||||
|
evidence = self.args.evidence
|
||||||
|
if evidence is not None:
|
||||||
|
evidence = sanitize_string(evidence)
|
||||||
|
new_hesitation = Hesitation(
|
||||||
|
hesitant_id=instance.id,
|
||||||
|
dubious_id=target_instance.id,
|
||||||
|
reason=reason,
|
||||||
|
evidence=evidence,
|
||||||
|
)
|
||||||
|
db.session.add(new_hesitation)
|
||||||
|
new_report = Report(
|
||||||
|
source_domain=instance.domain,
|
||||||
|
target_domain=target_instance.domain,
|
||||||
|
report_type=enums.ReportType.HESITATION,
|
||||||
|
report_activity=enums.ReportActivity.ADDED,
|
||||||
|
)
|
||||||
|
db.session.add(new_report)
|
||||||
|
db.session.commit()
|
||||||
|
logger.info(f"{instance.domain} hesitated against {domain}")
|
||||||
|
return {"message":'Changed'}, 200
|
||||||
|
|
||||||
|
|
||||||
|
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("reason", default=None, type=str, required=False, location="json")
|
||||||
|
patch_parser.add_argument("evidence", default=None, type=str, required=False, location="json")
|
||||||
|
|
||||||
|
|
||||||
|
@api.expect(patch_parser,models.input_censures_modify, validate=True)
|
||||||
|
@api.marshal_with(models.response_model_simple_response, code=200, description='Modify Instance Hesitation')
|
||||||
|
@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 an instance's Hesitation
|
||||||
|
'''
|
||||||
|
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?")
|
||||||
|
target_instance = database.find_instance_by_domain(domain=domain)
|
||||||
|
if not target_instance:
|
||||||
|
raise e.BadRequest("Instance from which to modify hesitation not found")
|
||||||
|
hesitation = database.get_hesitation(target_instance.id,instance.id)
|
||||||
|
if not hesitation:
|
||||||
|
raise e.BadRequest(f"No hesitation found for {domain} from {instance.domain}")
|
||||||
|
changed = False
|
||||||
|
reason = self.args.reason
|
||||||
|
if reason is not None:
|
||||||
|
reason = sanitize_string(reason)
|
||||||
|
if hesitation.reason != reason:
|
||||||
|
hesitation.reason = reason
|
||||||
|
changed = True
|
||||||
|
evidence = self.args.evidence
|
||||||
|
if evidence is not None:
|
||||||
|
evidence = sanitize_string(evidence)
|
||||||
|
if hesitation.evidence != evidence:
|
||||||
|
hesitation.evidence = evidence
|
||||||
|
changed = True
|
||||||
|
if changed is False:
|
||||||
|
return {"message":'OK'}, 200
|
||||||
|
new_report = Report(
|
||||||
|
source_domain=instance.domain,
|
||||||
|
target_domain=target_instance.domain,
|
||||||
|
report_type=enums.ReportType.HESITATION,
|
||||||
|
report_activity=enums.ReportActivity.MODIFIED,
|
||||||
|
)
|
||||||
|
db.session.add(new_report)
|
||||||
|
db.session.commit()
|
||||||
|
logger.info(f"{instance.domain} Modfied hesitation for {domain}")
|
||||||
|
return {"message":'Changed'}, 200
|
||||||
|
|
||||||
|
|
||||||
|
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='Withdraw Instance Hesitation')
|
||||||
|
@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):
|
||||||
|
'''Withdraw an instance hesitation
|
||||||
|
'''
|
||||||
|
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 hesitation not found")
|
||||||
|
hesitation = database.get_hesitation(target_instance.id,instance.id)
|
||||||
|
if not hesitation:
|
||||||
|
return {"message":'OK'}, 200
|
||||||
|
db.session.delete(hesitation)
|
||||||
|
new_report = Report(
|
||||||
|
source_domain=instance.domain,
|
||||||
|
target_domain=target_instance.domain,
|
||||||
|
report_type=enums.ReportType.HESITATION,
|
||||||
|
report_activity=enums.ReportActivity.DELETED,
|
||||||
|
)
|
||||||
|
db.session.add(new_report)
|
||||||
|
db.session.commit()
|
||||||
|
logger.info(f"{instance.domain} Withdrew hesitation from {domain}")
|
||||||
|
return {"message":'Changed'}, 200
|
|
@ -54,5 +54,4 @@ class Report(Resource):
|
||||||
'created': r.created.isoformat() + 'Z',
|
'created': r.created.isoformat() + 'Z',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
logger.debug(report_response)
|
|
||||||
return report_response,200
|
return report_response,200
|
||||||
|
|
|
@ -60,6 +60,18 @@ class Censure(db.Model):
|
||||||
censured_instance = db.relationship("Instance", back_populates="censures_received", foreign_keys=[censured_id])
|
censured_instance = db.relationship("Instance", back_populates="censures_received", foreign_keys=[censured_id])
|
||||||
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||||
|
|
||||||
|
class Hesitation(db.Model):
|
||||||
|
__tablename__ = "hesitations"
|
||||||
|
__table_args__ = (UniqueConstraint('hesitant_id', 'dubious_id', name='hesitations_hesitant_id_dubious_id'),)
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
reason = db.Column(db.String(255), unique=False, nullable=True, index=False)
|
||||||
|
evidence = db.Column(db.Text, unique=False, nullable=True, index=False)
|
||||||
|
hesitant_id = db.Column(db.Integer, db.ForeignKey("instances.id", ondelete="CASCADE"), nullable=False)
|
||||||
|
hesitating_instance = db.relationship("Instance", back_populates="hesitations_given", foreign_keys=[hesitant_id])
|
||||||
|
dubious_id = db.Column(db.Integer, db.ForeignKey("instances.id", ondelete="CASCADE"), nullable=False)
|
||||||
|
dubious_instance = db.relationship("Instance", back_populates="hesitations_received", foreign_keys=[dubious_id])
|
||||||
|
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class Instance(db.Model):
|
class Instance(db.Model):
|
||||||
__tablename__ = "instances"
|
__tablename__ = "instances"
|
||||||
|
@ -80,6 +92,8 @@ class Instance(db.Model):
|
||||||
endorsements = db.relationship("Endorsement", back_populates="endorsed_instance", cascade="all, delete-orphan", foreign_keys=[Endorsement.endorsed_id])
|
endorsements = db.relationship("Endorsement", back_populates="endorsed_instance", cascade="all, delete-orphan", foreign_keys=[Endorsement.endorsed_id])
|
||||||
censures_given = db.relationship("Censure", back_populates="censuring_instance", cascade="all, delete-orphan", foreign_keys=[Censure.censuring_id])
|
censures_given = db.relationship("Censure", back_populates="censuring_instance", cascade="all, delete-orphan", foreign_keys=[Censure.censuring_id])
|
||||||
censures_received = db.relationship("Censure", back_populates="censured_instance", cascade="all, delete-orphan", foreign_keys=[Censure.censured_id])
|
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])
|
||||||
guarantees = db.relationship("Guarantee", back_populates="guarantor_instance", cascade="all, delete-orphan", foreign_keys=[Guarantee.guarantor_id])
|
guarantees = db.relationship("Guarantee", back_populates="guarantor_instance", cascade="all, delete-orphan", foreign_keys=[Guarantee.guarantor_id])
|
||||||
guarantors = db.relationship("Guarantee", back_populates="guaranteed_instance", cascade="all, delete-orphan", foreign_keys=[Guarantee.guaranteed_id])
|
guarantors = db.relationship("Guarantee", back_populates="guaranteed_instance", cascade="all, delete-orphan", foreign_keys=[Guarantee.guaranteed_id])
|
||||||
rejections = db.relationship("RejectionRecord", back_populates="rejector_instance", cascade="all, delete-orphan", foreign_keys=[RejectionRecord.rejector_id])
|
rejections = db.relationship("RejectionRecord", back_populates="rejector_instance", cascade="all, delete-orphan", foreign_keys=[RejectionRecord.rejector_id])
|
||||||
|
|
|
@ -8,7 +8,7 @@ from sqlalchemy.orm import noload
|
||||||
from fediseer.flask import db, SQLITE_MODE
|
from fediseer.flask import db, SQLITE_MODE
|
||||||
from fediseer.utils import hash_api_key
|
from fediseer.utils import hash_api_key
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
from fediseer.classes.instance import Instance, Endorsement, Guarantee, RejectionRecord, Censure
|
from fediseer.classes.instance import Instance, Endorsement, Guarantee, RejectionRecord, Censure, Hesitation
|
||||||
from fediseer.classes.user import Claim, User
|
from fediseer.classes.user import Claim, User
|
||||||
from fediseer.classes.reports import Report
|
from fediseer.classes.reports import Report
|
||||||
from fediseer import enums
|
from fediseer import enums
|
||||||
|
@ -106,6 +106,47 @@ def get_all_censure_reasons_for_censured_id(censured_id, censuring_ids):
|
||||||
return query.all()
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_dubious_instances_by_hesitant_id(hesitant_ids):
|
||||||
|
query = db.session.query(
|
||||||
|
Instance
|
||||||
|
).outerjoin(
|
||||||
|
Instance.hesitations_received,
|
||||||
|
).options(
|
||||||
|
joinedload(Instance.hesitations_received),
|
||||||
|
).filter(
|
||||||
|
Hesitation.hesitant_id.in_(hesitant_ids)
|
||||||
|
).group_by(
|
||||||
|
Instance.id
|
||||||
|
)
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
def get_all_hesitant_instances_by_dubious_id(dubious_id):
|
||||||
|
query = db.session.query(
|
||||||
|
Instance
|
||||||
|
).outerjoin(
|
||||||
|
Instance.hesitations_given,
|
||||||
|
).options(
|
||||||
|
joinedload(Instance.hesitations_given),
|
||||||
|
).filter(
|
||||||
|
Hesitation.dubious_id == dubious_id
|
||||||
|
).group_by(
|
||||||
|
Instance.id
|
||||||
|
)
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
).with_entities(
|
||||||
|
Hesitation.reason,
|
||||||
|
Hesitation.evidence,
|
||||||
|
)
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_guaranteed_instances_by_guarantor_id(guarantor_id):
|
def get_all_guaranteed_instances_by_guarantor_id(guarantor_id):
|
||||||
query = db.session.query(
|
query = db.session.query(
|
||||||
|
@ -231,6 +272,13 @@ def get_censure(instance_id, censuring_instance_id):
|
||||||
)
|
)
|
||||||
return query.first()
|
return query.first()
|
||||||
|
|
||||||
|
def get_hesitation(instance_id, hesitant_instance_id):
|
||||||
|
query = Hesitation.query.filter_by(
|
||||||
|
dubious_id=instance_id,
|
||||||
|
hesitant_id=hesitant_instance_id,
|
||||||
|
)
|
||||||
|
return query.first()
|
||||||
|
|
||||||
def has_recent_endorsement(instance_id):
|
def has_recent_endorsement(instance_id):
|
||||||
query = Endorsement.query.filter(
|
query = Endorsement.query.filter(
|
||||||
Endorsement.endorsed_id == instance_id,
|
Endorsement.endorsed_id == instance_id,
|
||||||
|
|
|
@ -4,7 +4,7 @@ class ReportType(enum.Enum):
|
||||||
GUARANTEE = 0
|
GUARANTEE = 0
|
||||||
ENDORSEMENT = 1
|
ENDORSEMENT = 1
|
||||||
CENSURE = 2
|
CENSURE = 2
|
||||||
RESTRICTION = 3
|
HESITATION = 3
|
||||||
|
|
||||||
class ReportActivity(enum.Enum):
|
class ReportActivity(enum.Enum):
|
||||||
ADDED = 0
|
ADDED = 0
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TYPE reporttype
|
||||||
|
RENAME VALUE 'RESTRICTION' TO 'HESITATION';
|
Loading…
Reference in New Issue