* feat(api): dynamic-api 1/2
* feat(api): dynamic-api 2/2
feat(api): core-api 1/2
* feat(api): changed schemas
feat(api): aipkey authorizer
feat(api): jwt authorizer payload
feat(api): core-api 2/3
* feat(api): apikey authorizer
feat(api): shared context
feat(api): response editor
feat(api): middleware
feat(api): custom router
feat(api): fix auth double call
* feat(api): dashboard
feat(api): insights
feat(api): public api v1
* feat(api): allow full CORS
* feat(api): use decouple-config instead of env
feat(api): fixed conflict slack endpoint
feat(api): fixed favorite errors param
* feat(api): migration fixes
* feat(api): changes
* feat(api): crons
* feat(api): changes and fixes
* feat(api): added new endpoints
feat(api): applied new changes
feat(api): Docker image
* feat(api): EE 1/4
* feat(api): EE core_dynamic
* feat(api): global routers generator
* feat(api): project authorizer
feat(api): docker image
feat(api): crons
* feat(api): EE trace activity
* feat(api): changed ORRouter
* feat(api): EE trace activity parameters&payload
* feat(api): EE trace activity action name & path_format
* feat(db): user trace
* feat(api): EE trace activity ignore routes and hide attribute
feat(api): fix funnel payload schema
* feat(api): mobile support
* feat(api): changed build script
* feat(api): changed mobile sign endpoint
feat(api): changed requirements.txt
* feat(api): changed dockerfile
* feat(api): changed mobile-env-var
* feat(api): removed insights
* feat(api): changed EE Dockerfile
* feat(api): cast session_id to str for signing
* feat(api): fixed error_id type
* feat(api): fixed /errors priority conflict
* feat(api): fixed /errors/{errorId} default params
* feat(api): fixed change password after invitation
* feat(api): use background task for emails instead of low-timeout-api
feat(api): EE fixed missing required params
* feat(api): funnel-insights payload change
* feat(api): funnel-insights payload change
* feat(api): changed edit user payload schema
* feat(api): changed metrics payload schema
* feat(api): changed metrics payload schema
* feat(api): changed edit user default values
feat(api): fixed change error status route
* feat(api): changed edit user
* feat(api): stop user from changing his own role
* feat(api): changed add slack
* feat(api): changed get funnel
* feat(api): changed get funnel on the fly payload
feat(api): changed update payload
* feat(api): changed get funnel on the fly payload
* feat(api): changed update funnel payload
* feat(api): changed get funnel-sessions/issues on the fly payload
* feat(api): fixed funnel missing rangeValue
* feat(api): fixes
* feat(api): iceServers configuration
* feat(api): fix issueId casting
* feat(api): changed issues-sessions endpoint payload-schema
* feat(api): EE changed traces-ignored-routes
* feat(api): EE include core sessions.py
* feat(api): EE check licence on every request if expired
* feat(api): move general stats to dynamic
* feat(api): code cleanup
feat(api): removed sentry
* feat(api): changed traces-ignore-routes
* feat(api): changed dependencies
* feat(api): changed jwt-auth-response code
* feat(api): changed traces-ignore-routes
* feat(api): changed traces-ignore-routes
* feat(api): removed PyTZ
feat(api): migrated time-helper to zoneinfo
* feat(api): EE added missing dependency
feat(api): changed base docker image
* feat(api): merge after roles
* feat(api): EE roles fastapi
* feat(db): handel HTTPExceptions
* feat(db): changed payload schema
* feat(db): changed payload schema
* feat(api): included insights
* feat(api): removed unused helper
* feat(api): merge from dev to fatsapi
* feat(api): merge fixes
feat(api): SAML migration
* feat(api): changed GET /signup response
feat(api): changed EE Dockerfile
* feat(api): changed edition detection
* feat(api): include ee endpoints
* feat(api): add/edit member changes
* feat(api): saml changed redirect
* feat(api): track session's replay
feat(api): track error's details
* feat(api): ignore tracking for read roles
* feat(api): define global queue
feat(api): define global scheduler
feat(api): traces use queue
feat(api): traces batch insert
feat(DB): changed traces schema
* feat(api): fix signup captcha
* feat(api): fix signup captcha
* feat(api): optional roleId
feat(api): set roleId to member if None
* feat(api): fixed edit role
* feat(api): return role details when creating a new member
* feat(api): trace: use BackgroundTasks instead of BackgroundTask to not override previous tasks
* feat(api): trace: use BackgroundTask if no other background task is defined
* feat(api): optimised delete metadata
* feat(api): Notification optional message
* feat(api): fix background-task reference
* feat(api): fix trace-background-task
* feat(api): fixed g-captcha for reset password
* feat(api): fix edit self-user
* feat(api): fixed create github-issue
* feat(api): set misfire_grace_time for crons
* feat(api): removed chalice
feat(api): freeze dependencies
* feat(api): refactored blueprints
* feat(api): /metadata/session_search allow projectId=None
* feat(api): public API, changed userId type
* feat(api): fix upload sourcemaps
* feat(api): user-trace support ApiKey endpoints
* feat(api): fixed user-trace foreign key type
* feat(api): fixed trace schema
* feat(api): trace save auth-method
* feat(api): trace fixed auth-method
* feat(api): trace changed schema
90 lines
3 KiB
Python
90 lines
3 KiB
Python
import base64
|
|
import re
|
|
from email.header import Header
|
|
from email.mime.image import MIMEImage
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email.mime.text import MIMEText
|
|
|
|
from chalicelib.utils import helper, smtp
|
|
from decouple import config
|
|
|
|
|
|
def __get_subject(subject):
|
|
return subject
|
|
|
|
|
|
def __get_html_from_file(source, formatting_variables):
|
|
if formatting_variables is None:
|
|
formatting_variables = {}
|
|
formatting_variables["frontend_url"] = config("SITE_URL")
|
|
with open(source, "r") as body:
|
|
BODY_HTML = body.read()
|
|
if formatting_variables is not None and len(formatting_variables.keys()) > 0:
|
|
BODY_HTML = re.sub(r"%(?![(])", "%%", BODY_HTML)
|
|
BODY_HTML = BODY_HTML % {**formatting_variables}
|
|
return BODY_HTML
|
|
|
|
|
|
def __replace_images(HTML):
|
|
pattern_holder = re.compile(r'<img[\w\W\n]+?(src="[a-zA-Z0-9.+\/\\-]+")')
|
|
pattern_src = re.compile(r'src="(.*?)"')
|
|
mime_img = []
|
|
swap = []
|
|
for m in re.finditer(pattern_holder, HTML):
|
|
sub = m.groups()[0]
|
|
sub = str(re.findall(pattern_src, sub)[0])
|
|
if sub not in swap:
|
|
swap.append(sub)
|
|
HTML = HTML.replace(sub, f"cid:img-{len(mime_img)}")
|
|
sub = "chalicelib/utils/html/" + sub
|
|
with open(sub, "rb") as image_file:
|
|
img = base64.b64encode(image_file.read()).decode('utf-8')
|
|
mime_img.append(MIMEImage(base64.standard_b64decode(img)))
|
|
mime_img[-1].add_header('Content-ID', f'<img-{len(mime_img) - 1}>')
|
|
return HTML, mime_img
|
|
|
|
|
|
def send_html(BODY_HTML, SUBJECT, recipient, bcc=None):
|
|
BODY_HTML, mime_img = __replace_images(BODY_HTML)
|
|
if not isinstance(recipient, list):
|
|
recipient = [recipient]
|
|
msg = MIMEMultipart()
|
|
msg['Subject'] = Header(__get_subject(SUBJECT), 'utf-8')
|
|
msg['From'] = config("EMAIL_FROM")
|
|
msg['To'] = ""
|
|
body = MIMEText(BODY_HTML.encode('utf-8'), 'html', "utf-8")
|
|
msg.attach(body)
|
|
for m in mime_img:
|
|
msg.attach(m)
|
|
|
|
with smtp.SMTPClient() as s:
|
|
for r in recipient:
|
|
msg.replace_header("To", r)
|
|
r = [r]
|
|
if bcc is not None and len(bcc) > 0:
|
|
r += [bcc]
|
|
try:
|
|
print(f"Email sending to: {r}")
|
|
s.sendmail(msg['FROM'], r, msg.as_string().encode('ascii'))
|
|
except Exception as e:
|
|
print("!!! Email error!")
|
|
print(e)
|
|
|
|
|
|
def send_text(recipients, text, subject):
|
|
with smtp.SMTPClient() as s:
|
|
msg = MIMEMultipart()
|
|
msg['Subject'] = Header(__get_subject(subject), 'utf-8')
|
|
msg['From'] = config("EMAIL_FROM")
|
|
msg['To'] = ", ".join(recipients)
|
|
body = MIMEText(text)
|
|
msg.attach(body)
|
|
try:
|
|
s.sendmail(msg['FROM'], recipients, msg.as_string().encode('ascii'))
|
|
except Exception as e:
|
|
print("!! Text-email failed: " + subject),
|
|
print(e)
|
|
|
|
|
|
def __escape_text_html(text):
|
|
return text.replace("@", "<span>@</span>").replace(".", "<span>.</span>").replace("=", "<span>=</span>")
|