mirror of
https://github.com/wassname/talk.git
synced 2026-07-20 12:40:47 +08:00
feat: initial implementation (#2409)
This commit is contained in:
@@ -869,24 +869,27 @@ type DisableCommenting {
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## Email
|
||||
## EmailConfiguration
|
||||
################################################################################
|
||||
|
||||
type Email {
|
||||
type SMTP {
|
||||
secure: Boolean
|
||||
host: String
|
||||
port: Int
|
||||
authentication: Boolean
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
type EmailConfiguration {
|
||||
"""
|
||||
enabled when True, will enable the emailing functionality in Coral.
|
||||
enabled when true, will enable the emailing functionality in Coral.
|
||||
"""
|
||||
enabled: Boolean!
|
||||
|
||||
"""
|
||||
smtpURI is the SMTP connection url to send emails on.
|
||||
"""
|
||||
smtpURI: String @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
fromAddress is the email address that will be used to send emails from.
|
||||
"""
|
||||
fromAddress: String
|
||||
fromName: String
|
||||
fromEmail: String
|
||||
smtp: SMTP! @auth(roles: [ADMIN])
|
||||
}
|
||||
|
||||
################################################################################
|
||||
@@ -1148,7 +1151,7 @@ type Settings {
|
||||
"""
|
||||
email is the set of credentials and settings associated with the organization.
|
||||
"""
|
||||
email: Email! @auth(roles: [ADMIN, MODERATOR])
|
||||
email: EmailConfiguration! @auth(roles: [ADMIN, MODERATOR])
|
||||
|
||||
"""
|
||||
wordList will return a given list of words.
|
||||
@@ -2599,21 +2602,23 @@ input SettingsOIDCAuthIntegrationInput {
|
||||
issuer: String
|
||||
}
|
||||
|
||||
input SettingsEmailInput {
|
||||
input SettingsSMTPInput {
|
||||
secure: Boolean
|
||||
host: String
|
||||
port: Int
|
||||
authentication: Boolean
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
input SettingsEmailConfigurationInput {
|
||||
"""
|
||||
enabled when True, will enable the emailing functionality in Coral.
|
||||
"""
|
||||
enabled: Boolean
|
||||
|
||||
"""
|
||||
smtpURI is the SMTP connection url to send emails on.
|
||||
"""
|
||||
smtpURI: String
|
||||
|
||||
"""
|
||||
fromAddress is the email address that will be used to send emails from.
|
||||
"""
|
||||
fromAddress: String
|
||||
smtp: SettingsSMTPInput
|
||||
fromName: String
|
||||
fromEmail: String
|
||||
}
|
||||
|
||||
input SettingsWordListInput {
|
||||
@@ -3048,7 +3053,7 @@ input SettingsInput {
|
||||
"""
|
||||
email is the set of credentials and settings associated with the organization.
|
||||
"""
|
||||
email: SettingsEmailInput
|
||||
email: SettingsEmailConfigurationInput
|
||||
|
||||
"""
|
||||
auth contains all the settings related to authentication and authorization.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { LocalProfile, User } from "coral-server/models/user";
|
||||
|
||||
/**
|
||||
* getLocalProfile will get the LocalProfile from the User if it exists.
|
||||
*
|
||||
* @param user the User to pull the LocalProfile out of
|
||||
*/
|
||||
export function getLocalProfile(
|
||||
user: Pick<User, "profiles">
|
||||
): LocalProfile | undefined {
|
||||
return user.profiles.find(({ type }) => type === "local") as
|
||||
| LocalProfile
|
||||
| undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* hasLocalProfile will return true if the User has a LocalProfile, optionally
|
||||
* checking the email on it as well.
|
||||
*
|
||||
* @param user the User to pull the LocalProfile out of
|
||||
* @param withEmail when specified, will ensure that the LocalProfile has the
|
||||
* specific email provided
|
||||
*/
|
||||
export function hasLocalProfile(
|
||||
user: Pick<User, "profiles">,
|
||||
withEmail?: string
|
||||
): boolean {
|
||||
const profile = getLocalProfile(user);
|
||||
if (!profile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (withEmail && profile.id !== withEmail) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Omit } from "coral-common/types";
|
||||
import {
|
||||
GQLAuth,
|
||||
GQLEmailConfiguration,
|
||||
GQLFacebookAuthIntegration,
|
||||
GQLGoogleAuthIntegration,
|
||||
GQLLiveConfiguration,
|
||||
@@ -13,6 +14,8 @@ import {
|
||||
|
||||
export type LiveConfiguration = Omit<GQLLiveConfiguration, "configurable">;
|
||||
|
||||
export type EmailConfiguration = GQLEmailConfiguration;
|
||||
|
||||
export interface GlobalModerationSettings {
|
||||
live: LiveConfiguration;
|
||||
moderation: GQLMODERATION_MODE;
|
||||
@@ -77,7 +80,6 @@ export type Settings = GlobalModerationSettings &
|
||||
Pick<
|
||||
GQLSettings,
|
||||
| "charCount"
|
||||
| "email"
|
||||
| "karma"
|
||||
| "wordList"
|
||||
| "integrations"
|
||||
@@ -93,6 +95,12 @@ export type Settings = GlobalModerationSettings &
|
||||
*/
|
||||
auth: Auth;
|
||||
|
||||
/**
|
||||
* email is the set of credentials and settings associated with the
|
||||
* organization.
|
||||
*/
|
||||
email: EmailConfiguration;
|
||||
|
||||
/**
|
||||
* closeCommenting contains settings related to the automatic closing of commenting on
|
||||
* Stories.
|
||||
|
||||
@@ -158,6 +158,7 @@ export async function createTenant(
|
||||
},
|
||||
email: {
|
||||
enabled: false,
|
||||
smtp: {},
|
||||
},
|
||||
karma: {
|
||||
enabled: true,
|
||||
|
||||
@@ -6,9 +6,10 @@ import htmlToText from "html-to-text";
|
||||
import Joi from "joi";
|
||||
import { JSDOM } from "jsdom";
|
||||
import { juiceResources } from "juice";
|
||||
import { camelCase } from "lodash";
|
||||
import { camelCase, isNil } from "lodash";
|
||||
import { Db } from "mongodb";
|
||||
import { createTransport } from "nodemailer";
|
||||
import { Options } from "nodemailer/lib/smtp-connection";
|
||||
import now from "performance-now";
|
||||
|
||||
import { LanguageCode } from "coral-common/helpers/i18n/locales";
|
||||
@@ -202,24 +203,28 @@ export const createJobProcessor = (options: MailProcessorOptions) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const { enabled, smtpURI, fromAddress } = tenant.email;
|
||||
const { enabled, smtp, fromEmail, fromName } = tenant.email;
|
||||
if (!enabled) {
|
||||
log.error("not sending email, it was disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!smtpURI) {
|
||||
log.error("email was enabled but the smtpURI configuration was missing");
|
||||
// Check that we have enough to generate the smtp credentials.
|
||||
if (isNil(smtp.secure) || isNil(smtp.host) || isNil(smtp.port)) {
|
||||
log.error("email enabled, but configuration is incomplete");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fromAddress) {
|
||||
if (!fromEmail) {
|
||||
log.error(
|
||||
"email was enabled but the fromAddress configuration was missing"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct the fromAddress.
|
||||
const fromAddress = fromName ? `${fromName} <${fromEmail}>` : fromEmail;
|
||||
|
||||
const startTemplateGenerationTime = now();
|
||||
|
||||
// Get the message to send.
|
||||
@@ -242,8 +247,24 @@ export const createJobProcessor = (options: MailProcessorOptions) => {
|
||||
let transport = cache.get(tenantID);
|
||||
if (!transport) {
|
||||
try {
|
||||
// Create the new transport options.
|
||||
const opts: Options = {
|
||||
host: smtp.host,
|
||||
port: smtp.port,
|
||||
secure: smtp.secure,
|
||||
};
|
||||
if (smtp.authentication && smtp.username && smtp.password) {
|
||||
// If authentication details are provided, add them to the transport
|
||||
// configuration.
|
||||
opts.auth = {
|
||||
type: "login",
|
||||
user: smtp.username,
|
||||
pass: smtp.password,
|
||||
};
|
||||
}
|
||||
|
||||
// Create the transport based on the smtp uri.
|
||||
transport = createTransport(smtpURI);
|
||||
transport = createTransport(opts);
|
||||
} catch (err) {
|
||||
throw new InternalError(err, "could not create email transport");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user