[mail] Refactor queue for easier maintenance, use name

We thought the name parameter was the account name to be shown in the
plugin, but it is the contents of the "From" email header instead.

While changing that, we also update the code to better match the open
Pull Request upstream that adds the update-account to the mail plugin
for nextcloud.
mejoras_instalacion
Evilham 2022-10-17 17:46:29 +02:00
parent 3102b3c1f4
commit 559a90fba9
No known key found for this signature in database
GPG Key ID: AE3EE30D970886BF
5 changed files with 168 additions and 78 deletions

View File

@ -69,6 +69,7 @@ COPY supervisord.conf /
# Temporary replacement for a real queue # Temporary replacement for a real queue
RUN echo '*/1 * * * * /nc-queue.sh' >> /etc/crontabs/www-data RUN echo '*/1 * * * * /nc-queue.sh' >> /etc/crontabs/www-data
COPY nc-queue.sh / COPY nc-queue.sh /
COPY nc-mail-update.sh /
COPY saml.sh / COPY saml.sh /
ENV NEXTCLOUD_UPDATE=1 ENV NEXTCLOUD_UPDATE=1

View File

@ -0,0 +1,50 @@
#!/bin/sh -eu
OCC="${OCC:-/var/www/html/occ}"
#
# For this user, obtain lines formatted as: EmailAccountId:Email
#
get_mail_accounts() {
"$OCC" mail:account:export "$1" | \
grep -E '^([^-]|- E-Mail)' | tr -d '\n' | \
sed -Ee 's!(Account|- E-Mail: )!!g' | tr -d ' ' '\n' || true
}
# User-specific
user_id="$1"
account_name="$2"
email="$3"
email_password="$4"
# Server settings
inbound_host="$5"
inbound_port="$6"
inbound_ssl_mode="$7"
outbound_host="$8"
outbound_port="$9"
outbound_ssl_mode="${10}"
existing_mail_accounts="$(get_mail_accounts "$user_id")"
if [ -n "${existing_mail_accounts:-}" ]; then
# Use the first one, it was likely created by DD
account_id="$(echo "${existing_mail_accounts}" | head -n 1 | cut -d ':' -f 1)"
fi
if [ -z "${account_id:-}" ]; then
# Create account
"$OCC" mail:account:create \
"$user_id" "$account_name" "$email" \
"$inbound_host" "$inbound_port" "$inbound_ssl_mode" \
"$email" "$email_password" \
"$outbound_host" "$outbound_port" "$outbound_ssl_mode" \
"$email" "$email_password"
else
# Update account
"$OCC" mail:account:update \
--imap-host "$inbound_host" --imap-port "$inbound_port" --imap-ssl-mode "$inbound_ssl_mode" \
--imap-user "$email" --imap-password "$email_password" \
--smtp-host "$outbound_host" --smtp-port "$outbound_port" --smtp-ssl-mode "$outbound_ssl_mode" \
--smtp-user "$email" --smtp-password "$email_password" \
--name "$account_name" --email "$email" \
-- "$account_id"
fi

View File

@ -1,5 +1,5 @@
#/bin/sh #!/bin/sh
find "${NC_MAIL_QUEUE_FOLDER:-/nc-mail-queue}" -name '*.sh' -exec sh -c \ find "${NC_MAIL_QUEUE_FOLDER:-/nc-mail-queue}" -name '*.sh' -exec sh -c \
'cd /var/www/html && {} && rm {}' \ 'i="$1"; "$i" && rm "$i"' shell {} \
';' ';'

View File

@ -24,6 +24,7 @@ namespace OCA\Mail\Command;
use OCA\Mail\Db\MailAccountMapper; use OCA\Mail\Db\MailAccountMapper;
use OCP\Security\ICrypto; use OCP\Security\ICrypto;
use OCP\AppFramework\Db\DoesNotExistException;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
@ -31,8 +32,10 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
class UpdateAccount extends Command { class UpdateAccount extends Command {
public const ARGUMENT_USER_ID = 'user-id'; public const ARGUMENT_ACCOUNT_ID = 'account-id';
public const ARGUMENT_NAME = 'name';
public const ARGUMENT_EMAIL = 'email'; public const ARGUMENT_EMAIL = 'email';
public const ARGUMENT_AUTH_METHOD = 'auth-method';
public const ARGUMENT_IMAP_HOST = 'imap-host'; public const ARGUMENT_IMAP_HOST = 'imap-host';
public const ARGUMENT_IMAP_PORT = 'imap-port'; public const ARGUMENT_IMAP_PORT = 'imap-port';
public const ARGUMENT_IMAP_SSL_MODE = 'imap-ssl-mode'; public const ARGUMENT_IMAP_SSL_MODE = 'imap-ssl-mode';
@ -44,6 +47,7 @@ class UpdateAccount extends Command {
public const ARGUMENT_SMTP_USER = 'smtp-user'; public const ARGUMENT_SMTP_USER = 'smtp-user';
public const ARGUMENT_SMTP_PASSWORD = 'smtp-password'; public const ARGUMENT_SMTP_PASSWORD = 'smtp-password';
/** @var mapper */ /** @var mapper */
private $mapper; private $mapper;
@ -63,8 +67,10 @@ class UpdateAccount extends Command {
protected function configure() { protected function configure() {
$this->setName('mail:account:update'); $this->setName('mail:account:update');
$this->setDescription('Update a user\'s IMAP account'); $this->setDescription('Update a user\'s IMAP account');
$this->addArgument(self::ARGUMENT_USER_ID, InputArgument::REQUIRED); $this->addArgument(self::ARGUMENT_ACCOUNT_ID, InputArgument::REQUIRED);
$this->addArgument(self::ARGUMENT_EMAIL, InputArgument::REQUIRED);
$this->addOption(self::ARGUMENT_NAME, '', InputOption::VALUE_OPTIONAL);
$this->addOption(self::ARGUMENT_EMAIL, '', InputOption::VALUE_OPTIONAL);
$this->addOption(self::ARGUMENT_IMAP_HOST, '', InputOption::VALUE_OPTIONAL); $this->addOption(self::ARGUMENT_IMAP_HOST, '', InputOption::VALUE_OPTIONAL);
$this->addOption(self::ARGUMENT_IMAP_PORT, '', InputOption::VALUE_OPTIONAL); $this->addOption(self::ARGUMENT_IMAP_PORT, '', InputOption::VALUE_OPTIONAL);
@ -77,11 +83,15 @@ class UpdateAccount extends Command {
$this->addOption(self::ARGUMENT_SMTP_SSL_MODE, '', InputOption::VALUE_OPTIONAL); $this->addOption(self::ARGUMENT_SMTP_SSL_MODE, '', InputOption::VALUE_OPTIONAL);
$this->addOption(self::ARGUMENT_SMTP_USER, '', InputOption::VALUE_OPTIONAL); $this->addOption(self::ARGUMENT_SMTP_USER, '', InputOption::VALUE_OPTIONAL);
$this->addOption(self::ARGUMENT_SMTP_PASSWORD, '', InputOption::VALUE_OPTIONAL); $this->addOption(self::ARGUMENT_SMTP_PASSWORD, '', InputOption::VALUE_OPTIONAL);
$this->addOption(self::ARGUMENT_AUTH_METHOD, '', InputOption::VALUE_OPTIONAL);
} }
protected function execute(InputInterface $input, OutputInterface $output): int { protected function execute(InputInterface $input, OutputInterface $output): int {
$userId = $input->getArgument(self::ARGUMENT_USER_ID); $accountId = (int)$input->getArgument(self::ARGUMENT_ACCOUNT_ID);
$email = $input->getArgument(self::ARGUMENT_EMAIL);
$name = $input->getOption(self::ARGUMENT_NAME);
$email = $input->getOption(self::ARGUMENT_EMAIL);
$imapHost = $input->getOption(self::ARGUMENT_IMAP_HOST); $imapHost = $input->getOption(self::ARGUMENT_IMAP_HOST);
$imapPort = $input->getOption(self::ARGUMENT_IMAP_PORT); $imapPort = $input->getOption(self::ARGUMENT_IMAP_PORT);
@ -94,10 +104,30 @@ class UpdateAccount extends Command {
$smtpSslMode = $input->getOption(self::ARGUMENT_SMTP_SSL_MODE); $smtpSslMode = $input->getOption(self::ARGUMENT_SMTP_SSL_MODE);
$smtpUser = $input->getOption(self::ARGUMENT_SMTP_USER); $smtpUser = $input->getOption(self::ARGUMENT_SMTP_USER);
$smtpPassword = $input->getOption(self::ARGUMENT_SMTP_PASSWORD); $smtpPassword = $input->getOption(self::ARGUMENT_SMTP_PASSWORD);
$authMethod = $input->getOption(self::ARGUMENT_AUTH_METHOD);
$mailAccount = $this->mapper->findByUserIdAndEmail($userId, $email); try {
$mailAccount = $this->mapper->findById($accountId);
} catch (DoesNotExistException $e) {
$output->writeln("<error>No Email Account found with ID $accountId </error>");
return 1;
}
$output->writeLn("<info>Found account with email: " . $mailAccount->getEmail() . "</info>");
//ACCOUNT OPTIONS
if ($input->getOption(self::ARGUMENT_NAME)) {
$mailAccount->setName($name);
}
if ($input->getOption(self::ARGUMENT_EMAIL)) {
$mailAccount->setEmail($email);
}
//AUTH METHOD
if ($input->getOption(self::ARGUMENT_AUTH_METHOD)) {
$mailAccount->setAuthMethod($authMethod);
}
if ($mailAccount) {
//INBOUND //INBOUND
if ($input->getOption(self::ARGUMENT_IMAP_HOST)) { if ($input->getOption(self::ARGUMENT_IMAP_HOST)) {
$mailAccount->setInboundHost($imapHost); $mailAccount->setInboundHost($imapHost);
@ -143,12 +173,7 @@ class UpdateAccount extends Command {
$this->mapper->save($mailAccount); $this->mapper->save($mailAccount);
$output->writeln("<info>Account $email for user $userId succesfully updated </info>"); $output->writeln("<info>Account " . $mailAccount->getEmail() . " with ID $accountId succesfully updated </info>");
return 1;
} else {
$output->writeln("<info>No Email Account $email found for user $userId </info>");
}
return 0; return 0;
} }
} }

View File

@ -139,23 +139,32 @@ class Admin:
res = res and tp.delete_user(user_id) res = res and tp.delete_user(user_id)
return res return res
def _nextcloud_mail_set_cmd(self, user : DDUser, kw : Dict) -> Tuple[str, str]: def _nextcloud_mail_set_cmd(self, user: DDUser, kw: Dict) -> str:
account_name = 'DD' # Treating this as a constant from shlex import quote as q
update_cmd = f"""mail:account:update \
--imap-host '{ kw['inbound_host'] }' --imap-port '{ kw['inbound_port'] }' --imap-ssl-mode '{ kw['inbound_ssl_mode'] }' \\ account_name = user.get("name", "DD User")
--imap-user '{ user['email'] }' --imap-password '{ user['password'] }' \\
--smtp-host '{ kw['outbound_host'] }' --smtp-port '{ kw['outbound_port'] }' --smtp-ssl-mode '{ kw['outbound_ssl_mode'] }' \\ nc_mail_update = "/nc-mail-update.sh"
--smtp-user '{ user['email'] }' --smtp-password '{ user['password'] }' \\ # As defined in nc-mail-update.sh
-- '{ user['user_id'] }' '{ user['email']}'""" unquoted_args = [
create_cmd = f"""mail:account:create '{ user['user_id'] }' '{ account_name }' '{ user['email'] }' \\ # User-specific
'{ kw['inbound_host'] }' '{ kw['inbound_port'] }' '{ kw['inbound_ssl_mode'] }' \\ user["user_id"],
'{ user['email'] }' '{ user['password'] }' \\ account_name,
'{ kw['outbound_host'] }' '{ kw['outbound_port'] }' '{ kw['outbound_ssl_mode'] }' \\ user["email"],
'{ user['email'] }' '{ user['password'] }'""" user["password"],
return (update_cmd, create_cmd) # Server settings
kw.get("inbound_host", ""),
kw.get("inbound_port", ""),
kw.get("inbound_ssl_mode", ""),
kw.get("outbound_host", ""),
kw.get("outbound_port", ""),
kw.get("outbound_ssl_mode", ""),
]
args = [q(str(a) if a else '') for a in unquoted_args]
return " ".join([nc_mail_update] + args)
def _nextcloud_mail_set_sh(self, users: List[DDUser], extra_data: Dict) -> str: def _nextcloud_mail_set_sh(self, users: List[DDUser], extra_data: Dict) -> str:
cmds = '\n'.join((f"./occ {u} || ./occ {c}" for u, c in (self._nextcloud_mail_set_cmd(u, extra_data) for u in users))) cmds = "\n".join((self._nextcloud_mail_set_cmd(u, extra_data) for u in users))
return f"""#!/bin/sh -eu return f"""#!/bin/sh -eu
{cmds} {cmds}
""" """
@ -170,10 +179,15 @@ class Admin:
tmp = d.joinpath(fn + '.tmp') tmp = d.joinpath(fn + '.tmp')
# Create executable file # Create executable file
tmp.touch(mode=0o750) tmp.touch(mode=0o750)
try:
# Write script # Write script
tmp.write_text(self._nextcloud_mail_set_sh(users, extra_data)) tmp.write_text(self._nextcloud_mail_set_sh(users, extra_data))
# Put it in-place # Put it in-place
tmp.rename(sh) tmp.rename(sh)
except:
log.error(traceback.format_exc())
log.error("Issue writing mail changes...")
raise
return {} return {}
def check_connections(self, app : "AdminFlaskApp") -> None: def check_connections(self, app : "AdminFlaskApp") -> None: