lint: reformat python code with black
This commit is contained in:
parent
331beb01b4
commit
a406a7974b
88 changed files with 2579 additions and 1608 deletions
|
@ -17,7 +17,9 @@ class AbstractConfiguration(db.Model): # type: ignore
|
|||
description: Mapped[str]
|
||||
added: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||
updated: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||
destroyed: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||
destroyed: Mapped[Optional[datetime]] = mapped_column(
|
||||
AwareDateTime(), nullable=True
|
||||
)
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
|
@ -30,14 +32,10 @@ class AbstractConfiguration(db.Model): # type: ignore
|
|||
|
||||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return [
|
||||
"id", "description", "added", "updated", "destroyed"
|
||||
]
|
||||
return ["id", "description", "added", "updated", "destroyed"]
|
||||
|
||||
def csv_row(self) -> List[Any]:
|
||||
return [
|
||||
getattr(self, x) for x in self.csv_header()
|
||||
]
|
||||
return [getattr(self, x) for x in self.csv_header()]
|
||||
|
||||
|
||||
class Deprecation(db.Model): # type: ignore[name-defined,misc]
|
||||
|
@ -51,7 +49,8 @@ class Deprecation(db.Model): # type: ignore[name-defined,misc]
|
|||
@property
|
||||
def resource(self) -> "AbstractResource":
|
||||
from app.models.mirrors import Proxy # pylint: disable=R0401
|
||||
model = {'Proxy': Proxy}[self.resource_type]
|
||||
|
||||
model = {"Proxy": Proxy}[self.resource_type]
|
||||
return model.query.get(self.resource_id) # type: ignore[no-any-return]
|
||||
|
||||
|
||||
|
@ -61,29 +60,38 @@ class AbstractResource(db.Model): # type: ignore
|
|||
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
|
||||
added: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||
updated: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||
deprecated: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||
deprecated: Mapped[Optional[datetime]] = mapped_column(
|
||||
AwareDateTime(), nullable=True
|
||||
)
|
||||
deprecation_reason: Mapped[Optional[str]]
|
||||
destroyed: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||
destroyed: Mapped[Optional[datetime]] = mapped_column(
|
||||
AwareDateTime(), nullable=True
|
||||
)
|
||||
|
||||
def __init__(self, *,
|
||||
id: Optional[int] = None,
|
||||
added: Optional[datetime] = None,
|
||||
updated: Optional[datetime] = None,
|
||||
deprecated: Optional[datetime] = None,
|
||||
deprecation_reason: Optional[str] = None,
|
||||
destroyed: Optional[datetime] = None,
|
||||
**kwargs: Any) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
id: Optional[int] = None,
|
||||
added: Optional[datetime] = None,
|
||||
updated: Optional[datetime] = None,
|
||||
deprecated: Optional[datetime] = None,
|
||||
deprecation_reason: Optional[str] = None,
|
||||
destroyed: Optional[datetime] = None,
|
||||
**kwargs: Any
|
||||
) -> None:
|
||||
if added is None:
|
||||
added = datetime.now(tz=timezone.utc)
|
||||
if updated is None:
|
||||
updated = datetime.now(tz=timezone.utc)
|
||||
super().__init__(id=id,
|
||||
added=added,
|
||||
updated=updated,
|
||||
deprecated=deprecated,
|
||||
deprecation_reason=deprecation_reason,
|
||||
destroyed=destroyed,
|
||||
**kwargs)
|
||||
super().__init__(
|
||||
id=id,
|
||||
added=added,
|
||||
updated=updated,
|
||||
deprecated=deprecated,
|
||||
deprecation_reason=deprecation_reason,
|
||||
destroyed=destroyed,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
|
@ -110,19 +118,21 @@ class AbstractResource(db.Model): # type: ignore
|
|||
resource_type=type(self).__name__,
|
||||
resource_id=self.id,
|
||||
reason=reason,
|
||||
meta=meta
|
||||
meta=meta,
|
||||
)
|
||||
db.session.add(new_deprecation)
|
||||
return True
|
||||
logging.info("Not deprecating %s (reason=%s) because it's already deprecated with that reason.",
|
||||
self.brn, reason)
|
||||
logging.info(
|
||||
"Not deprecating %s (reason=%s) because it's already deprecated with that reason.",
|
||||
self.brn,
|
||||
reason,
|
||||
)
|
||||
return False
|
||||
|
||||
@property
|
||||
def deprecations(self) -> List[Deprecation]:
|
||||
return Deprecation.query.filter_by( # type: ignore[no-any-return]
|
||||
resource_type='Proxy',
|
||||
resource_id=self.id
|
||||
resource_type="Proxy", resource_id=self.id
|
||||
).all()
|
||||
|
||||
def destroy(self) -> None:
|
||||
|
@ -139,10 +149,13 @@ class AbstractResource(db.Model): # type: ignore
|
|||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return [
|
||||
"id", "added", "updated", "deprecated", "deprecation_reason", "destroyed"
|
||||
"id",
|
||||
"added",
|
||||
"updated",
|
||||
"deprecated",
|
||||
"deprecation_reason",
|
||||
"destroyed",
|
||||
]
|
||||
|
||||
def csv_row(self) -> List[Union[datetime, bool, int, str]]:
|
||||
return [
|
||||
getattr(self, x) for x in self.csv_header()
|
||||
]
|
||||
return [getattr(self, x) for x in self.csv_header()]
|
||||
|
|
|
@ -17,31 +17,40 @@ class Activity(db.Model): # type: ignore
|
|||
text: Mapped[str]
|
||||
added: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||
|
||||
def __init__(self, *,
|
||||
id: Optional[int] = None,
|
||||
group_id: Optional[int] = None,
|
||||
activity_type: str,
|
||||
text: str,
|
||||
added: Optional[datetime] = None,
|
||||
**kwargs: Any) -> None:
|
||||
if not isinstance(activity_type, str) or len(activity_type) > 20 or activity_type == "":
|
||||
raise TypeError("expected string for activity type between 1 and 20 characters")
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
id: Optional[int] = None,
|
||||
group_id: Optional[int] = None,
|
||||
activity_type: str,
|
||||
text: str,
|
||||
added: Optional[datetime] = None,
|
||||
**kwargs: Any
|
||||
) -> None:
|
||||
if (
|
||||
not isinstance(activity_type, str)
|
||||
or len(activity_type) > 20
|
||||
or activity_type == ""
|
||||
):
|
||||
raise TypeError(
|
||||
"expected string for activity type between 1 and 20 characters"
|
||||
)
|
||||
if not isinstance(text, str):
|
||||
raise TypeError("expected string for text")
|
||||
if added is None:
|
||||
added = datetime.now(tz=timezone.utc)
|
||||
super().__init__(id=id,
|
||||
group_id=group_id,
|
||||
activity_type=activity_type,
|
||||
text=text,
|
||||
added=added,
|
||||
**kwargs)
|
||||
super().__init__(
|
||||
id=id,
|
||||
group_id=group_id,
|
||||
activity_type=activity_type,
|
||||
text=text,
|
||||
added=added,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def notify(self) -> int:
|
||||
count = 0
|
||||
hooks = Webhook.query.filter(
|
||||
Webhook.destroyed.is_(None)
|
||||
)
|
||||
hooks = Webhook.query.filter(Webhook.destroyed.is_(None))
|
||||
for hook in hooks:
|
||||
hook.send(self.text)
|
||||
count += 1
|
||||
|
@ -59,7 +68,7 @@ class Webhook(AbstractConfiguration):
|
|||
product="notify",
|
||||
provider=self.format,
|
||||
resource_type="conf",
|
||||
resource_id=str(self.id)
|
||||
resource_id=str(self.id),
|
||||
)
|
||||
|
||||
def send(self, text: str) -> None:
|
||||
|
|
|
@ -37,7 +37,15 @@ class Alarm(db.Model): # type: ignore
|
|||
|
||||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return ["id", "target", "alarm_type", "alarm_state", "state_changed", "last_updated", "text"]
|
||||
return [
|
||||
"id",
|
||||
"target",
|
||||
"alarm_type",
|
||||
"alarm_state",
|
||||
"state_changed",
|
||||
"last_updated",
|
||||
"text",
|
||||
]
|
||||
|
||||
def csv_row(self) -> List[Any]:
|
||||
return [getattr(self, x) for x in self.csv_header()]
|
||||
|
@ -45,11 +53,15 @@ class Alarm(db.Model): # type: ignore
|
|||
def update_state(self, state: AlarmState, text: str) -> None:
|
||||
if self.alarm_state != state or self.state_changed is None:
|
||||
self.state_changed = datetime.now(tz=timezone.utc)
|
||||
activity = Activity(activity_type="alarm_state",
|
||||
text=f"[{self.aspect}] {state.emoji} Alarm state changed from "
|
||||
f"{self.alarm_state.name} to {state.name} on {self.target}: {text}.")
|
||||
if (self.alarm_state.name in ["WARNING", "CRITICAL"]
|
||||
or state.name in ["WARNING", "CRITICAL"]):
|
||||
activity = Activity(
|
||||
activity_type="alarm_state",
|
||||
text=f"[{self.aspect}] {state.emoji} Alarm state changed from "
|
||||
f"{self.alarm_state.name} to {state.name} on {self.target}: {text}.",
|
||||
)
|
||||
if self.alarm_state.name in ["WARNING", "CRITICAL"] or state.name in [
|
||||
"WARNING",
|
||||
"CRITICAL",
|
||||
]:
|
||||
# Notifications are only sent on recovery from warning/critical state or on entry
|
||||
# to warning/critical states. This should reduce alert fatigue.
|
||||
activity.notify()
|
||||
|
|
|
@ -33,7 +33,7 @@ class Automation(AbstractConfiguration):
|
|||
product="core",
|
||||
provider="",
|
||||
resource_type="automation",
|
||||
resource_id=self.short_name
|
||||
resource_id=self.short_name,
|
||||
)
|
||||
|
||||
def kick(self) -> None:
|
||||
|
@ -55,5 +55,5 @@ class AutomationLogs(AbstractResource):
|
|||
product="core",
|
||||
provider="",
|
||||
resource_type="automationlog",
|
||||
resource_id=str(self.id)
|
||||
resource_id=str(self.id),
|
||||
)
|
||||
|
|
|
@ -26,17 +26,21 @@ class Group(AbstractConfiguration):
|
|||
eotk: Mapped[bool]
|
||||
|
||||
origins: Mapped[List["Origin"]] = relationship("Origin", back_populates="group")
|
||||
statics: Mapped[List["StaticOrigin"]] = relationship("StaticOrigin", back_populates="group")
|
||||
statics: Mapped[List["StaticOrigin"]] = relationship(
|
||||
"StaticOrigin", back_populates="group"
|
||||
)
|
||||
eotks: Mapped[List["Eotk"]] = relationship("Eotk", back_populates="group")
|
||||
onions: Mapped[List["Onion"]] = relationship("Onion", back_populates="group")
|
||||
smart_proxies: Mapped[List["SmartProxy"]] = relationship("SmartProxy", back_populates="group")
|
||||
pools: Mapped[List["Pool"]] = relationship("Pool", secondary="pool_group", back_populates="groups")
|
||||
smart_proxies: Mapped[List["SmartProxy"]] = relationship(
|
||||
"SmartProxy", back_populates="group"
|
||||
)
|
||||
pools: Mapped[List["Pool"]] = relationship(
|
||||
"Pool", secondary="pool_group", back_populates="groups"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return super().csv_header() + [
|
||||
"group_name", "eotk"
|
||||
]
|
||||
return super().csv_header() + ["group_name", "eotk"]
|
||||
|
||||
@property
|
||||
def brn(self) -> BRN:
|
||||
|
@ -45,16 +49,15 @@ class Group(AbstractConfiguration):
|
|||
product="group",
|
||||
provider="",
|
||||
resource_type="group",
|
||||
resource_id=str(self.id)
|
||||
resource_id=str(self.id),
|
||||
)
|
||||
|
||||
def to_dict(self) -> GroupDict:
|
||||
if not TYPE_CHECKING:
|
||||
from app.models.mirrors import Origin # to prevent circular import
|
||||
|
||||
active_origins_query = (
|
||||
db.session.query(aliased(Origin))
|
||||
.filter(and_(Origin.group_id == self.id, Origin.destroyed.is_(None)))
|
||||
active_origins_query = db.session.query(aliased(Origin)).filter(
|
||||
and_(Origin.group_id == self.id, Origin.destroyed.is_(None))
|
||||
)
|
||||
active_origins_count = active_origins_query.count()
|
||||
return {
|
||||
|
@ -70,16 +73,20 @@ class Pool(AbstractConfiguration):
|
|||
api_key: Mapped[str]
|
||||
redirector_domain: Mapped[Optional[str]]
|
||||
|
||||
bridgeconfs: Mapped[List["BridgeConf"]] = relationship("BridgeConf", back_populates="pool")
|
||||
bridgeconfs: Mapped[List["BridgeConf"]] = relationship(
|
||||
"BridgeConf", back_populates="pool"
|
||||
)
|
||||
proxies: Mapped[List["Proxy"]] = relationship("Proxy", back_populates="pool")
|
||||
lists: Mapped[List["MirrorList"]] = relationship("MirrorList", back_populates="pool")
|
||||
groups: Mapped[List[Group]] = relationship("Group", secondary="pool_group", back_populates="pools")
|
||||
lists: Mapped[List["MirrorList"]] = relationship(
|
||||
"MirrorList", back_populates="pool"
|
||||
)
|
||||
groups: Mapped[List[Group]] = relationship(
|
||||
"Group", secondary="pool_group", back_populates="pools"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return super().csv_header() + [
|
||||
"pool_name"
|
||||
]
|
||||
return super().csv_header() + ["pool_name"]
|
||||
|
||||
@property
|
||||
def brn(self) -> BRN:
|
||||
|
@ -88,7 +95,7 @@ class Pool(AbstractConfiguration):
|
|||
product="pool",
|
||||
provider="",
|
||||
resource_type="pool",
|
||||
resource_id=str(self.pool_name)
|
||||
resource_id=str(self.pool_name),
|
||||
)
|
||||
|
||||
|
||||
|
@ -121,14 +128,14 @@ class MirrorList(AbstractConfiguration):
|
|||
"bc3": "Bypass Censorship v3",
|
||||
"bca": "Bypass Censorship Analytics",
|
||||
"bridgelines": "Tor Bridge Lines",
|
||||
"rdr": "Redirector Data"
|
||||
"rdr": "Redirector Data",
|
||||
}
|
||||
|
||||
encodings_supported = {
|
||||
"json": "JSON (Plain)",
|
||||
"jsno": "JSON (Obfuscated)",
|
||||
"js": "JavaScript (Plain)",
|
||||
"jso": "JavaScript (Obfuscated)"
|
||||
"jso": "JavaScript (Obfuscated)",
|
||||
}
|
||||
|
||||
def destroy(self) -> None:
|
||||
|
@ -149,7 +156,11 @@ class MirrorList(AbstractConfiguration):
|
|||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return super().csv_header() + [
|
||||
"provider", "format", "container", "branch", "filename"
|
||||
"provider",
|
||||
"format",
|
||||
"container",
|
||||
"branch",
|
||||
"filename",
|
||||
]
|
||||
|
||||
@property
|
||||
|
@ -159,5 +170,5 @@ class MirrorList(AbstractConfiguration):
|
|||
product="list",
|
||||
provider=self.provider,
|
||||
resource_type="list",
|
||||
resource_id=str(self.id)
|
||||
resource_id=str(self.id),
|
||||
)
|
||||
|
|
|
@ -34,7 +34,7 @@ class BridgeConf(AbstractConfiguration):
|
|||
product="bridge",
|
||||
provider="",
|
||||
resource_type="bridgeconf",
|
||||
resource_id=str(self.id)
|
||||
resource_id=str(self.id),
|
||||
)
|
||||
|
||||
def destroy(self) -> None:
|
||||
|
@ -48,14 +48,22 @@ class BridgeConf(AbstractConfiguration):
|
|||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return super().csv_header() + [
|
||||
"pool_id", "provider", "method", "description", "target_number", "max_number", "expiry_hours"
|
||||
"pool_id",
|
||||
"provider",
|
||||
"method",
|
||||
"description",
|
||||
"target_number",
|
||||
"max_number",
|
||||
"expiry_hours",
|
||||
]
|
||||
|
||||
|
||||
class Bridge(AbstractResource):
|
||||
conf_id: Mapped[int] = mapped_column(db.ForeignKey("bridge_conf.id"))
|
||||
cloud_account_id: Mapped[int] = mapped_column(db.ForeignKey("cloud_account.id"))
|
||||
terraform_updated: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||
terraform_updated: Mapped[Optional[datetime]] = mapped_column(
|
||||
AwareDateTime(), nullable=True
|
||||
)
|
||||
nickname: Mapped[Optional[str]]
|
||||
fingerprint: Mapped[Optional[str]]
|
||||
hashed_fingerprint: Mapped[Optional[str]]
|
||||
|
@ -71,11 +79,16 @@ class Bridge(AbstractResource):
|
|||
product="bridge",
|
||||
provider=self.cloud_account.provider.key,
|
||||
resource_type="bridge",
|
||||
resource_id=str(self.id)
|
||||
resource_id=str(self.id),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return super().csv_header() + [
|
||||
"conf_id", "terraform_updated", "nickname", "fingerprint", "hashed_fingerprint", "bridgeline"
|
||||
"conf_id",
|
||||
"terraform_updated",
|
||||
"nickname",
|
||||
"fingerprint",
|
||||
"hashed_fingerprint",
|
||||
"bridgeline",
|
||||
]
|
||||
|
|
|
@ -42,9 +42,14 @@ class CloudAccount(AbstractConfiguration):
|
|||
# Compute Quotas
|
||||
max_instances: Mapped[int]
|
||||
|
||||
bridges: Mapped[List["Bridge"]] = relationship("Bridge", back_populates="cloud_account")
|
||||
statics: Mapped[List["StaticOrigin"]] = relationship("StaticOrigin", back_populates="storage_cloud_account", foreign_keys=[
|
||||
StaticOrigin.storage_cloud_account_id])
|
||||
bridges: Mapped[List["Bridge"]] = relationship(
|
||||
"Bridge", back_populates="cloud_account"
|
||||
)
|
||||
statics: Mapped[List["StaticOrigin"]] = relationship(
|
||||
"StaticOrigin",
|
||||
back_populates="storage_cloud_account",
|
||||
foreign_keys=[StaticOrigin.storage_cloud_account_id],
|
||||
)
|
||||
|
||||
@property
|
||||
def brn(self) -> BRN:
|
||||
|
|
|
@ -10,8 +10,7 @@ from tldextract import extract
|
|||
from werkzeug.datastructures import FileStorage
|
||||
|
||||
from app.brm.brn import BRN
|
||||
from app.brm.utils import (create_data_uri, normalize_color,
|
||||
thumbnail_uploaded_image)
|
||||
from app.brm.utils import create_data_uri, normalize_color, thumbnail_uploaded_image
|
||||
from app.extensions import db
|
||||
from app.models import AbstractConfiguration, AbstractResource, Deprecation
|
||||
from app.models.base import Group, Pool
|
||||
|
@ -19,10 +18,10 @@ from app.models.onions import Onion
|
|||
from app.models.types import AwareDateTime
|
||||
|
||||
country_origin = db.Table(
|
||||
'country_origin',
|
||||
"country_origin",
|
||||
db.metadata,
|
||||
db.Column('country_id', db.ForeignKey('country.id'), primary_key=True),
|
||||
db.Column('origin_id', db.ForeignKey('origin.id'), primary_key=True),
|
||||
db.Column("country_id", db.ForeignKey("country.id"), primary_key=True),
|
||||
db.Column("origin_id", db.ForeignKey("origin.id"), primary_key=True),
|
||||
extend_existing=True,
|
||||
)
|
||||
|
||||
|
@ -45,7 +44,9 @@ class Origin(AbstractConfiguration):
|
|||
|
||||
group: Mapped[Group] = relationship("Group", back_populates="origins")
|
||||
proxies: Mapped[List[Proxy]] = relationship("Proxy", back_populates="origin")
|
||||
countries: Mapped[List[Country]] = relationship("Country", secondary=country_origin, back_populates='origins')
|
||||
countries: Mapped[List[Country]] = relationship(
|
||||
"Country", secondary=country_origin, back_populates="origins"
|
||||
)
|
||||
|
||||
@property
|
||||
def brn(self) -> BRN:
|
||||
|
@ -54,13 +55,18 @@ class Origin(AbstractConfiguration):
|
|||
product="mirror",
|
||||
provider="conf",
|
||||
resource_type="origin",
|
||||
resource_id=self.domain_name
|
||||
resource_id=self.domain_name,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return super().csv_header() + [
|
||||
"group_id", "domain_name", "auto_rotation", "smart", "assets", "country"
|
||||
"group_id",
|
||||
"domain_name",
|
||||
"auto_rotation",
|
||||
"smart",
|
||||
"assets",
|
||||
"country",
|
||||
]
|
||||
|
||||
def destroy(self) -> None:
|
||||
|
@ -84,30 +90,41 @@ class Origin(AbstractConfiguration):
|
|||
@property
|
||||
def risk_level(self) -> Dict[str, int]:
|
||||
if self.risk_level_override:
|
||||
return {country.country_code: self.risk_level_override for country in self.countries}
|
||||
return {
|
||||
country.country_code: self.risk_level_override
|
||||
for country in self.countries
|
||||
}
|
||||
frequency_factor = 0.0
|
||||
recency_factor = 0.0
|
||||
recent_deprecations = (
|
||||
db.session.query(Deprecation)
|
||||
.join(Proxy,
|
||||
Deprecation.resource_id == Proxy.id)
|
||||
.join(Proxy, Deprecation.resource_id == Proxy.id)
|
||||
.join(Origin, Origin.id == Proxy.origin_id)
|
||||
.filter(
|
||||
Origin.id == self.id,
|
||||
Deprecation.resource_type == 'Proxy',
|
||||
Deprecation.deprecated_at >= datetime.now(tz=timezone.utc) - timedelta(hours=168),
|
||||
Deprecation.reason != "destroyed"
|
||||
Deprecation.resource_type == "Proxy",
|
||||
Deprecation.deprecated_at
|
||||
>= datetime.now(tz=timezone.utc) - timedelta(hours=168),
|
||||
Deprecation.reason != "destroyed",
|
||||
)
|
||||
.distinct(Proxy.id)
|
||||
.all()
|
||||
)
|
||||
for deprecation in recent_deprecations:
|
||||
recency_factor += 1 / max((datetime.now(tz=timezone.utc) - deprecation.deprecated_at).total_seconds() // 3600, 1)
|
||||
recency_factor += 1 / max(
|
||||
(
|
||||
datetime.now(tz=timezone.utc) - deprecation.deprecated_at
|
||||
).total_seconds()
|
||||
// 3600,
|
||||
1,
|
||||
)
|
||||
frequency_factor += 1
|
||||
risk_levels: Dict[str, int] = {}
|
||||
for country in self.countries:
|
||||
risk_levels[country.country_code.upper()] = int(
|
||||
max(1, min(10, frequency_factor * recency_factor))) + country.risk_level
|
||||
risk_levels[country.country_code.upper()] = (
|
||||
int(max(1, min(10, frequency_factor * recency_factor)))
|
||||
+ country.risk_level
|
||||
)
|
||||
return risk_levels
|
||||
|
||||
def to_dict(self) -> OriginDict:
|
||||
|
@ -128,13 +145,15 @@ class Country(AbstractConfiguration):
|
|||
product="country",
|
||||
provider="iso3166-1",
|
||||
resource_type="alpha2",
|
||||
resource_id=self.country_code
|
||||
resource_id=self.country_code,
|
||||
)
|
||||
|
||||
country_code: Mapped[str]
|
||||
risk_level_override: Mapped[Optional[int]]
|
||||
|
||||
origins = db.relationship("Origin", secondary=country_origin, back_populates='countries')
|
||||
origins = db.relationship(
|
||||
"Origin", secondary=country_origin, back_populates="countries"
|
||||
)
|
||||
|
||||
@property
|
||||
def risk_level(self) -> int:
|
||||
|
@ -144,29 +163,39 @@ class Country(AbstractConfiguration):
|
|||
recency_factor = 0.0
|
||||
recent_deprecations = (
|
||||
db.session.query(Deprecation)
|
||||
.join(Proxy,
|
||||
Deprecation.resource_id == Proxy.id)
|
||||
.join(Proxy, Deprecation.resource_id == Proxy.id)
|
||||
.join(Origin, Origin.id == Proxy.origin_id)
|
||||
.join(Origin.countries)
|
||||
.filter(
|
||||
Country.id == self.id,
|
||||
Deprecation.resource_type == 'Proxy',
|
||||
Deprecation.deprecated_at >= datetime.now(tz=timezone.utc) - timedelta(hours=168),
|
||||
Deprecation.reason != "destroyed"
|
||||
Deprecation.resource_type == "Proxy",
|
||||
Deprecation.deprecated_at
|
||||
>= datetime.now(tz=timezone.utc) - timedelta(hours=168),
|
||||
Deprecation.reason != "destroyed",
|
||||
)
|
||||
.distinct(Proxy.id)
|
||||
.all()
|
||||
)
|
||||
for deprecation in recent_deprecations:
|
||||
recency_factor += 1 / max((datetime.now(tz=timezone.utc) - deprecation.deprecated_at).total_seconds() // 3600, 1)
|
||||
recency_factor += 1 / max(
|
||||
(
|
||||
datetime.now(tz=timezone.utc) - deprecation.deprecated_at
|
||||
).total_seconds()
|
||||
// 3600,
|
||||
1,
|
||||
)
|
||||
frequency_factor += 1
|
||||
return int(max(1, min(10, frequency_factor * recency_factor)))
|
||||
|
||||
|
||||
class StaticOrigin(AbstractConfiguration):
|
||||
group_id = mapped_column(db.Integer, db.ForeignKey("group.id"), nullable=False)
|
||||
storage_cloud_account_id = mapped_column(db.Integer(), db.ForeignKey("cloud_account.id"), nullable=False)
|
||||
source_cloud_account_id = mapped_column(db.Integer(), db.ForeignKey("cloud_account.id"), nullable=False)
|
||||
storage_cloud_account_id = mapped_column(
|
||||
db.Integer(), db.ForeignKey("cloud_account.id"), nullable=False
|
||||
)
|
||||
source_cloud_account_id = mapped_column(
|
||||
db.Integer(), db.ForeignKey("cloud_account.id"), nullable=False
|
||||
)
|
||||
source_project = mapped_column(db.String(255), nullable=False)
|
||||
auto_rotate = mapped_column(db.Boolean, nullable=False)
|
||||
matrix_homeserver = mapped_column(db.String(255), nullable=True)
|
||||
|
@ -182,30 +211,34 @@ class StaticOrigin(AbstractConfiguration):
|
|||
product="mirror",
|
||||
provider="aws",
|
||||
resource_type="static",
|
||||
resource_id=self.domain_name
|
||||
resource_id=self.domain_name,
|
||||
)
|
||||
|
||||
group = db.relationship("Group", back_populates="statics")
|
||||
storage_cloud_account = db.relationship("CloudAccount", back_populates="statics",
|
||||
foreign_keys=[storage_cloud_account_id])
|
||||
source_cloud_account = db.relationship("CloudAccount", back_populates="statics",
|
||||
foreign_keys=[source_cloud_account_id])
|
||||
storage_cloud_account = db.relationship(
|
||||
"CloudAccount",
|
||||
back_populates="statics",
|
||||
foreign_keys=[storage_cloud_account_id],
|
||||
)
|
||||
source_cloud_account = db.relationship(
|
||||
"CloudAccount", back_populates="statics", foreign_keys=[source_cloud_account_id]
|
||||
)
|
||||
|
||||
def destroy(self) -> None:
|
||||
# TODO: The StaticMetaAutomation will clean up for now, but it should probably happen here for consistency
|
||||
super().destroy()
|
||||
|
||||
def update(
|
||||
self,
|
||||
source_project: str,
|
||||
description: str,
|
||||
auto_rotate: bool,
|
||||
matrix_homeserver: Optional[str],
|
||||
keanu_convene_path: Optional[str],
|
||||
keanu_convene_logo: Optional[FileStorage],
|
||||
keanu_convene_color: Optional[str],
|
||||
clean_insights_backend: Optional[Union[str, bool]],
|
||||
db_session_commit: bool,
|
||||
self,
|
||||
source_project: str,
|
||||
description: str,
|
||||
auto_rotate: bool,
|
||||
matrix_homeserver: Optional[str],
|
||||
keanu_convene_path: Optional[str],
|
||||
keanu_convene_logo: Optional[FileStorage],
|
||||
keanu_convene_color: Optional[str],
|
||||
clean_insights_backend: Optional[Union[str, bool]],
|
||||
db_session_commit: bool,
|
||||
) -> None:
|
||||
if isinstance(source_project, str):
|
||||
self.source_project = source_project
|
||||
|
@ -235,19 +268,29 @@ class StaticOrigin(AbstractConfiguration):
|
|||
elif isinstance(keanu_convene_logo, FileStorage):
|
||||
if keanu_convene_logo.filename: # if False, no file was uploaded
|
||||
keanu_convene_config["logo"] = create_data_uri(
|
||||
thumbnail_uploaded_image(keanu_convene_logo), keanu_convene_logo.filename)
|
||||
thumbnail_uploaded_image(keanu_convene_logo),
|
||||
keanu_convene_logo.filename,
|
||||
)
|
||||
else:
|
||||
raise ValueError("keanu_convene_logo must be a FileStorage")
|
||||
try:
|
||||
if isinstance(keanu_convene_color, str):
|
||||
keanu_convene_config["color"] = normalize_color(keanu_convene_color) # can raise ValueError
|
||||
keanu_convene_config["color"] = normalize_color(
|
||||
keanu_convene_color
|
||||
) # can raise ValueError
|
||||
else:
|
||||
raise ValueError() # re-raised below with message
|
||||
except ValueError:
|
||||
raise ValueError("keanu_convene_path must be a str containing an HTML color (CSS name or hex)")
|
||||
self.keanu_convene_config = json.dumps(keanu_convene_config, separators=(',', ':'))
|
||||
raise ValueError(
|
||||
"keanu_convene_path must be a str containing an HTML color (CSS name or hex)"
|
||||
)
|
||||
self.keanu_convene_config = json.dumps(
|
||||
keanu_convene_config, separators=(",", ":")
|
||||
)
|
||||
del keanu_convene_config # done with this temporary variable
|
||||
if clean_insights_backend is None or (isinstance(clean_insights_backend, bool) and not clean_insights_backend):
|
||||
if clean_insights_backend is None or (
|
||||
isinstance(clean_insights_backend, bool) and not clean_insights_backend
|
||||
):
|
||||
self.clean_insights_backend = None
|
||||
elif isinstance(clean_insights_backend, bool) and clean_insights_backend:
|
||||
self.clean_insights_backend = "metrics.cleaninsights.org"
|
||||
|
@ -260,7 +303,9 @@ class StaticOrigin(AbstractConfiguration):
|
|||
self.updated = datetime.now(tz=timezone.utc)
|
||||
|
||||
|
||||
ResourceStatus = Union[Literal["active"], Literal["pending"], Literal["expiring"], Literal["destroyed"]]
|
||||
ResourceStatus = Union[
|
||||
Literal["active"], Literal["pending"], Literal["expiring"], Literal["destroyed"]
|
||||
]
|
||||
|
||||
|
||||
class ProxyDict(TypedDict):
|
||||
|
@ -271,12 +316,16 @@ class ProxyDict(TypedDict):
|
|||
|
||||
|
||||
class Proxy(AbstractResource):
|
||||
origin_id: Mapped[int] = mapped_column(db.Integer, db.ForeignKey("origin.id"), nullable=False)
|
||||
origin_id: Mapped[int] = mapped_column(
|
||||
db.Integer, db.ForeignKey("origin.id"), nullable=False
|
||||
)
|
||||
pool_id: Mapped[Optional[int]] = mapped_column(db.Integer, db.ForeignKey("pool.id"))
|
||||
provider: Mapped[str] = mapped_column(db.String(20), nullable=False)
|
||||
psg: Mapped[Optional[int]] = mapped_column(db.Integer, nullable=True)
|
||||
slug: Mapped[Optional[str]] = mapped_column(db.String(20), nullable=True)
|
||||
terraform_updated: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||
terraform_updated: Mapped[Optional[datetime]] = mapped_column(
|
||||
AwareDateTime(), nullable=True
|
||||
)
|
||||
url: Mapped[Optional[str]] = mapped_column(db.String(255), nullable=True)
|
||||
|
||||
origin: Mapped[Origin] = relationship("Origin", back_populates="proxies")
|
||||
|
@ -289,13 +338,18 @@ class Proxy(AbstractResource):
|
|||
product="mirror",
|
||||
provider=self.provider,
|
||||
resource_type="proxy",
|
||||
resource_id=str(self.id)
|
||||
resource_id=str(self.id),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def csv_header(cls) -> List[str]:
|
||||
return super().csv_header() + [
|
||||
"origin_id", "provider", "psg", "slug", "terraform_updated", "url"
|
||||
"origin_id",
|
||||
"provider",
|
||||
"psg",
|
||||
"slug",
|
||||
"terraform_updated",
|
||||
"url",
|
||||
]
|
||||
|
||||
def to_dict(self) -> ProxyDict:
|
||||
|
@ -329,5 +383,5 @@ class SmartProxy(AbstractResource):
|
|||
product="mirror",
|
||||
provider=self.provider,
|
||||
resource_type="smart_proxy",
|
||||
resource_id=str(1)
|
||||
resource_id=str(1),
|
||||
)
|
||||
|
|
|
@ -32,7 +32,7 @@ class Onion(AbstractConfiguration):
|
|||
product="eotk",
|
||||
provider="*",
|
||||
resource_type="onion",
|
||||
resource_id=self.onion_name
|
||||
resource_id=self.onion_name,
|
||||
)
|
||||
|
||||
group_id: Mapped[int] = mapped_column(db.ForeignKey("group.id"))
|
||||
|
@ -80,5 +80,5 @@ class Eotk(AbstractResource):
|
|||
provider=self.provider,
|
||||
product="eotk",
|
||||
resource_type="instance",
|
||||
resource_id=self.region
|
||||
resource_id=self.region,
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue