This commit is contained in:
+109
-2
@@ -62,7 +62,9 @@ class Source(TimeStampedModel):
|
||||
ordering = ["name"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["domain", "source_type"], name="unique_domain_source_type"
|
||||
fields=["source_type", "base_url"],
|
||||
condition=~models.Q(base_url=""),
|
||||
name="unique_source_type_base_url_nonempty",
|
||||
)
|
||||
]
|
||||
|
||||
@@ -315,8 +317,101 @@ class RawDocument(TimeStampedModel):
|
||||
return self.final_url or self.url or f"Document {self.pk}"
|
||||
|
||||
|
||||
class MailboxConnection(TimeStampedModel):
|
||||
class Platform(models.TextChoices):
|
||||
VDAB = "vdab", "VDAB"
|
||||
INDEED = "indeed", "Indeed"
|
||||
LINKEDIN = "linkedin", "LinkedIn"
|
||||
ICTJOB = "ictjob", "ictjob.be"
|
||||
JOBAT = "jobat", "Jobat"
|
||||
STEPSTONE = "stepstone", "StepStone"
|
||||
CAREERJET = "careerjet", "Careerjet"
|
||||
RANDSTAD = "randstad", "Randstad"
|
||||
ROBERTHALF = "roberthalf", "Robert Half"
|
||||
|
||||
class Provider(models.TextChoices):
|
||||
GMAIL = "gmail", "Gmail"
|
||||
OUTLOOK = "outlook", "Outlook / Microsoft 365"
|
||||
CUSTOM = "custom", "Andere IMAP-provider"
|
||||
|
||||
class PollInterval(models.IntegerChoices):
|
||||
FIVE_MINUTES = 5, "Elke 5 minuten"
|
||||
FIFTEEN_MINUTES = 15, "Elke 15 minuten"
|
||||
THIRTY_MINUTES = 30, "Elke 30 minuten"
|
||||
HOURLY = 60, "Elk uur"
|
||||
THREE_HOURS = 180, "Elke 3 uur"
|
||||
SIX_HOURS = 360, "Elke 6 uur"
|
||||
|
||||
PROVIDER_HOSTS = {
|
||||
Provider.GMAIL: "imap.gmail.com",
|
||||
Provider.OUTLOOK: "outlook.office365.com",
|
||||
}
|
||||
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="mailbox_connections",
|
||||
)
|
||||
platform = models.CharField(max_length=24, choices=Platform.choices)
|
||||
provider = models.CharField(max_length=24, choices=Provider.choices)
|
||||
custom_host = models.CharField(max_length=255, blank=True)
|
||||
port = models.PositiveIntegerField(default=993)
|
||||
username = models.CharField(max_length=320)
|
||||
encrypted_password = models.TextField()
|
||||
mailbox = models.CharField(max_length=255, default="INBOX")
|
||||
enabled = models.BooleanField(default=True)
|
||||
poll_interval_minutes = models.PositiveIntegerField(
|
||||
choices=PollInterval.choices,
|
||||
default=PollInterval.THIRTY_MINUTES,
|
||||
)
|
||||
next_poll_at = models.DateTimeField(default=timezone.now, db_index=True)
|
||||
last_polled_at = models.DateTimeField(null=True, blank=True)
|
||||
last_success_at = models.DateTimeField(null=True, blank=True)
|
||||
last_error_category = models.CharField(max_length=80, blank=True)
|
||||
last_error_message = models.CharField(max_length=500, blank=True)
|
||||
lease_token = models.CharField(max_length=64, blank=True)
|
||||
lease_expires_at = models.DateTimeField(null=True, blank=True, db_index=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["platform"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["user", "platform"], name="unique_mailbox_platform_per_user"
|
||||
)
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.get_platform_display()} · {self.username}"
|
||||
|
||||
@property
|
||||
def imap_host(self) -> str:
|
||||
return self.PROVIDER_HOSTS.get(self.provider, self.custom_host).strip().lower()
|
||||
|
||||
def clean(self) -> None:
|
||||
host = self.imap_host
|
||||
if (
|
||||
not host
|
||||
or "://" in host
|
||||
or "/" in host
|
||||
or "@" in host
|
||||
or any(c.isspace() for c in host)
|
||||
):
|
||||
raise ValidationError({"custom_host": "Vul een geldige IMAP-hostnaam in."})
|
||||
if not 1 <= self.port <= 65535:
|
||||
raise ValidationError({"port": "De IMAP-poort moet tussen 1 en 65535 liggen."})
|
||||
if "\n" in self.mailbox or "\r" in self.mailbox:
|
||||
raise ValidationError({"mailbox": "De mailboxnaam bevat ongeldige tekens."})
|
||||
|
||||
|
||||
class EmailMessageRecord(TimeStampedModel):
|
||||
message_id = models.CharField(max_length=998, unique=True)
|
||||
mailbox_connection = models.ForeignKey(
|
||||
MailboxConnection,
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="messages",
|
||||
)
|
||||
message_id = models.CharField(max_length=998)
|
||||
mailbox = models.CharField(max_length=255, default="INBOX")
|
||||
sender = models.CharField(max_length=500, blank=True)
|
||||
subject = models.CharField(max_length=998, blank=True)
|
||||
@@ -330,6 +425,18 @@ class EmailMessageRecord(TimeStampedModel):
|
||||
|
||||
class Meta:
|
||||
ordering = ["-received_at", "-created_at"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["mailbox_connection", "message_id"],
|
||||
condition=models.Q(mailbox_connection__isnull=False),
|
||||
name="unique_message_per_mailbox_connection",
|
||||
),
|
||||
models.UniqueConstraint(
|
||||
fields=["message_id"],
|
||||
condition=models.Q(mailbox_connection__isnull=True),
|
||||
name="unique_legacy_email_message_id",
|
||||
),
|
||||
]
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.subject or self.message_id
|
||||
|
||||
Reference in New Issue
Block a user