diff --git a/cps/admin.py b/cps/admin.py index b3df370f..e938f3a1 100644 --- a/cps/admin.py +++ b/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: diff --git a/cps/config_sql.py b/cps/config_sql.py index f35d1dd1..de1ee6d4 100644 --- a/cps/config_sql.py +++ b/cps/config_sql.py @@ -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_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) diff --git a/cps/gmail.py b/cps/gmail.py new file mode 100644 index 00000000..50b60e85 --- /dev/null +++ b/cps/gmail.py @@ -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()) diff --git a/cps/templates/email_edit.html b/cps/templates/email_edit.html index 9df0a385..60b96c9f 100644 --- a/cps/templates/email_edit.html +++ b/cps/templates/email_edit.html @@ -8,43 +8,61 @@

{{title}}

- - + +
-
- - +
+
+ {% if content.mail_gmail_token == {} %} + + {% else %} + + {% endif %} +
-
- - +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + + + +
+ +
-
- - -
-
- - -
-
- - -
- -
- - - - -
- - - {{_('Cancel')}} + {{_('Cancel')}} {% if g.allow_registration %}
diff --git a/optional-requirements.txt b/optional-requirements.txt index 3283777b..547f0256 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -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