mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-25 09:30:31 +00:00
Implementation for gmail server with OAuth2 started
This commit is contained in:
parent
0ceb12f74f
commit
8f91437701
32
cps/admin.py
32
cps/admin.py
@ -39,7 +39,7 @@ from sqlalchemy.orm.attributes import flag_modified
|
||||
from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError
|
||||
from sqlalchemy.sql.expression import func, or_
|
||||
|
||||
from . import constants, logger, helper, services
|
||||
from . import constants, logger, helper, services, gmail
|
||||
from .cli import filepicker
|
||||
from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils
|
||||
from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash
|
||||
@ -1319,14 +1319,24 @@ def edit_mailsettings():
|
||||
@admin_required
|
||||
def update_mailsettings():
|
||||
to_save = request.form.to_dict()
|
||||
|
||||
_config_string(to_save, "mail_server")
|
||||
_config_int(to_save, "mail_port")
|
||||
_config_int(to_save, "mail_use_ssl")
|
||||
_config_string(to_save, "mail_login")
|
||||
_config_string(to_save, "mail_password")
|
||||
_config_string(to_save, "mail_from")
|
||||
_config_int(to_save, "mail_size", lambda y: int(y)*1024*1024)
|
||||
_config_int(to_save, "mail_server_type")
|
||||
if to_save.get("invalidate_server"):
|
||||
config.mail_gmail_token = {}
|
||||
try:
|
||||
flag_modified(config, "mail_gmail_token")
|
||||
except AttributeError:
|
||||
pass
|
||||
elif to_save.get("gmail"):
|
||||
config.mail_gmail_token = gmail.setup_gmail(config)
|
||||
flash(_(u"G-Mail Account Verification Successfull"), category="success")
|
||||
else:
|
||||
_config_string(to_save, "mail_server")
|
||||
_config_int(to_save, "mail_port")
|
||||
_config_int(to_save, "mail_use_ssl")
|
||||
_config_string(to_save, "mail_login")
|
||||
_config_string(to_save, "mail_password")
|
||||
_config_string(to_save, "mail_from")
|
||||
_config_int(to_save, "mail_size", lambda y: int(y)*1024*1024)
|
||||
try:
|
||||
config.save()
|
||||
except (OperationalError, InvalidRequestError):
|
||||
@ -1338,8 +1348,8 @@ def update_mailsettings():
|
||||
if current_user.email:
|
||||
result = send_test_mail(current_user.email, current_user.name)
|
||||
if result is None:
|
||||
flash(_(u"Test e-mail queued for sending to %(email)s, please check Tasks for result", email=current_user.email),
|
||||
category="info")
|
||||
flash(_(u"Test e-mail queued for sending to %(email)s, please check Tasks for result",
|
||||
email=current_user.email), category="info")
|
||||
else:
|
||||
flash(_(u"There was an error sending the Test e-mail: %(res)s", res=result), category="error")
|
||||
else:
|
||||
|
@ -39,7 +39,7 @@ class _Flask_Settings(_Base):
|
||||
__tablename__ = 'flask_settings'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
flask_session_key = Column(BLOB, default="")
|
||||
flask_session_key = Column(BLOB, default=b"")
|
||||
|
||||
def __init__(self, key):
|
||||
self.flask_session_key = key
|
||||
@ -58,6 +58,8 @@ class _Settings(_Base):
|
||||
mail_password = Column(String, default='mypassword')
|
||||
mail_from = Column(String, default='automailer <mail@example.com>')
|
||||
mail_size = Column(Integer, default=25*1024*1024)
|
||||
mail_server_type = Column(SmallInteger, default=0)
|
||||
mail_gmail_token = Column(JSON, default={})
|
||||
|
||||
config_calibre_dir = Column(String)
|
||||
config_port = Column(Integer, default=constants.DEFAULT_PORT)
|
||||
@ -246,7 +248,8 @@ class _ConfigSQL(object):
|
||||
return {k:v for k, v in self.__dict__.items() if k.startswith('mail_')}
|
||||
|
||||
def get_mail_server_configured(self):
|
||||
return not bool(self.mail_server == constants.DEFAULT_MAIL_SERVER)
|
||||
return bool((self.mail_server != constants.DEFAULT_MAIL_SERVER and self.mail_server_type == 0)
|
||||
or (self.mail_gmail_token != b"" and self.mail_server_type == 1))
|
||||
|
||||
|
||||
def set_from_dictionary(self, dictionary, field, convertor=None, default=None, encode=None):
|
||||
@ -364,10 +367,14 @@ def _migrate_table(session, orm_class):
|
||||
if isinstance(column.default.arg, bool):
|
||||
column_default = ("DEFAULT %r" % int(column.default.arg))
|
||||
else:
|
||||
column_default = ("DEFAULT %r" % column.default.arg)
|
||||
column_default = ("DEFAULT '%r'" % column.default.arg)
|
||||
if isinstance(column.type, JSON):
|
||||
column_type = "JSON"
|
||||
else:
|
||||
column_type = column.type
|
||||
alter_table = "ALTER TABLE %s ADD COLUMN `%s` %s %s" % (orm_class.__tablename__,
|
||||
column_name,
|
||||
column.type,
|
||||
column_type,
|
||||
column_default)
|
||||
log.debug(alter_table)
|
||||
session.execute(alter_table)
|
||||
|
64
cps/gmail.py
Normal file
64
cps/gmail.py
Normal file
@ -0,0 +1,64 @@
|
||||
from __future__ import print_function
|
||||
import os.path
|
||||
from googleapiclient.discovery import build
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
from google.oauth2.credentials import Credentials
|
||||
from .constants import BASE_DIR
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
subject = "Test"
|
||||
msg = "Testnachricht"
|
||||
sender = "matthias1.knopp@googlemail.com"
|
||||
receiver = "matthias.knopp@web.de"
|
||||
|
||||
SCOPES = ['https://www.googleapis.com/auth/gmail.send']
|
||||
|
||||
def setup_gmail(config):
|
||||
token = config.mail_gmail_token
|
||||
# if config.mail_gmail_token != "{}":
|
||||
# If there are no (valid) credentials available, let the user log in.
|
||||
creds = None
|
||||
if "token" in token:
|
||||
creds = Credentials(
|
||||
token=token['token'],
|
||||
refresh_token=token['refresh_token'],
|
||||
token_uri=token['token_uri'],
|
||||
client_id=token['client_id'],
|
||||
client_secret=token['client_secret'],
|
||||
scopes=token['scopes'],
|
||||
)
|
||||
creds.expiry = datetime.fromisoformat(token['expiry'])
|
||||
|
||||
if not creds or not creds.valid:
|
||||
# don't forget to dump one more time after the refresh
|
||||
# also, some file-locking routines wouldn't be needless
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
os.path.join(BASE_DIR, 'gmail.json'), SCOPES)
|
||||
creds = flow.run_local_server(port=0)
|
||||
|
||||
return {
|
||||
'token': creds.token,
|
||||
'refresh_token': creds.refresh_token,
|
||||
'token_uri': creds.token_uri,
|
||||
'client_id': creds.client_id,
|
||||
'client_secret': creds.client_secret,
|
||||
'scopes': creds.scopes,
|
||||
'expiry': creds.expiry.isoformat(),
|
||||
}
|
||||
|
||||
# implement your storage logic here, e.g. just good old json.dump() / json.load()
|
||||
|
||||
# service = build('gmail', 'v1', credentials=creds)
|
||||
# message = MIMEText(msg)
|
||||
# message['to'] = receiver
|
||||
# message['from'] = sender
|
||||
# message['subject'] = subject
|
||||
# raw = base64.urlsafe_b64encode(message.as_bytes())
|
||||
# raw = raw.decode()
|
||||
# body = {'raw' : raw}
|
||||
# message = (service.users().messages().send(userId='me', body=body).execute())
|
@ -8,43 +8,61 @@
|
||||
<h1>{{title}}</h1>
|
||||
<form role="form" class="col-md-10 col-lg-6" method="POST">
|
||||
<div class="form-group">
|
||||
<label for="mail_server">{{_('SMTP Hostname')}}</label>
|
||||
<input type="text" class="form-control" name="mail_server" id="mail_server" value="{{content.mail_server}}">
|
||||
<label for="mail_server_type">{{_('Choose Server Type')}}</label>
|
||||
<select name="mail_server_type" id="config_email_type" class="form-control" data-control="email-settings">
|
||||
<option value="0" {% if content.mail_server_type == 0 %}selected{% endif %}>{{_('Use Standard E-Mail Account')}}</option>
|
||||
<option value="1" {% if content.mail_server_type == 1 %}selected{% endif %}>{{_('G-Mail Account with OAuth2 Verfification')}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_port">{{_('SMTP Port')}}</label>
|
||||
<input type="number" min="1" max="65535" step="1" class="form-control" name="mail_port" id="mail_port" value="{% if content.mail_port != None %}{{ content.mail_port }}{% endif %}" autocomplete="off">
|
||||
<div data-related="email-settings-1">
|
||||
<div class="form-group">
|
||||
{% if content.mail_gmail_token == {} %}
|
||||
<button type="submit" id="gmail_server" name="gmail" value="submit" class="btn btn-default">{{_('Setup Gmail Account as E-Mail Server')}}</button>
|
||||
{% else %}
|
||||
<button type="submit" id="invalidate_server" name="invalidate" value="submit" class="btn btn-danger">{{_('Revoke G-Mail Access')}}</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_use_ssl">{{_('Encryption')}}</label>
|
||||
<select name="mail_use_ssl" id="mail_use_ssl" class="form-control">
|
||||
<option value="0" {% if content.mail_use_ssl == 0 %}selected{% endif %}>{{ _('None') }}</option>
|
||||
<option value="1" {% if content.mail_use_ssl == 1 %}selected{% endif %}>{{ _('STARTTLS') }}</option>
|
||||
<option value="2" {% if content.mail_use_ssl == 2 %}selected{% endif %}>{{ _('SSL/TLS') }}</option>
|
||||
</select>
|
||||
<div data-related="email-settings-0">
|
||||
<div class="form-group">
|
||||
<label for="mail_server">{{_('SMTP Hostname')}}</label>
|
||||
<input type="text" class="form-control" name="mail_server" id="mail_server" value="{{content.mail_server}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_port">{{_('SMTP Port')}}</label>
|
||||
<input type="number" min="1" max="65535" step="1" class="form-control" name="mail_port" id="mail_port" value="{% if content.mail_port != None %}{{ content.mail_port }}{% endif %}" autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_use_ssl">{{_('Encryption')}}</label>
|
||||
<select name="mail_use_ssl" id="mail_use_ssl" class="form-control">
|
||||
<option value="0" {% if content.mail_use_ssl == 0 %}selected{% endif %}>{{ _('None') }}</option>
|
||||
<option value="1" {% if content.mail_use_ssl == 1 %}selected{% endif %}>{{ _('STARTTLS') }}</option>
|
||||
<option value="2" {% if content.mail_use_ssl == 2 %}selected{% endif %}>{{ _('SSL/TLS') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_login">{{_('SMTP Login')}}</label>
|
||||
<input type="text" class="form-control" name="mail_login" id="mail_login" value="{{content.mail_login}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_password">{{_('SMTP Password')}}</label>
|
||||
<input type="password" class="form-control" name="mail_password" id="mail_password" value="{{content.mail_password}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_from">{{_('From E-mail')}}</label>
|
||||
<input type="text" class="form-control" name="mail_from" id="mail_from" value="{{content.mail_from}}">
|
||||
</div>
|
||||
<label for="mail_size">{{_('Attachment Size Limit')}}</label>
|
||||
<div class="form-group input-group">
|
||||
<input type="number" min="1" max="600" step="1" class="form-control" name="mail_size" id="mail_size" value="{% if content.mail_size != None %}{{ (content.mail_size / 1024 / 1024)|int }}{% endif %}" required>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="attachement_size" class="btn btn-default" disabled>MB</button>
|
||||
</span>
|
||||
</div>
|
||||
<button type="submit" name="submit" value="submit" class="btn btn-default">{{_('Save')}}</button>
|
||||
<button type="submit" name="test" value="test" class="btn btn-default">{{_('Save and Send Test E-mail')}}</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_login">{{_('SMTP Login')}}</label>
|
||||
<input type="text" class="form-control" name="mail_login" id="mail_login" value="{{content.mail_login}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_password">{{_('SMTP Password')}}</label>
|
||||
<input type="password" class="form-control" name="mail_password" id="mail_password" value="{{content.mail_password}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail_from">{{_('From E-mail')}}</label>
|
||||
<input type="text" class="form-control" name="mail_from" id="mail_from" value="{{content.mail_from}}">
|
||||
</div>
|
||||
<label for="mail_size">{{_('Attachment Size Limit')}}</label>
|
||||
<div class="form-group input-group">
|
||||
<input type="number" min="1" max="600" step="1" class="form-control" name="mail_size" id="mail_size" value="{% if content.mail_size != None %}{{ (content.mail_size / 1024 / 1024)|int }}{% endif %}" required>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="attachement_size" class="btn btn-default" disabled>MB</button>
|
||||
</span>
|
||||
</div>
|
||||
<button type="submit" name="submit" value="submit" class="btn btn-default">{{_('Save')}}</button>
|
||||
<button type="submit" name="test" value="test" class="btn btn-default">{{_('Save and Send Test E-mail')}}</button>
|
||||
<a href="{{ url_for('admin.admin') }}" id="back" class="btn btn-default">{{_('Cancel')}}</a>
|
||||
<a href="{{ url_for('admin.admin') }}" id="back" class="btn btn-default">{{_('Cancel')}}</a>
|
||||
</form>
|
||||
{% if g.allow_registration %}
|
||||
<div class="col-md-10 col-lg-6">
|
||||
|
@ -1,9 +1,9 @@
|
||||
# GDrive Integration
|
||||
google-api-python-client>=1.7.11,<1.13.0
|
||||
google-api-python-client>=1.7.11,<2.1.0
|
||||
gevent>20.6.0,<21.2.0
|
||||
greenlet>=0.4.17,<1.1.0
|
||||
httplib2>=0.9.2,<0.18.0
|
||||
oauth2client>=4.0.0,<4.1.4
|
||||
# oauth2client>=4.0.0,<4.1.4
|
||||
uritemplate>=3.0.0,<3.1.0
|
||||
pyasn1-modules>=0.0.8,<0.3.0
|
||||
pyasn1>=0.1.9,<0.5.0
|
||||
|
Loading…
Reference in New Issue
Block a user