diff --git a/src-ui/src/app/components/manage/mail/mail.component.html b/src-ui/src/app/components/manage/mail/mail.component.html index e6e4ac200..798aa8718 100644 --- a/src-ui/src/app/components/manage/mail/mail.component.html +++ b/src-ui/src/app/components/manage/mail/mail.component.html @@ -37,7 +37,16 @@ @for (account of mailAccounts; track account) {
  • -
    +
    + +
    {{account.imap_server}}
    {{account.username}}
    diff --git a/src-ui/src/app/components/manage/mail/mail.component.ts b/src-ui/src/app/components/manage/mail/mail.component.ts index 381db6e1d..ca93b7a16 100644 --- a/src-ui/src/app/components/manage/mail/mail.component.ts +++ b/src-ui/src/app/components/manage/mail/mail.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { Subject, first, takeUntil } from 'rxjs' import { ObjectWithPermissions } from 'src/app/data/object-with-permissions' -import { MailAccount } from 'src/app/data/mail-account' +import { MailAccount, MailAccountType } from 'src/app/data/mail-account' import { MailRule } from 'src/app/data/mail-rule' import { PermissionsService, @@ -31,6 +31,8 @@ export class MailComponent extends ComponentWithPermissions implements OnInit, OnDestroy { + public MailAccountType = MailAccountType + mailAccounts: MailAccount[] = [] mailRules: MailRule[] = [] diff --git a/src-ui/src/app/data/mail-account.ts b/src-ui/src/app/data/mail-account.ts index 5ab8ba3b5..b56917044 100644 --- a/src-ui/src/app/data/mail-account.ts +++ b/src-ui/src/app/data/mail-account.ts @@ -6,6 +6,12 @@ export enum IMAPSecurity { STARTTLS = 3, } +export enum MailAccountType { + IMAP = 1, + Gmail = 2, + Outlook = 3, +} + export interface MailAccount extends ObjectWithPermissions { name: string @@ -22,4 +28,10 @@ export interface MailAccount extends ObjectWithPermissions { character_set?: string is_token: boolean + + account_type: MailAccountType + + refresh_token?: string + + expiration?: string // Date } diff --git a/src-ui/src/app/data/ui-settings.ts b/src-ui/src/app/data/ui-settings.ts index 18f9ff130..d1e6bdcec 100644 --- a/src-ui/src/app/data/ui-settings.ts +++ b/src-ui/src/app/data/ui-settings.ts @@ -247,11 +247,11 @@ export const SETTINGS: UiSetting[] = [ { key: SETTINGS_KEYS.GMAIL_OAUTH_URL, type: 'string', - default: '', + default: null, }, { key: SETTINGS_KEYS.OUTLOOK_OAUTH_URL, type: 'string', - default: '', + default: null, }, ] diff --git a/src/documents/tests/test_migration_workflows.py b/src/documents/tests/test_migration_workflows.py index 34e2afb5b..9a911d2e5 100644 --- a/src/documents/tests/test_migration_workflows.py +++ b/src/documents/tests/test_migration_workflows.py @@ -8,7 +8,7 @@ class TestMigrateWorkflow(TestMigrations): dependencies = ( ( "paperless_mail", - "0027_mailaccount_expiration_mailaccount_refresh_token", + "0027_mailaccount_expiration_mailaccount_account_type_and_more", ), ) diff --git a/src/paperless_mail/mail.py b/src/paperless_mail/mail.py index f2d428407..30498943d 100644 --- a/src/paperless_mail/mail.py +++ b/src/paperless_mail/mail.py @@ -431,7 +431,7 @@ def refresh_oauth_token(self, account: MailAccount) -> bool: self.log.error(f"Account {account}: No refresh token available.") return False - if "gmail" in account.imap_server: + if account.account_type == MailAccount.MailAccountType.GMAIL: url = "https://accounts.google.com/o/oauth2/token" data = { "client_id": settings.GMAIL_OAUTH_CLIENT_ID, @@ -439,7 +439,7 @@ def refresh_oauth_token(self, account: MailAccount) -> bool: "refresh_token": account.refresh_token, "grant_type": "refresh_token", } - elif "outlook" in account.imap_server: + elif account.account_type == MailAccount.MailAccountType.OUTLOOK: url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" data = { "client_id": settings.OUTLOOK_OAUTH_CLIENT_ID, diff --git a/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_refresh_token.py b/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_account_type_and_more.py similarity index 72% rename from src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_refresh_token.py rename to src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_account_type_and_more.py index 95e202fd1..8dd7fe618 100644 --- a/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_refresh_token.py +++ b/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_account_type_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.1 on 2024-10-05 07:42 +# Generated by Django 5.1.1 on 2024-10-05 17:12 from django.db import migrations from django.db import models @@ -20,6 +20,15 @@ class Migration(migrations.Migration): verbose_name="expiration", ), ), + migrations.AddField( + model_name="mailaccount", + name="account_type", + field=models.PositiveIntegerField( + choices=[(1, "IMAP"), (2, "Gmail"), (3, "Outlook")], + default=1, + verbose_name="account type", + ), + ), migrations.AddField( model_name="mailaccount", name="refresh_token", diff --git a/src/paperless_mail/models.py b/src/paperless_mail/models.py index 231b01659..0ffce38bf 100644 --- a/src/paperless_mail/models.py +++ b/src/paperless_mail/models.py @@ -15,6 +15,11 @@ class MailAccount(document_models.ModelWithOwner): SSL = 2, _("Use SSL") STARTTLS = 3, _("Use STARTTLS") + class MailAccountType(models.IntegerChoices): + IMAP = 1, _("IMAP") + GMAIL = 2, _("Gmail") + OUTLOOK = 3, _("Outlook") + name = models.CharField(_("name"), max_length=256, unique=True) imap_server = models.CharField(_("IMAP server"), max_length=256) @@ -51,6 +56,12 @@ class MailAccount(document_models.ModelWithOwner): ), ) + account_type = models.PositiveIntegerField( + _("account type"), + choices=MailAccountType.choices, + default=MailAccountType.IMAP, + ) + refresh_token = models.CharField( _("refresh token"), max_length=2048, diff --git a/src/paperless_mail/serialisers.py b/src/paperless_mail/serialisers.py index 9237b47de..40dac8cc7 100644 --- a/src/paperless_mail/serialisers.py +++ b/src/paperless_mail/serialisers.py @@ -39,6 +39,9 @@ class MailAccountSerializer(OwnedObjectSerializer): "user_can_change", "permissions", "set_permissions", + "account_type", + "refresh_token", + "expiration", ] def update(self, instance, validated_data): diff --git a/src/paperless_mail/views.py b/src/paperless_mail/views.py index 2a84e04ea..2c3d9dd77 100644 --- a/src/paperless_mail/views.py +++ b/src/paperless_mail/views.py @@ -63,6 +63,7 @@ class MailAccountTestView(GenericAPIView): ): existing_account = MailAccount.objects.get(pk=request.data["id"]) serializer.validated_data["password"] = existing_account.password + serializer.validated_data["account_type"] = existing_account.account_type serializer.validated_data["refresh_token"] = existing_account.refresh_token serializer.validated_data["expiration"] = existing_account.expiration @@ -109,12 +110,14 @@ class OauthCallbackView(GenericAPIView): if scope is not None and "google" in scope: # Google # Gmail setup guide: https://postmansmtp.com/how-to-configure-post-smtp-with-gmailgsuite-using-oauth/ + account_type = MailAccount.AccountType.GMAIL imap_server = "imap.gmail.com" defaults = { "name": f"Gmail OAuth {datetime.now()}", "username": "", "imap_security": MailAccount.ImapSecurity.SSL, "imap_port": 993, + "account_type": account_type, } token_request_uri = "https://accounts.google.com/o/oauth2/token" @@ -124,12 +127,14 @@ class OauthCallbackView(GenericAPIView): elif scope is None: # Outlook # Outlok setup guide: https://medium.com/@manojkumardhakad/python-read-and-send-outlook-mail-using-oauth2-token-and-graph-api-53de606ecfa1 + account_type = MailAccount.AccountType.OUTLOOK imap_server = "outlook.office365.com" defaults = { "name": f"Outlook OAuth {datetime.now()}", "username": "", "imap_security": MailAccount.ImapSecurity.SSL, "imap_port": 993, + "account_type": account_type, } token_request_uri = (