From 85b19dc50cea898181258af9bdd0d5950c325f53 Mon Sep 17 00:00:00 2001 From: Divided by Zer0 Date: Tue, 26 Sep 2023 12:06:30 +0200 Subject: [PATCH] Feat: Instance flags (#36) --- CHANGELOG.md | 4 + fediseer/apis/models/v1.py | 9 ++ fediseer/apis/v1/__init__.py | 2 + fediseer/apis/v1/admin.py | 148 +++++++++++++++++++++++++++++++ fediseer/apis/v1/censures.py | 4 +- fediseer/apis/v1/endorsements.py | 4 +- fediseer/apis/v1/guarantees.py | 13 ++- fediseer/apis/v1/hesitations.py | 4 +- fediseer/apis/v1/whitelist.py | 16 +++- fediseer/classes/instance.py | 24 ++++- fediseer/consts.py | 2 +- fediseer/database/functions.py | 18 +++- fediseer/enums.py | 5 ++ sql_statements/0.18.0.txt | 1 + 14 files changed, 241 insertions(+), 13 deletions(-) create mode 100644 fediseer/apis/v1/admin.py create mode 100644 sql_statements/0.18.0.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 50e1f2c..50bcb9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +# 0.18.0 + +* Added instance flags + # 0.17.1 * Prevent endorsement PMs being sent when visibility is private diff --git a/fediseer/apis/models/v1.py b/fediseer/apis/models/v1.py index 583c6fe..c0e2c06 100644 --- a/fediseer/apis/models/v1.py +++ b/fediseer/apis/models/v1.py @@ -42,10 +42,15 @@ class Models: 'moderators': fields.Integer(required=False, default=None, description="The count of community moderators in this instance as reported by its admins."), 'state': fields.String(required=True, enum=[e.name for e in enums.InstanceState], description="The state of the instance as seen from the fediseer."), }) + self.response_model_flag_details = api.model('FlagDetails', { + 'flag': fields.String(required=True, enum=[e.name for e in enums.InstanceFlags], description="The type of flag"), + 'comment': fields.String(required=False, description="A comment explaining this flag", example="admin"), + }) self.response_model_instances_visibility = api.inherit('InstanceVisibilityDetails', self.response_model_instances, { 'visibility_endorsements': fields.String(required=True, enum=[e.name for e in enums.ListVisibility], description="If OPEN, this instance allows anyone to read this instance's endorsements. When set to ENDORSED, only endorsed instances can see their endorsements. If set to PRIVATE allow this instance's own admins can see their endorsements."), 'visibility_censures': fields.String(required=True, enum=[e.name for e in enums.ListVisibility], description="If OPEN, this instance allows anyone to read this instance's censures. When set to ENDORSED, only endorsed instances can see their censures. If set to PRIVATE allow this instance's own admins can see their censures."), 'visibility_hesitations': fields.String(required=True, enum=[e.name for e in enums.ListVisibility], description="If OPEN, this instance allows anyone to read this instance's hesitations. When set to ENDORSED, only endorsed instances can see their hesitations. If set to PRIVATE allow this instance's own admins can see their hesitations."), + 'flags': fields.List(fields.Nested(self.response_model_flag_details)), }) self.response_model_model_Whitelist_get = api.model('WhitelistedInstances', { 'instances': fields.List(fields.Nested(self.response_model_instances_visibility)), @@ -126,3 +131,7 @@ class Models: 'domains': fields.List(fields.String(description="The instance domains as a list.")), 'csv': fields.String(description="The instance domains as a csv."), }) + self.input_flag_modify = api.model('FlagModify', { + 'flag': fields.String(required=True, enum=[e.name for e in enums.InstanceFlags], description="The type of flag to apply"), + 'comment': fields.String(max_length=255, required=False, description="A comment explaining this flag", example="reasons"), + }) diff --git a/fediseer/apis/v1/__init__.py b/fediseer/apis/v1/__init__.py index 333a311..49d42dd 100644 --- a/fediseer/apis/v1/__init__.py +++ b/fediseer/apis/v1/__init__.py @@ -9,6 +9,7 @@ import fediseer.apis.v1.activitypub as activitypub import fediseer.apis.v1.badges as badges import fediseer.apis.v1.find as find import fediseer.apis.v1.report as report +import fediseer.apis.v1.admin as admin from fediseer.apis.v1.base import api api.add_resource(base.Suspicions, "/instances") @@ -28,4 +29,5 @@ api.add_resource(guarantees.Guarantors, "/guarantors/") api.add_resource(guarantees.Guarantees, "/guarantees/") api.add_resource(badges.GuaranteeBadge, "/badges/guarantees/.svg") api.add_resource(badges.EndorsementBadge, "/badges/endorsements/.svg") +api.add_resource(admin.Flag, "/admin/flags/") api.add_resource(report.Report, "/reports") diff --git a/fediseer/apis/v1/admin.py b/fediseer/apis/v1/admin.py new file mode 100644 index 0000000..2455449 --- /dev/null +++ b/fediseer/apis/v1/admin.py @@ -0,0 +1,148 @@ +from fediseer.apis.v1.base import * +from fediseer.messaging import activitypub_pm +from fediseer import enums +from fediseer.classes.reports import Report +from fediseer.register import ensure_instance_registered +from fediseer.classes.instance import InstanceFlag + +class Flag(Resource): + + 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("comment", required=False, type=str, help="provide a reasoning for this flag", location="json") + put_parser.add_argument("flag", required=True, type=str, help="The flag to apply", location="json") + + + @api.expect(put_parser,models.input_flag_modify, validate=True) + @api.marshal_with(models.response_model_simple_response, code=200, description='Action Result') + @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) + + def put(self, domain): + '''Flag an instance + ''' + 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 the admin account") + user = database.find_user_by_api_key(self.args.apikey) + if not user: + raise e.Forbidden("Only a fediseer admin can modify instance flags") + if user.account != "@fediseer@fediseer.com": + raise e.Forbidden("Only a fediseer admin can modify instance flags") + admin_instance = database.find_instance_by_user(user) + target_instance, instance_info = ensure_instance_registered(domain) + flag = enums.InstanceFlags[self.args.flag] + if database.instance_has_flag(target_instance.id,flag): + return {"message": "OK"},200 + new_flag = InstanceFlag( + instance_id = target_instance.id, + flag = flag, + comment = self.args.comment, + ) + db.session.add(new_flag) + if flag == enums.InstanceFlags.RESTRICTED and not database.instance_has_flag(target_instance.id,enums.InstanceFlags.MUTED): + muted_flag = InstanceFlag( + instance_id = target_instance.id, + flag = enums.InstanceFlags.MUTED, + comment = "Restricted with reason: " + self.args.comment, + ) + db.session.add(muted_flag) + # Sactioned instances get no visibility + if flag in [enums.InstanceFlags.MUTED,enums.InstanceFlags.RESTRICTED]: + target_instance.visibility_censures = enums.ListVisibility.PRIVATE + target_instance.visibility_endorsements = enums.ListVisibility.PRIVATE + target_instance.visibility_hesitations = enums.ListVisibility.PRIVATE + new_report = Report( + source_domain=admin_instance.domain, + target_domain=target_instance.domain, + report_type=enums.ReportType.FLAG, + report_activity=enums.ReportActivity.ADDED, + ) + db.session.add(new_report) + db.session.commit() + 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("comment", required=False, type=str, help="provide a reasoning for this flag", location="json") + patch_parser.add_argument("flag", required=False, type=str, help="The flag to apply", location="json") + + + @api.expect(patch_parser,models.input_flag_modify, validate=True) + @api.marshal_with(models.response_model_simple_response, code=200, description='Action Result') + @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 or flag not found', models.response_model_error) + def patch(self, domain): + '''Modify an instance's flag + ''' + 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 the admin account") + user = database.find_user_by_api_key(self.args.apikey) + if not user: + raise e.Forbidden("Only a fediseer admin can modify instance flags") + if user.account != "@fediseer@fediseer.com": + raise e.Forbidden("Only a fediseer admin can modify instance flags") + admin_instance = database.find_instance_by_user(user) + target_instance, instance_info = ensure_instance_registered(domain) + flag = enums.InstanceFlags[self.args.flag] + existing_flag = database.get_instance_flag(target_instance.id,flag) + if not existing_flag: + raise e.NotFound(f"{flag.name} not found in {domain}") + if existing_flag.comment == self.args.comment: + return {"message": "OK"},200 + existing_flag.comment = self.args.comment, + new_report = Report( + source_domain=admin_instance.domain, + target_domain=target_instance.domain, + report_type=enums.ReportType.FLAG, + report_activity=enums.ReportActivity.MODIFIED, + ) + db.session.add(new_report) + db.session.commit() + 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") + delete_parser.add_argument("flag", required=False, type=str, help="The flag to delete", location="json") + + + @api.expect(delete_parser) + @api.marshal_with(models.response_model_simple_response, code=200, description='Instances', skip_none=True) + @api.response(400, 'Bad Request', models.response_model_error) + @api.response(401, 'Invalid API Key', models.response_model_error) + @api.response(403, 'Forbidden', models.response_model_error) + def delete(self, domain): + '''Delete an instance's flag + ''' + 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 the admin account") + user = database.find_user_by_api_key(self.args.apikey) + if not user: + raise e.Forbidden("Only a fediseer admin can delete instance flags") + if user.account != "@fediseer@fediseer.com": + raise e.Forbidden("Only a fediseer admin can delete instance flags") + admin_instance = database.find_instance_by_user(user) + target_instance, instance_info = ensure_instance_registered(domain) + flag = enums.InstanceFlags[self.args.flag] + existing_flag = database.get_instance_flag(target_instance.id,flag) + if not existing_flag: + return {"message": "OK"},200 + db.session.delete(existing_flag) + new_report = Report( + source_domain=admin_instance.domain, + target_domain=target_instance.domain, + report_type=enums.ReportType.FLAG, + report_activity=enums.ReportActivity.DELETED, + ) + db.session.add(new_report) + db.session.commit() + return {"message": "Changed"},200 \ No newline at end of file diff --git a/fediseer/apis/v1/censures.py b/fediseer/apis/v1/censures.py index 108016c..0361eab 100644 --- a/fediseer/apis/v1/censures.py +++ b/fediseer/apis/v1/censures.py @@ -165,7 +165,7 @@ class Censures(Resource): @api.marshal_with(models.response_model_simple_response, code=200, description='Censure 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(403, 'Access Denied', models.response_model_error) @api.response(404, 'Instance not registered', models.response_model_error) def put(self, domain): '''Censure an instance @@ -179,6 +179,8 @@ class Censures(Resource): 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 censure others.") + if database.instance_has_flag(instance.id,enums.InstanceFlags.RESTRICTED): + raise e.Forbidden("You cannot take this action as your instance is restricted") if instance.domain == domain: raise e.BadRequest("You're a mad lad, but you can't censure yourself.") if database.has_too_many_actions_per_min(instance.domain): diff --git a/fediseer/apis/v1/endorsements.py b/fediseer/apis/v1/endorsements.py index abed1f5..5a203bd 100644 --- a/fediseer/apis/v1/endorsements.py +++ b/fediseer/apis/v1/endorsements.py @@ -144,7 +144,7 @@ class Endorsements(Resource): @api.marshal_with(models.response_model_simple_response, code=200, description='Endorse 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(403, 'Access Denied', models.response_model_error) @api.response(404, 'Instance not registered', models.response_model_error) def put(self, domain): '''Endorse an instance @@ -158,6 +158,8 @@ class Endorsements(Resource): 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 endorse others.") + if database.instance_has_flag(instance.id,enums.InstanceFlags.RESTRICTED): + raise e.Forbidden("You cannot take this action as your instance is restricted") if instance.domain == domain: raise e.BadRequest("Nice try, but you can't endorse yourself.") if database.has_too_many_actions_per_min(instance.domain): diff --git a/fediseer/apis/v1/guarantees.py b/fediseer/apis/v1/guarantees.py index cb7ccaf..a615d97 100644 --- a/fediseer/apis/v1/guarantees.py +++ b/fediseer/apis/v1/guarantees.py @@ -1,5 +1,5 @@ from fediseer.apis.v1.base import * -from fediseer.classes.instance import Guarantee, RejectionRecord, Solicitation +from fediseer.classes.instance import Guarantee, RejectionRecord, Solicitation, InstanceFlag from fediseer.classes.reports import Report from fediseer import enums from fediseer.register import ensure_instance_registered @@ -69,7 +69,7 @@ class Guarantees(Resource): @api.marshal_with(models.response_model_simple_response, code=200, description='Endorse Instance') @api.response(400, 'Bad Request', models.response_model_error) @api.response(401, 'Invalid API Key', models.response_model_error) - @api.response(403, 'Instance Not Guaranteed or Tartget instance Guaranteed by others', 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): '''Guarantee an instance @@ -87,6 +87,8 @@ class Guarantees(Resource): raise e.Forbidden("Only guaranteed instances can guarantee others.") if len(instance.guarantees) >= 20 and instance.id != 0: raise e.Forbidden("You cannot guarantee for more than 20 instances") + 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) @@ -105,6 +107,13 @@ class Guarantees(Resource): guarantor_id=instance.id, ) db.session.add(new_guarantee) + if database.instance_has_flag(instance.id,enums.InstanceFlags.MUTED): + muted_flag = InstanceFlag( + instance_id=target_instance.id, + flag=enums.InstanceFlags.MUTED, + comment=f"Inherited from guarantor {target_instance.domain}", + ) + db.session.add(muted_flag) database.delete_all_solicitation_by_source(target_instance.id) new_report = Report( source_domain=instance.domain, diff --git a/fediseer/apis/v1/hesitations.py b/fediseer/apis/v1/hesitations.py index 872dd09..758cfa3 100644 --- a/fediseer/apis/v1/hesitations.py +++ b/fediseer/apis/v1/hesitations.py @@ -151,7 +151,7 @@ class Hesitations(Resource): @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(403, 'Access Denied', models.response_model_error) @api.response(404, 'Instance not registered', models.response_model_error) def put(self, domain): '''Hesitate against an instance @@ -165,6 +165,8 @@ class Hesitations(Resource): 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 database.instance_has_flag(instance.id,enums.InstanceFlags.RESTRICTED): + raise e.Forbidden("You cannot take this action as your instance is restricted") if instance.domain == domain: raise e.BadRequest("You're a mad lad, but you can't hesitation yourself.") if database.has_too_many_actions_per_min(instance.domain): diff --git a/fediseer/apis/v1/whitelist.py b/fediseer/apis/v1/whitelist.py index 577d128..8d0855a 100644 --- a/fediseer/apis/v1/whitelist.py +++ b/fediseer/apis/v1/whitelist.py @@ -159,7 +159,7 @@ class WhitelistDomain(Resource): @api.marshal_with(models.response_model_api_key_reset, code=200, description='Instances', skip_none=True) @api.response(401, 'Invalid API Key', models.response_model_error) @api.response(403, 'Access Denied', models.response_model_error) - @api.response(403, 'Instance not claimed', models.response_model_error) + @api.response(404, 'Instance not claimed', models.response_model_error) def patch(self, domain): '''Regenerate API key for instance ''' @@ -174,7 +174,7 @@ class WhitelistDomain(Resource): instance_to_reset = database.find_instance_by_domain(domain) changed = False new_key = None - if requestor_instance != instance_to_reset and user.username != "fediseer": + if requestor_instance != instance_to_reset and user.account != "@fediseer@fediseer.com": raise e.Forbidden("Only an instance admin can modify the instance") if self.args.sysadmins is not None and instance.sysadmins != self.args.sysadmins: instance.sysadmins = self.args.sysadmins @@ -183,6 +183,8 @@ class WhitelistDomain(Resource): instance.moderators = self.args.moderators changed = True if self.args.pm_proxy is not None: + if instance_to_reset is None: + raise e.NotFound(f"Instance {domain} has not been registered yet.") proxy = enums.PMProxy[self.args.pm_proxy] if instance_to_reset.software == "lemmy" and proxy == enums.PMProxy.MASTODON: raise e.BadRequest("I'm sorry Dave, I can't let you do that. Lemmy is not capable of receiving mastodon PMs.") @@ -193,26 +195,32 @@ class WhitelistDomain(Resource): if self.args.visibility_endorsements is not None: visibility = enums.ListVisibility[self.args.visibility_endorsements] if instance.visibility_endorsements != visibility: + if database.instance_has_flag(instance.id,enums.InstanceFlags.MUTED): + raise e.Forbidden("Muted instances cannot change their visibility away from private!") instance.visibility_endorsements = visibility changed = True if self.args.visibility_censures is not None: visibility = enums.ListVisibility[self.args.visibility_censures] if instance.visibility_censures != visibility: + if database.instance_has_flag(instance.id,enums.InstanceFlags.MUTED): + raise e.Forbidden("Muted instances cannot change their visibility away from private!") instance.visibility_censures = visibility changed = True if self.args.visibility_hesitations is not None: visibility = enums.ListVisibility[self.args.visibility_hesitations] if instance.visibility_hesitations != visibility: + if database.instance_has_flag(instance.id,enums.InstanceFlags.MUTED): + raise e.Forbidden("Muted instances cannot change their visibility away from private!") instance.visibility_hesitations = visibility changed = True if self.args.admin_username: requestor = None - if self.args.admin_username != user.username or user.username == "fediseer": + if self.args.admin_username != user.username or user.account == "@fediseer@fediseer.com": requestor = user.username instance_to_reset = database.find_instance_by_account(f"@{self.args.admin_username}@{domain}") if instance_to_reset is None: raise e.NotFound(f"No admin '{self.args.admin_username}' found in instance {domain}. Have you remembered to claim it as that admin?") - if instance != instance_to_reset and user.username != "fediseer": + if instance != instance_to_reset and user.account != "@fediseer@fediseer.com": raise e.BadRequest("Only other admins of the same instance or the fediseer can request API key reset for others.") instance = instance_to_reset diff --git a/fediseer/classes/instance.py b/fediseer/classes/instance.py index 31944a4..1acc5b9 100644 --- a/fediseer/classes/instance.py +++ b/fediseer/classes/instance.py @@ -82,6 +82,16 @@ class Solicitation(db.Model): target_instance = db.relationship("Instance", back_populates="solicitations_received", foreign_keys=[target_id]) created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False, index=True) +class InstanceFlag(db.Model): + __tablename__ = "instance_flags" + __table_args__ = (UniqueConstraint('instance_id', 'flag', name='instance_flags_instance_id_flag'),) + id = db.Column(db.Integer, primary_key=True) + comment = db.Column(db.String(255), unique=False, nullable=True, index=False) + flag = db.Column(Enum(enums.InstanceFlags), nullable=False, index=True) + instance_id = db.Column(db.Integer, db.ForeignKey("instances.id", ondelete="CASCADE"), nullable=False, index=True) + instance = db.relationship("Instance", back_populates="flags") + created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False, index=True) + class Instance(db.Model): __tablename__ = "instances" @@ -117,6 +127,7 @@ class Instance(db.Model): rejections = db.relationship("RejectionRecord", back_populates="rejector_instance", cascade="all, delete-orphan", foreign_keys=[RejectionRecord.rejector_id]) rejectors = db.relationship("RejectionRecord", back_populates="rejected_instance", cascade="all, delete-orphan", foreign_keys=[RejectionRecord.rejected_id]) admins = db.relationship("Claim", back_populates="instance", cascade="all, delete-orphan") + flags = db.relationship("InstanceFlag", back_populates="instance", cascade="all, delete-orphan") def create(self): db.session.add(self) @@ -147,6 +158,12 @@ class Instance(db.Model): ret_dict["visibility_endorsements"] = self.visibility_endorsements.name ret_dict["visibility_censures"] = self.visibility_censures.name ret_dict["visibility_hesitations"] = self.visibility_hesitations.name + ret_dict["flags"] = [] + for flag in self.flags: + ret_dict["flags"].append({ + "flag": flag.flag.name, + "comment": flag.comment + }) return ret_dict @@ -197,4 +214,9 @@ class Instance(db.Model): if self.poll_failures <= 30*POLLS_PER_DAY: return enums.InstanceState.OFFLINE return enums.InstanceState.DECIMMISSIONED - \ No newline at end of file + + def has_flag(self, flag_enum): + for flag in self.flags: + if flag.flag == flag_enum: + return True + return False \ No newline at end of file diff --git a/fediseer/consts.py b/fediseer/consts.py index e5b771b..bb0ae58 100644 --- a/fediseer/consts.py +++ b/fediseer/consts.py @@ -1,4 +1,4 @@ -FEDISEER_VERSION = "0.17.1" +FEDISEER_VERSION = "0.18.0" SUPPORTED_SOFTWARE = { "lemmy", "mastodon", diff --git a/fediseer/database/functions.py b/fediseer/database/functions.py index 9ce9cd0..545a8ef 100644 --- a/fediseer/database/functions.py +++ b/fediseer/database/functions.py @@ -8,7 +8,7 @@ from sqlalchemy.orm import noload from fediseer.flask import db, SQLITE_MODE from fediseer.utils import hash_api_key from sqlalchemy.orm import joinedload -from fediseer.classes.instance import Instance, Endorsement, Guarantee, RejectionRecord, Censure, Hesitation, Solicitation +from fediseer.classes.instance import Instance, Endorsement, Guarantee, RejectionRecord, Censure, Hesitation, Solicitation, InstanceFlag from fediseer.classes.user import Claim, User from fediseer.classes.reports import Report from fediseer import enums @@ -459,4 +459,18 @@ def has_too_many_actions_per_min(source_domain): ).filter( Report.created > datetime.utcnow() - timedelta(minutes=1), ) - return query.count() > 20 \ No newline at end of file + return query.count() > 20 + +def get_instance_flag(instance_id, flag_enum): + query = InstanceFlag.query.filter( + InstanceFlag.instance_id == instance_id, + InstanceFlag.flag == flag_enum, + ) + return query.first() + +def instance_has_flag(instance_id, flag_enum): + query = InstanceFlag.query.filter( + InstanceFlag.instance_id == instance_id, + InstanceFlag.flag == flag_enum, + ) + return query.count() == 1 \ No newline at end of file diff --git a/fediseer/enums.py b/fediseer/enums.py index 4183135..e4d1961 100644 --- a/fediseer/enums.py +++ b/fediseer/enums.py @@ -7,6 +7,7 @@ class ReportType(enum.Enum): HESITATION = 3 CLAIM = 4 SOLICITATION = 5 + FLAG = 6 class ReportActivity(enum.Enum): ADDED = 0 @@ -27,3 +28,7 @@ class InstanceState(enum.Enum): UNREACHABLE = 1 OFFLINE = 2 DECIMMISSIONED = 3 + +class InstanceFlags(enum.Enum): + RESTRICTED = 0 + MUTED = 1 diff --git a/sql_statements/0.18.0.txt b/sql_statements/0.18.0.txt new file mode 100644 index 0000000..409c6bc --- /dev/null +++ b/sql_statements/0.18.0.txt @@ -0,0 +1 @@ +ALTER TYPE reporttype ADD VALUE 'FLAG'; \ No newline at end of file