forked from frappe/mail
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request frappe#46 from s-aga-r/mono-repo
refactor!: Mail
- Loading branch information
Showing
171 changed files
with
10,360 additions
and
3,152 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Diff not rendered.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<template> | ||
<h1 class="font-semibold mb-8">Account</h1> | ||
<div class="flex items-center mb-3"> | ||
<span class="font-medium leading-normal text-gray-800 text-base">Email Address</span> | ||
<Link | ||
v-model="email" | ||
doctype="Mail Account" | ||
:filters="{ user: userResource.data?.name }" | ||
class="ml-auto" | ||
/> | ||
</div> | ||
<div v-if="account.doc" class="space-y-1.5"> | ||
<Switch | ||
label="Enabled" | ||
v-model="account.doc.enabled" | ||
@update:modelValue="account.setValue.submit({ enabled: account.doc.enabled })" | ||
/> | ||
<Switch | ||
label="Default Outgoing" | ||
v-model="account.doc.is_default" | ||
@update:modelValue="account.setValue.submit({ is_default: account.doc.is_default })" | ||
/> | ||
<Switch | ||
label="Track Outgoing Mail" | ||
v-model="account.doc.track_outgoing_mail" | ||
@update:modelValue=" | ||
account.setValue.submit({ track_outgoing_mail: account.doc.track_outgoing_mail }) | ||
" | ||
/> | ||
<Switch | ||
label="Create Mail Contact" | ||
v-model="account.doc.create_mail_contact" | ||
@update:modelValue=" | ||
account.setValue.submit({ create_mail_contact: account.doc.create_mail_contact }) | ||
" | ||
/> | ||
<div class="mx-2.5 space-y-2.5 pt-0.5"> | ||
<div class="flex items-center justify-between"> | ||
<span class="font-medium leading-normal text-gray-800 text-base"> | ||
Display Name | ||
</span> | ||
<TextInput | ||
v-model="account.doc.display_name" | ||
@input=" | ||
account.setValueDebounced.submit({ | ||
display_name: account.doc.display_name, | ||
}) | ||
" | ||
/> | ||
</div> | ||
<div class="flex items-center justify-between"> | ||
<span class="font-medium leading-normal text-gray-800 text-base">Reply To</span> | ||
<TextInput | ||
v-model="account.doc.reply_to" | ||
@input="account.setValueDebounced.submit({ reply_to: account.doc.reply_to })" | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
<script setup> | ||
import { ref, watch, onMounted } from 'vue' | ||
import { Switch, TextInput, createDocumentResource } from 'frappe-ui' | ||
import Link from '@/components/Controls/Link.vue' | ||
import { userStore } from '@/stores/user' | ||
const { userResource, defaultOutgoing } = userStore() | ||
const email = ref(defaultOutgoing.data) | ||
const fetchMailAccount = () => { | ||
account.name = email.value | ||
account.reload() | ||
} | ||
onMounted(fetchMailAccount) | ||
watch(email, fetchMailAccount) | ||
const account = createDocumentResource({ | ||
doctype: 'Mail Account', | ||
name: email.value, | ||
auto: false, | ||
transform(data) { | ||
for (const d of ['enabled', 'is_default', 'track_outgoing_mail', 'create_mail_contact']) { | ||
data[d] = !!data[d] | ||
} | ||
}, | ||
}) | ||
</script> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
from dataclasses import dataclass, field | ||
from typing import Any, Literal | ||
from urllib.parse import urljoin | ||
|
||
import frappe | ||
import requests | ||
from frappe import _ | ||
|
||
|
||
@dataclass | ||
class Principal: | ||
"""Dataclass to represent a principal.""" | ||
|
||
name: str | ||
type: Literal["domain", "apiKey", "individual"] | ||
id: int = 0 | ||
quota: int = 0 | ||
description: str = "" | ||
secrets: str | list[str] = field(default_factory=list) | ||
emails: list[str] = field(default_factory=list) | ||
urls: list[str] = field(default_factory=list) | ||
memberOf: list[str] = field(default_factory=list) | ||
roles: list[str] = field(default_factory=list) | ||
lists: list[str] = field(default_factory=list) | ||
members: list[str] = field(default_factory=list) | ||
enabledPermissions: list[str] = field(default_factory=list) | ||
disabledPermissions: list[str] = field(default_factory=list) | ||
externalMembers: list[str] = field(default_factory=list) | ||
|
||
|
||
class AgentAPI: | ||
"""Class to interact with the Agent.""" | ||
|
||
def __init__( | ||
self, | ||
base_url: str, | ||
api_key: str | None = None, | ||
username: str | None = None, | ||
password: str | None = None, | ||
) -> None: | ||
self.base_url = base_url | ||
self.__api_key = api_key | ||
self.__username = username | ||
self.__password = password | ||
self.__session = requests.Session() | ||
|
||
self.__auth = None | ||
self.__headers = {} | ||
if self.__api_key: | ||
self.__headers.update({"Authorization": f"Bearer {self.__api_key}"}) | ||
else: | ||
if not self.__username or not self.__password: | ||
frappe.throw(_("API Key or Username and Password is required.")) | ||
|
||
self.__auth = (self.__username, self.__password) | ||
|
||
def request( | ||
self, | ||
method: str, | ||
endpoint: str, | ||
params: dict | None = None, | ||
data: dict | None = None, | ||
json: dict | None = None, | ||
files: dict | None = None, | ||
headers: dict[str, str] | None = None, | ||
timeout: int | tuple[int, int] = (60, 120), | ||
) -> Any | None: | ||
"""Makes an HTTP request to the Agent.""" | ||
|
||
url = urljoin(self.base_url, endpoint) | ||
|
||
headers = headers or {} | ||
headers.update(self.__headers) | ||
|
||
if files: | ||
headers.pop("content-type", None) | ||
|
||
response = self.__session.request( | ||
method=method, | ||
url=url, | ||
params=params, | ||
data=data, | ||
headers=headers, | ||
files=files, | ||
auth=self.__auth, | ||
timeout=timeout, | ||
json=json, | ||
) | ||
response.raise_for_status() | ||
|
||
return response.json() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,35 @@ | ||
import frappe | ||
from frappe import _ | ||
|
||
from mail.utils.user import has_role, is_mailbox_owner | ||
from mail.utils.validation import ( | ||
validate_mailbox_for_incoming, | ||
validate_mailbox_for_outgoing, | ||
) | ||
from mail.utils.user import has_role, is_mail_account_owner | ||
|
||
|
||
@frappe.whitelist(methods=["POST"]) | ||
def validate(mailbox: str | None = None, for_inbound: bool = False, for_outbound: bool = False) -> None: | ||
"""Validates the mailbox for inbound and outbound emails.""" | ||
def validate(account: str | None = None) -> None: | ||
"""Validates the account for inbound and outbound emails.""" | ||
|
||
if mailbox: | ||
if account: | ||
validate_user() | ||
validate_mailbox(mailbox) | ||
|
||
if for_inbound: | ||
validate_mailbox_for_incoming(mailbox) | ||
|
||
if for_outbound: | ||
validate_mailbox_for_outgoing(mailbox) | ||
validate_account(account) | ||
|
||
|
||
def validate_user() -> None: | ||
"""Validates if the user has the required role to access mailboxes.""" | ||
"""Validates if the user has the required role to access mail accounts.""" | ||
|
||
user = frappe.session.user | ||
|
||
if not has_role(user, "Mailbox User"): | ||
frappe.throw(_("User {0} is not allowed to access mailboxes.").format(frappe.bold(user))) | ||
if not has_role(user, "Mail User"): | ||
frappe.throw(_("User {0} is not allowed to access mail accounts.").format(frappe.bold(user))) | ||
|
||
|
||
def validate_mailbox(mailbox: str) -> None: | ||
"""Validates if the mailbox is associated with the user.""" | ||
def validate_account(account: str) -> None: | ||
"""Validates if the mail account is associated with the user.""" | ||
|
||
user = frappe.session.user | ||
|
||
if not is_mailbox_owner(mailbox, user): | ||
if not is_mail_account_owner(account, user): | ||
frappe.throw( | ||
_("Mailbox {0} is not associated with user {1}").format(frappe.bold(mailbox), frappe.bold(user)) | ||
_("Mail Account {0} is not associated with user {1}").format( | ||
frappe.bold(account), frappe.bold(user) | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import frappe | ||
from frappe import _ | ||
|
||
from mail.mail.doctype.ip_blacklist.ip_blacklist import get_blacklist_for_ip_address | ||
|
||
|
||
@frappe.whitelist(methods=["GET"], allow_guest=True) | ||
def get(ip_address: str) -> dict: | ||
"""Returns the blacklist for the given IP address.""" | ||
|
||
if not ip_address: | ||
frappe.throw(_("IP address is required."), frappe.MandatoryError) | ||
|
||
return get_blacklist_for_ip_address(ip_address, create_if_not_exists=True, commit=True) or {} |
Oops, something went wrong.