diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 23019de..aec596b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,6 @@ repos: rev: v4.5.0 hooks: - id: check-merge-conflict - - id: check-json - id: debug-statements - id: mixed-line-ending args: [--fix=lf] diff --git a/CHANGELOG.md b/CHANGELOG.md index 93a58ee..024b555 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,3 +12,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/). codebase - Use host 0.0.0.0 for test servers - Fix bug with example-flask-peewee import +- Fix bug with example-cherrypy import (Specify parent package name when importing setting, local_setting modules) +- Changed the DB session creation, DB connection closing, and DB model creation to align with SQLAlchemy 2. (for example-flask program) +- Removed flask-script package from requirements.txt as it doesn't work with recent flasks (programs: example-flask, example-flask-mongoengine, example-flask-peewee) +- Configured the manage.py file to use the CLI environment built into flask (programs: example-flask, example-flask-mongoengine, example-flask-peewee) as the flask-script package has been removed +- Changed the part that binds the DB session to comply with SQLAlchemy 2 (for example-pyramid program) +- Changed the part that fetches authenticated users from DB to be SQLAlchemy 2 based (for example-pyramid program) +- Removed all entries in the SOCIAL_AUTH_KEYS dictionary in local_settings.py.template into a single variable (tests showed that adding provider-supplied key information in SOCIAL_AUTH_KEYS caused errors on social login) (for example-pyramid program) +- Changed the DB model creation part. (for example-pyramid program) +- Error occurred when social login integration was completed because it was supposed to find google plus ID in the redirected URL. google plus is discontinued, so delete the part that gets plus ID. (for example-pyramid program) +- Changed the part that binds the DB session and creates the Base Model class to comply with SQLAlchemy 2 (for example-tornado, example-webpy program) +- Added local_settings.py.template file to reference other programs to easily generate local_settings.py (for example-tornado, example-webpy program) +- Fixed an error importing the local_settings module from settings.py (for the example-tornado program) +- Change the declaration of the Model class based on SQLAlchemy 2 (corresponds to the example-tornado, example-webpy program) +- Fix bug with example-webpy import +- Separated AUTHENTICATION_BACKENDS and PIPELINE entries into separate settings.py entries as web.config entries in app.py (for example-webpy program) \ No newline at end of file diff --git a/example-cherrypy/example/app.py b/example-cherrypy/example/app.py index 3ee8cea..1cb6ff7 100644 --- a/example-cherrypy/example/app.py +++ b/example-cherrypy/example/app.py @@ -1,12 +1,11 @@ import os -import sys import cherrypy -import settings from common import filters from common.utils import common_context, url_for +from example import settings from jinja2 import Environment, FileSystemLoader -from social_cherrypy.utils import backends, load_strategy +from social_cherrypy.utils import load_strategy from social_cherrypy.views import CherryPyPSAViews from social_core.utils import setting_name @@ -15,7 +14,9 @@ from .db.user import User BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -DATABASE_NAME = "sqlite:///{dbname}".format(dbname=os.path.join(BASE_DIR, "db.sqlite3")) +DATABASE_NAME = "sqlite:///{dbname}".format( # fix: skip + dbname=os.path.join(BASE_DIR, "db.sqlite3") +) SAEnginePlugin(cherrypy.engine, DATABASE_NAME).subscribe() @@ -38,9 +39,9 @@ def render_home(self): cherrypy.config[setting_name("AUTHENTICATION_BACKENDS")], load_strategy(), user=getattr(cherrypy.request, "user", None), - plus_id=cherrypy.config.get(setting_name("SOCIAL_AUTH_GOOGLE_PLUS_KEY")), ) - return cherrypy.tools.jinja2env.get_template("home.html").render(**context) + jinja2env = cherrypy.tools.jinja2env + return jinja2env.get_template("home.html").render(**context) def load_user(): @@ -56,22 +57,24 @@ def session_commit(): def get_settings(module): + not_in_items = ["__builtins__", "__file__"] return { key: value for key, value in module.__dict__.items() - if key not in module.__builtins__ and key not in ["__builtins__", "__file__"] + if key not in module.__builtins__ and key not in not_in_items } SOCIAL_SETTINGS = get_settings(settings) try: - import local_settings + from example import local_settings SOCIAL_SETTINGS.update(get_settings(local_settings)) except ImportError: raise RuntimeError( - "Define a local_settings.py using " "local_settings.py.template as base" + "Define a local_settings.py using " # fix: skip + "local_settings.py.template as base" ) @@ -82,7 +85,7 @@ def run_app(listen_address="0.0.0.0:8001"): "server.socket_port": int(port), "server.socket_host": host, "tools.sessions.on": True, - "tools.sessions.storage_type": "ram", + "tools.sessions.storage_class": cherrypy.lib.sessions.RamSession, "tools.db.on": True, "tools.authenticate.on": True, "SOCIAL_AUTH_USER_MODEL": "example.db.user.User", diff --git a/example-cherrypy/example/db/__init__.py b/example-cherrypy/example/db/__init__.py index 860e542..fa2b68a 100644 --- a/example-cherrypy/example/db/__init__.py +++ b/example-cherrypy/example/db/__init__.py @@ -1,3 +1,5 @@ -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import DeclarativeBase -Base = declarative_base() + +class Base(DeclarativeBase): + pass diff --git a/example-cherrypy/example/db/saplugin.py b/example-cherrypy/example/db/saplugin.py index b670615..82005a7 100644 --- a/example-cherrypy/example/db/saplugin.py +++ b/example-cherrypy/example/db/saplugin.py @@ -1,13 +1,13 @@ from cherrypy.process import plugins from sqlalchemy import create_engine -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import Session class SAEnginePlugin(plugins.SimplePlugin): def __init__(self, bus, connection_string=None): self.sa_engine = None self.connection_string = connection_string - self.session = scoped_session(sessionmaker(autoflush=True, autocommit=False)) + self.session = Session(autoflush=True, autocommit=False) super().__init__(bus) def start(self): @@ -23,14 +23,14 @@ def stop(self): self.sa_engine = None def bind(self): - self.session.configure(bind=self.sa_engine) + self.session.bind = self.sa_engine return self.session def commit(self): try: self.session.commit() - except: + except Exception: self.session.rollback() raise finally: - self.session.remove() + self.session.close() diff --git a/example-cherrypy/example/db/user.py b/example-cherrypy/example/db/user.py index 2fc69bf..48a57cf 100644 --- a/example-cherrypy/example/db/user.py +++ b/example-cherrypy/example/db/user.py @@ -1,16 +1,19 @@ -from sqlalchemy import Boolean, Column, Integer, String +from typing import Optional + +from sqlalchemy import String +from sqlalchemy.orm import Mapped, mapped_column from . import Base class User(Base): __tablename__ = "users" - id = Column(Integer, primary_key=True) - username = Column(String(200)) - password = Column(String(200), default="") - name = Column(String(100)) - email = Column(String(200)) - active = Column(Boolean, default=True) + id: Mapped[int] = mapped_column(primary_key=True) + username: Mapped[str] = mapped_column(String(200)) + password: Mapped[str] = mapped_column(String(200), default="") + name: Mapped[Optional[str]] = mapped_column(String(100)) + email: Mapped[Optional[str]] = mapped_column(String(200)) + active: Mapped[bool] = mapped_column(default=True) def is_active(self): return self.active diff --git a/example-cherrypy/manage.py b/example-cherrypy/manage.py index 2833953..8c87f24 100755 --- a/example-cherrypy/manage.py +++ b/example-cherrypy/manage.py @@ -2,6 +2,9 @@ import sys import cherrypy +from example.app import DATABASE_NAME, run_app +from example.db import Base +from social_cherrypy.models import SocialBase from sqlalchemy import create_engine cherrypy.config.update( @@ -10,11 +13,6 @@ } ) -from example.app import DATABASE_NAME, run_app -from example.db import Base -from example.db.user import User -from social_cherrypy.models import SocialBase - if __name__ == "__main__": if len(sys.argv) > 1 and sys.argv[1] == "syncdb": engine = create_engine(DATABASE_NAME) diff --git a/example-common/filters.py b/example-common/filters.py index 27c1c9e..b0ef3df 100644 --- a/example-common/filters.py +++ b/example-common/filters.py @@ -38,15 +38,22 @@ def icon_name(name): def slice_by(value, items): - return [value[n : n + items] for n in range(0, len(value), items)] + return [ + value[n : n + items] # fix: skip # noqa: E203 + for n in range(0, len(value), items) + ] def social_backends(backends): - return filter_backends(backends, lambda name, backend: name not in LEGACY_NAMES) + return filter_backends( # fix: skip + backends, lambda name, backend: name not in LEGACY_NAMES + ) def legacy_backends(backends): - return filter_backends(backends, lambda name, backend: name in LEGACY_NAMES) + return filter_backends( # fix: skip + backends, lambda name, backend: name in LEGACY_NAMES + ) def oauth_backends(backends): diff --git a/example-common/pipeline.py b/example-common/pipeline.py index 3c6e0ba..aeb16a8 100644 --- a/example-common/pipeline.py +++ b/example-common/pipeline.py @@ -11,11 +11,15 @@ def require_email(strategy, details, user=None, is_new=False, *args, **kwargs): details["email"] = email else: current_partial = kwargs.get("current_partial") - return strategy.redirect(f"/email?partial_token={current_partial.token}") + return strategy.redirect( # fix: skip + f"/email?partial_token={current_partial.token}" + ) @partial -def require_country(strategy, details, user=None, is_new=False, *args, **kwargs): +def require_country( # fix: skip + strategy, details, user=None, is_new=False, *args, **kwargs +): if kwargs.get("ajax"): return elif is_new and not details.get("country"): @@ -24,7 +28,9 @@ def require_country(strategy, details, user=None, is_new=False, *args, **kwargs) details["country"] = country else: current_partial = kwargs.get("current_partial") - return strategy.redirect(f"/country?partial_token={current_partial.token}") + return strategy.redirect( # fix: skip + f"/country?partial_token={current_partial.token}" + ) @partial @@ -37,4 +43,6 @@ def require_city(strategy, details, user=None, is_new=False, *args, **kwargs): details["city"] = city else: current_partial = kwargs.get("current_partial") - return strategy.redirect(f"/city?partial_token={current_partial.token}") + return strategy.redirect( # fix: skip + f"/city?partial_token={current_partial.token}" + ) diff --git a/example-common/utils.py b/example-common/utils.py index 7698b5e..f282433 100644 --- a/example-common/utils.py +++ b/example-common/utils.py @@ -16,7 +16,9 @@ def associations(user, strategy): return list(user_associations) -def common_context(authentication_backends, strategy, user=None, plus_id=None, **extra): +def common_context( # fix: skip + authentication_backends, strategy, user=None, plus_id=None, **extra +): """Common view context""" context = { "user": user, diff --git a/example-django-mongoengine/app/admin.py b/example-django-mongoengine/app/admin.py index 8c38f3f..4fd5490 100644 --- a/example-django-mongoengine/app/admin.py +++ b/example-django-mongoengine/app/admin.py @@ -1,3 +1,3 @@ -from django.contrib import admin +from django.contrib import admin # noqa: F401 # Register your models here. diff --git a/example-django-mongoengine/app/decorators.py b/example-django-mongoengine/app/decorators.py index 09f4007..2bbad50 100644 --- a/example-django-mongoengine/app/decorators.py +++ b/example-django-mongoengine/app/decorators.py @@ -24,7 +24,6 @@ def wrapper(request, *args, **kwargs): settings.AUTHENTICATION_BACKENDS, load_strategy(), request.user, - plus_id=getattr(settings, "SOCIAL_AUTH_GOOGLE_PLUS_KEY", None), **out ), ) diff --git a/example-django-mongoengine/app/mail.py b/example-django-mongoengine/app/mail.py index f01fceb..506e7b5 100644 --- a/example-django-mongoengine/app/mail.py +++ b/example-django-mongoengine/app/mail.py @@ -4,8 +4,10 @@ def send_validation(strategy, backend, code, partial_token): - url = "{}?verification_code={}&partial_token={}".format( - reverse("social:complete", args=(backend.name,)), code.code, partial_token + url = "{}?verification_code={}&partial_token={}".format( # fix: skip + reverse("social:complete", args=(backend.name,)), # fix: skip + code.code, + partial_token, ) url = strategy.request.build_absolute_uri(url) send_mail( diff --git a/example-django-mongoengine/app/templatetags/backend_utils.py b/example-django-mongoengine/app/templatetags/backend_utils.py index 03032dc..03af81c 100644 --- a/example-django-mongoengine/app/templatetags/backend_utils.py +++ b/example-django-mongoengine/app/templatetags/backend_utils.py @@ -49,7 +49,10 @@ def social_backends(backends): if name not in ["username", "email"] ] backends.sort(key=lambda b: b[0]) - return [backends[n : n + 10] for n in range(0, len(backends), 10)] + return [ + backends[n : n + 10] # fix: skip # noqa: E203 + for n in range(0, len(backends), 10) + ] @register.filter @@ -80,7 +83,9 @@ def associated(context, backend): context["association"] = None if user and user.is_authenticated(): try: - context["association"] = user.social_auth.filter(provider=backend.name)[0] + context["association"] = user.social_auth.filter( # fix: skip + provider=backend.name + )[0] except IndexError: pass return "" diff --git a/example-django-mongoengine/app/tests.py b/example-django-mongoengine/app/tests.py index 7ce503c..e55d689 100644 --- a/example-django-mongoengine/app/tests.py +++ b/example-django-mongoengine/app/tests.py @@ -1,3 +1,3 @@ -from django.test import TestCase +from django.test import TestCase # noqa: F401 # Create your tests here. diff --git a/example-django-mongoengine/app/views.py b/example-django-mongoengine/app/views.py index 5e24d72..0c7d7a4 100644 --- a/example-django-mongoengine/app/views.py +++ b/example-django-mongoengine/app/views.py @@ -1,14 +1,11 @@ import json -from django.conf import settings from django.contrib.auth import login from django.contrib.auth import logout as auth_logout from django.contrib.auth.decorators import login_required from django.http import HttpResponse, HttpResponseBadRequest from django.shortcuts import redirect -from social_core.backends.google import GooglePlusAuth from social_core.backends.oauth import BaseOAuth1, BaseOAuth2 -from social_core.backends.utils import load_backends from social_django.utils import load_strategy, psa from .decorators import render_to diff --git a/example-django-mongoengine/example/settings.py b/example-django-mongoengine/example/settings.py index 87728e9..ab95178 100644 --- a/example-django-mongoengine/example/settings.py +++ b/example-django-mongoengine/example/settings.py @@ -237,18 +237,34 @@ # Password validation # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators +UserAttributeSimilarityValidator = ( # fix: skip + "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" +) + +MinimumLengthValidator = ( # fix: skip + "django.contrib.auth.password_validation.MinimumLengthValidator" +) + +CommonPasswordValidator = ( # fix: skip + "django.contrib.auth.password_validation.CommonPasswordValidator" +) + +NumericPasswordValidator = ( # fix: skip + "django.contrib.auth.password_validation.NumericPasswordValidator" +) + AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + "NAME": UserAttributeSimilarityValidator, }, { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "NAME": MinimumLengthValidator, }, { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + "NAME": CommonPasswordValidator, }, { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + "NAME": NumericPasswordValidator, }, ] @@ -273,6 +289,6 @@ STATIC_URL = "/static/" try: - from example.local_settings import * + from example.local_settings import * # noqa: F401,F403 except ImportError: pass diff --git a/example-django-mongoengine/example/urls.py b/example-django-mongoengine/example/urls.py index 49e2fe7..71d21e4 100644 --- a/example-django-mongoengine/example/urls.py +++ b/example-django-mongoengine/example/urls.py @@ -9,7 +9,11 @@ url(r"^login/$", app_views.home), url(r"^logout/$", app_views.logout), url(r"^done/$", app_views.done, name="done"), - url(r"^ajax-auth/(?P[^/]+)/$", app_views.ajax_auth, name="ajax-auth"), + url( + r"^ajax-auth/(?P[^/]+)/$", # fix: skip + app_views.ajax_auth, + name="ajax-auth", + ), url(r"^email/$", app_views.require_email, name="require_email"), url(r"", include("social_django.urls")), ] diff --git a/example-django-mongoengine/manage.py b/example-django-mongoengine/manage.py index 72c4bb0..9036db9 100755 --- a/example-django-mongoengine/manage.py +++ b/example-django-mongoengine/manage.py @@ -11,7 +11,7 @@ # issue is really that Django is missing to avoid masking other # exceptions on Python 2. try: - import django + import django # noqa: F401 except ImportError: raise ImportError( "Couldn't import Django. Are you sure it's installed and " diff --git a/example-django/app/admin.py b/example-django/app/admin.py index 8c38f3f..4fd5490 100644 --- a/example-django/app/admin.py +++ b/example-django/app/admin.py @@ -1,3 +1,3 @@ -from django.contrib import admin +from django.contrib import admin # noqa: F401 # Register your models here. diff --git a/example-django/app/decorators.py b/example-django/app/decorators.py index 09f4007..2bbad50 100644 --- a/example-django/app/decorators.py +++ b/example-django/app/decorators.py @@ -24,7 +24,6 @@ def wrapper(request, *args, **kwargs): settings.AUTHENTICATION_BACKENDS, load_strategy(), request.user, - plus_id=getattr(settings, "SOCIAL_AUTH_GOOGLE_PLUS_KEY", None), **out ), ) diff --git a/example-django/app/mail.py b/example-django/app/mail.py index 40cc4cc..34b9ddb 100644 --- a/example-django/app/mail.py +++ b/example-django/app/mail.py @@ -4,8 +4,10 @@ def send_validation(strategy, backend, code, partial_token): - url = "{}?verification_code={}&partial_token={}".format( - reverse("social:complete", args=(backend.name,)), code.code, partial_token + url = "{}?verification_code={}&partial_token={}".format( # fix: skip + reverse("social:complete", args=(backend.name,)), # fix: skip + code.code, + partial_token, # fix: skip ) url = strategy.request.build_absolute_uri(url) send_mail( diff --git a/example-django/app/models.py b/example-django/app/models.py index 0cbb60a..9ec504b 100644 --- a/example-django/app/models.py +++ b/example-django/app/models.py @@ -1,5 +1,9 @@ from django.db import models -from social_django.models import USER_MODEL, AbstractUserSocialAuth, DjangoStorage +from social_django.models import ( # fix: skip + USER_MODEL, + AbstractUserSocialAuth, + DjangoStorage, +) class CustomUserSocialAuth(AbstractUserSocialAuth): diff --git a/example-django/app/templatetags/backend_utils.py b/example-django/app/templatetags/backend_utils.py index 740d72b..148b3a2 100644 --- a/example-django/app/templatetags/backend_utils.py +++ b/example-django/app/templatetags/backend_utils.py @@ -50,7 +50,10 @@ def social_backends(backends): if name not in ["username", "email"] ] backends.sort(key=lambda b: b[0]) - return [backends[n : n + 10] for n in range(0, len(backends), 10)] + return [ + backends[n : n + 10] # fix: skip # noqa: E203 + for n in range(0, len(backends), 10) + ] @register.filter diff --git a/example-django/app/tests.py b/example-django/app/tests.py index 7ce503c..e55d689 100644 --- a/example-django/app/tests.py +++ b/example-django/app/tests.py @@ -1,3 +1,3 @@ -from django.test import TestCase +from django.test import TestCase # noqa: F401 # Create your tests here. diff --git a/example-django/app/views.py b/example-django/app/views.py index ba61b75..31eadf0 100644 --- a/example-django/app/views.py +++ b/example-django/app/views.py @@ -1,14 +1,11 @@ import json -from django.conf import settings from django.contrib.auth import login from django.contrib.auth import logout as auth_logout from django.contrib.auth.decorators import login_required from django.http import HttpResponse, HttpResponseBadRequest from django.shortcuts import redirect -from social_core.backends.google import GooglePlusAuth from social_core.backends.oauth import BaseOAuth1, BaseOAuth2 -from social_core.backends.utils import load_backends from social_django.utils import load_strategy, psa from .decorators import render_to diff --git a/example-django/example/settings.py b/example-django/example/settings.py index 0aabcf6..ba7126b 100644 --- a/example-django/example/settings.py +++ b/example-django/example/settings.py @@ -236,18 +236,34 @@ # Password validation # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators +UserAttributeSimilarityValidator = ( # fix: skip + "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" +) + +MinimumLengthValidator = ( # fix: skip + "django.contrib.auth.password_validation.MinimumLengthValidator" +) + +CommonPasswordValidator = ( # fix: skip + "django.contrib.auth.password_validation.CommonPasswordValidator" +) + +NumericPasswordValidator = ( # fix: skip + "django.contrib.auth.password_validation.NumericPasswordValidator" +) + AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + "NAME": UserAttributeSimilarityValidator, }, { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + "NAME": MinimumLengthValidator, }, { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + "NAME": CommonPasswordValidator, }, { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + "NAME": NumericPasswordValidator, }, ] @@ -272,6 +288,6 @@ STATIC_URL = "/static/" try: - from example.local_settings import * + from example.local_settings import * # noqa: F401,F403 except ImportError: pass diff --git a/example-django/manage.py b/example-django/manage.py index 72c4bb0..9036db9 100755 --- a/example-django/manage.py +++ b/example-django/manage.py @@ -11,7 +11,7 @@ # issue is really that Django is missing to avoid masking other # exceptions on Python 2. try: - import django + import django # noqa: F401 except ImportError: raise ImportError( "Couldn't import Django. Are you sure it's installed and " diff --git a/example-flask-mongoengine/example/__init__.py b/example-flask-mongoengine/example/__init__.py index f86026b..748c239 100644 --- a/example-flask-mongoengine/example/__init__.py +++ b/example-flask-mongoengine/example/__init__.py @@ -3,7 +3,8 @@ from common import filters from common.utils import common_context from common.utils import url_for as common_url_for -from flask import Flask, g, url_for +from example import models +from flask import Flask, g from flask_login import LoginManager, current_user from flask_mongoengine import MongoEngine from social_flask.routes import social_auth @@ -14,7 +15,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # App -app = Flask(__name__, template_folder=os.path.join(BASE_DIR, "common", "templates")) +template_folder = os.path.join(BASE_DIR, "common", "templates") +app = Flask(__name__, template_folder=template_folder) app.config.from_object("example.settings") try: @@ -32,8 +34,6 @@ login_manager.login_message = "" login_manager.init_app(app) -from example import models, routes - @login_manager.user_loader def load_user(userid): diff --git a/example-flask-mongoengine/example/models/__init__.py b/example-flask-mongoengine/example/models/__init__.py index fde4944..f627dcd 100644 --- a/example-flask-mongoengine/example/models/__init__.py +++ b/example-flask-mongoengine/example/models/__init__.py @@ -1,2 +1,2 @@ -from example.models import user -from social_flask_sqlalchemy import models +from example.models import user # noqa: F401 +from social_flask_sqlalchemy import models # noqa: F401 diff --git a/example-flask-mongoengine/example/models/user.py b/example-flask-mongoengine/example/models/user.py index d37c0ac..6491716 100644 --- a/example-flask-mongoengine/example/models/user.py +++ b/example-flask-mongoengine/example/models/user.py @@ -1,6 +1,6 @@ from example import db from flask_login import UserMixin -from mongoengine import BooleanField, EmailField, ListField, ReferenceField, StringField +from mongoengine import BooleanField, EmailField, StringField from social_flask_mongoengine.models import FlaskStorage diff --git a/example-flask-mongoengine/example/routes/__init__.py b/example-flask-mongoengine/example/routes/__init__.py index 9797f20..50f2c6f 100644 --- a/example-flask-mongoengine/example/routes/__init__.py +++ b/example-flask-mongoengine/example/routes/__init__.py @@ -1,2 +1,2 @@ -from example.routes import main -from social_flask import routes +from example.routes import main # noqa: F401 +from social_flask import routes # noqa: F401 diff --git a/example-flask-mongoengine/example/settings.py b/example-flask-mongoengine/example/settings.py index a976f4b..84ae24f 100644 --- a/example-flask-mongoengine/example/settings.py +++ b/example-flask-mongoengine/example/settings.py @@ -1,5 +1,3 @@ -from os.path import abspath, dirname, join - SECRET_KEY = "random-secret-key" SESSION_COOKIE_NAME = "python_social_auth_mongoengine_session" DEBUG = True diff --git a/example-flask-mongoengine/manage.py b/example-flask-mongoengine/manage.py index 62e69c9..984146e 100755 --- a/example-flask-mongoengine/manage.py +++ b/example-flask-mongoengine/manage.py @@ -1,11 +1,17 @@ #!/usr/bin/env python +import click from example import app, db -from flask_script import Manager, Server, Shell +from flask.cli import FlaskGroup -manager = Manager(app) -manager.add_command("runserver", Server()) -manager.add_command("shell", Shell(make_context=lambda: {"app": app, "db": db})) + +@click.group(cls=FlaskGroup, create_app=lambda: app) +def cli(): + """Management script for the Example Flask Social Login application.""" + + @app.shell_context_processor + def make_shell_context(): + return dict(db=db) if __name__ == "__main__": - manager.run() + cli() diff --git a/example-flask-mongoengine/requirements.txt b/example-flask-mongoengine/requirements.txt index 3312328..f5591f7 100644 --- a/example-flask-mongoengine/requirements.txt +++ b/example-flask-mongoengine/requirements.txt @@ -1,4 +1,3 @@ -r ../requirements.txt -flask-script flask-mongoengine social-auth-app-flask-mongoengine diff --git a/example-flask-peewee/example/__init__.py b/example-flask-peewee/example/__init__.py index c9bf04c..e87807a 100644 --- a/example-flask-peewee/example/__init__.py +++ b/example-flask-peewee/example/__init__.py @@ -3,7 +3,7 @@ from common import filters from common.utils import common_context from common.utils import url_for as common_url_for -from flask import Flask, g, url_for +from flask import Flask, g from flask_login import LoginManager, current_user from peewee import SqliteDatabase from social_flask.routes import social_auth @@ -16,7 +16,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # App -app = Flask(__name__, template_folder=os.path.join(BASE_DIR, "common", "templates")) +template_folder = os.path.join(BASE_DIR, "common", "templates") +app = Flask(__name__, template_folder=template_folder) app.config.from_object("example.settings") try: @@ -36,8 +37,6 @@ login_manager.login_message = "" login_manager.init_app(app) -from example import models, routes - @login_manager.user_loader def load_user(userid): diff --git a/example-flask-peewee/example/models/__init__.py b/example-flask-peewee/example/models/__init__.py index d86b607..2515e67 100644 --- a/example-flask-peewee/example/models/__init__.py +++ b/example-flask-peewee/example/models/__init__.py @@ -1,2 +1,2 @@ -from example.models import user -from social_flask_peewee import models +from example.models import user # noqa: F401 +from social_flask_peewee import models # noqa: F401 diff --git a/example-flask-peewee/example/models/user.py b/example-flask-peewee/example/models/user.py index 4a94163..6b5b2f7 100644 --- a/example-flask-peewee/example/models/user.py +++ b/example-flask-peewee/example/models/user.py @@ -7,7 +7,8 @@ # model definitions -- the standard "pattern" is to define a base model class -# that specifies which database to use. then, any subclasses will automatically +# that specifies which database to use. +# then, any subclasses will automatically # use the correct storage. class BaseModel(Model): class Meta: diff --git a/example-flask-peewee/example/routes/__init__.py b/example-flask-peewee/example/routes/__init__.py index 9797f20..50f2c6f 100644 --- a/example-flask-peewee/example/routes/__init__.py +++ b/example-flask-peewee/example/routes/__init__.py @@ -1,2 +1,2 @@ -from example.routes import main -from social_flask import routes +from example.routes import main # noqa: F401 +from social_flask import routes # noqa: F401 diff --git a/example-flask-peewee/manage.py b/example-flask-peewee/manage.py index 4904628..f9d7f01 100755 --- a/example-flask-peewee/manage.py +++ b/example-flask-peewee/manage.py @@ -1,13 +1,15 @@ #!/usr/bin/env python -from example import app, database -from flask_script import Manager, Server, Shell +import click +from example import app +from flask.cli import FlaskGroup -manager = Manager(app) -manager.add_command("runserver", Server()) -manager.add_command("shell", Shell(make_context=lambda: {"app": app})) +@click.group(cls=FlaskGroup, create_app=lambda: app) +def cli(): + """Management script for the Example Flask Social Login application.""" -@manager.command + +@app.cli.command() def syncdb(): from example.models.user import User from social_flask_peewee.models import FlaskStorage @@ -25,4 +27,4 @@ def syncdb(): if __name__ == "__main__": - manager.run() + cli() diff --git a/example-flask-peewee/requirements.txt b/example-flask-peewee/requirements.txt index a57c0a8..100c350 100644 --- a/example-flask-peewee/requirements.txt +++ b/example-flask-peewee/requirements.txt @@ -1,3 +1,2 @@ -r ../requirements.txt -flask-script social-auth-app-flask-peewee diff --git a/example-flask/example/__init__.py b/example-flask/example/__init__.py index 88ee9f7..ac89c42 100644 --- a/example-flask/example/__init__.py +++ b/example-flask/example/__init__.py @@ -3,19 +3,21 @@ from common import filters from common.utils import common_context from common.utils import url_for as common_url_for -from flask import Flask, g, url_for +from example import models +from flask import Flask, g from flask_login import LoginManager, current_user from social_flask.routes import social_auth from social_flask.template_filters import backends from social_flask.utils import load_strategy from social_flask_sqlalchemy.models import init_social from sqlalchemy import create_engine -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import Session BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # App -app = Flask(__name__, template_folder=os.path.join(BASE_DIR, "common", "templates")) +template_folder = os.path.join(BASE_DIR, "common", "templates") +app = Flask(__name__, template_folder=template_folder) app.config.from_object("example.settings") try: @@ -25,8 +27,7 @@ # DB engine = create_engine(app.config["SQLALCHEMY_DATABASE_URI"]) -Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) -db_session = scoped_session(Session) +db_session = Session(engine, autocommit=False, autoflush=False) app.register_blueprint(social_auth) init_social(app, db_session) @@ -36,13 +37,11 @@ login_manager.login_message = "" login_manager.init_app(app) -from example import models, routes - @login_manager.user_loader def load_user(userid): try: - return models.user.User.query.get(int(userid)) + return db_session.get(models.user.User, int(userid)) except (TypeError, ValueError): pass @@ -60,7 +59,7 @@ def commit_on_success(error=None): else: db_session.rollback() - db_session.remove() + db_session.close() @app.context_processor diff --git a/example-flask/example/models/__init__.py b/example-flask/example/models/__init__.py index fde4944..f627dcd 100644 --- a/example-flask/example/models/__init__.py +++ b/example-flask/example/models/__init__.py @@ -1,2 +1,2 @@ -from example.models import user -from social_flask_sqlalchemy import models +from example.models import user # noqa: F401 +from social_flask_sqlalchemy import models # noqa: F401 diff --git a/example-flask/example/models/user.py b/example-flask/example/models/user.py index 2af04b7..0a7977c 100644 --- a/example-flask/example/models/user.py +++ b/example-flask/example/models/user.py @@ -1,20 +1,22 @@ -from example import db_session +from typing import Optional + from flask_login import UserMixin -from sqlalchemy import Boolean, Column, Integer, String -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import String +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + -Base = declarative_base() -Base.query = db_session.query_property() +class Base(DeclarativeBase): + pass class User(Base, UserMixin): __tablename__ = "users" - id = Column(Integer, primary_key=True) - username = Column(String(200)) - password = Column(String(200), default="") - name = Column(String(100)) - email = Column(String(200)) - active = Column(Boolean, default=True) + id: Mapped[int] = mapped_column(primary_key=True) + username: Mapped[str] = mapped_column(String(200)) + password: Mapped[str] = mapped_column(String(200), default="") + name: Mapped[Optional[str]] = mapped_column(String(100)) + email: Mapped[Optional[str]] = mapped_column(String(200)) + active: Mapped[bool] = mapped_column(default=True) def is_active(self): return self.active diff --git a/example-flask/example/routes/__init__.py b/example-flask/example/routes/__init__.py index 9797f20..50f2c6f 100644 --- a/example-flask/example/routes/__init__.py +++ b/example-flask/example/routes/__init__.py @@ -1,2 +1,2 @@ -from example.routes import main -from social_flask import routes +from example.routes import main # noqa: F401 +from social_flask import routes # noqa: F401 diff --git a/example-flask/manage.py b/example-flask/manage.py old mode 100755 new mode 100644 index 383962e..e334709 --- a/example-flask/manage.py +++ b/example-flask/manage.py @@ -1,15 +1,18 @@ -#!/usr/bin/env python +import click from example import app, db_session, engine -from flask_script import Manager, Server, Shell +from flask.cli import FlaskGroup -manager = Manager(app) -manager.add_command("runserver", Server()) -manager.add_command( - "shell", Shell(make_context=lambda: {"app": app, "db_session": db_session}) -) +@click.group(cls=FlaskGroup, create_app=lambda: app) +def cli(): + """Management script for the Example Flask Social Login application.""" -@manager.command + @app.shell_context_processor + def make_shell_context(): + return dict(db_session=db_session) + + +@app.cli.command() def syncdb(): from example.models import user from social_flask_sqlalchemy import models @@ -19,4 +22,4 @@ def syncdb(): if __name__ == "__main__": - manager.run() + cli() diff --git a/example-flask/requirements.txt b/example-flask/requirements.txt index 9ce1c8d..4f9fe7a 100644 --- a/example-flask/requirements.txt +++ b/example-flask/requirements.txt @@ -1,7 +1,6 @@ -r ../requirements.txt Flask Flask-Login -Flask-Script Werkzeug Jinja2 social-auth-app-flask diff --git a/example-pyramid/example/__init__.py b/example-pyramid/example/__init__.py index 5b8e7bb..422067f 100644 --- a/example-pyramid/example/__init__.py +++ b/example-pyramid/example/__init__.py @@ -1,5 +1,3 @@ -import sys - import example.local_settings as app_local_settings import example.settings as app_settings from common import filters, utils @@ -12,17 +10,18 @@ def get_settings(module): + not_in_filters = ["__builtins__", "__file__"] return { key: value for key, value in module.__dict__.items() - if key not in module.__builtins__ and key not in ["__builtins__", "__file__"] + if key not in module.__builtins__ and key not in not_in_filters } def main(global_config, **settings): """This function returns a Pyramid WSGI application.""" engine = engine_from_config(settings, "sqlalchemy.") - DBSession.configure(bind=engine) + DBSession.bind = engine Base.metadata.bind = engine session_factory = SignedCookieSessionFactory("thisisasecret") settings["jinja2.globals"] = {"url": utils.url_for} diff --git a/example-pyramid/example/auth.py b/example-pyramid/example/auth.py index 2faf33c..d57b9a2 100644 --- a/example-pyramid/example/auth.py +++ b/example-pyramid/example/auth.py @@ -1,6 +1,7 @@ from example.models import DBSession, User from pyramid.events import BeforeRender, subscriber from social_pyramid.utils import backends +from sqlalchemy import select def login_user(backend, user, user_social_auth): @@ -14,7 +15,7 @@ def login_required(request): def get_user(request): user_id = request.session.get("user_id") if user_id: - user = DBSession.query(User).filter(User.id == user_id).first() + user = DBSession.scalar(select(User).where(User.id == user_id)) else: user = None return user diff --git a/example-pyramid/example/local_settings.py.template b/example-pyramid/example/local_settings.py.template index 8fac843..479b3cd 100644 --- a/example-pyramid/example/local_settings.py.template +++ b/example-pyramid/example/local_settings.py.template @@ -1,94 +1,92 @@ -SOCIAL_AUTH_KEYS = { - 'SOCIAL_AUTH_GOOGLE_OAUTH2_KEY': '', - 'SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET': '', +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' - 'SOCIAL_AUTH_TWITTER_KEY': '', - 'SOCIAL_AUTH_TWITTER_SECRET': '', +SOCIAL_AUTH_TWITTER_KEY = '' +SOCIAL_AUTH_TWITTER_SECRET = '' - 'SOCIAL_AUTH_STRIPE_KEY': '', - 'SOCIAL_AUTH_STRIPE_SECRET': '', - 'SOCIAL_AUTH_STRIPE_SCOPE': [], +SOCIAL_AUTH_STRIPE_KEY = '' +SOCIAL_AUTH_STRIPE_SECRET = '' +SOCIAL_AUTH_STRIPE_SCOPE = [] - 'SOCIAL_AUTH_FACEBOOK_KEY': '', - 'SOCIAL_AUTH_FACEBOOK_SECRET': '', +SOCIAL_AUTH_FACEBOOK_KEY = '' +SOCIAL_AUTH_FACEBOOK_SECRET = '' - 'SOCIAL_AUTH_FACEBOOK_APP_KEY': '', - 'SOCIAL_AUTH_FACEBOOK_APP_SECRET': '', - 'SOCIAL_AUTH_FACEBOOK_APP_NAMESPACE': '', +SOCIAL_AUTH_FACEBOOK_APP_KEY = '' +SOCIAL_AUTH_FACEBOOK_APP_SECRET = '' +SOCIAL_AUTH_FACEBOOK_APP_NAMESPACE = '' - 'SOCIAL_AUTH_YAHOO_OAUTH_KEY': '', - 'SOCIAL_AUTH_YAHOO_OAUTH_SECRET': '', +SOCIAL_AUTH_YAHOO_OAUTH_KEY = '' +SOCIAL_AUTH_YAHOO_OAUTH_SECRET = '' - 'SOCIAL_AUTH_ANGEL_KEY': '', - 'SOCIAL_AUTH_ANGEL_SECRET': '', +SOCIAL_AUTH_ANGEL_KEY = '' +SOCIAL_AUTH_ANGEL_SECRET = '' - 'SOCIAL_AUTH_BEHANCE_KEY': '', - 'SOCIAL_AUTH_BEHANCE_SECRET': '', - 'SOCIAL_AUTH_BEHANCE_SCOPE': [], +SOCIAL_AUTH_BEHANCE_KEY = '' +SOCIAL_AUTH_BEHANCE_SECRET = '' +SOCIAL_AUTH_BEHANCE_SCOPE = [] - 'SOCIAL_AUTH_BITBUCKET_KEY': '', - 'SOCIAL_AUTH_BITBUCKET_SECRET': '', +SOCIAL_AUTH_BITBUCKET_KEY = '' +SOCIAL_AUTH_BITBUCKET_SECRET = '' - 'SOCIAL_AUTH_LINKEDIN_KEY': '', - 'SOCIAL_AUTH_LINKEDIN_SECRET': '', - 'SOCIAL_AUTH_LINKEDIN_SCOPE': [], +SOCIAL_AUTH_LINKEDIN_KEY = '' +SOCIAL_AUTH_LINKEDIN_SECRET = '' +SOCIAL_AUTH_LINKEDIN_SCOPE = [] - 'SOCIAL_AUTH_GITHUB_KEY': '', - 'SOCIAL_AUTH_GITHUB_SECRET': '', +SOCIAL_AUTH_GITHUB_KEY = '' +SOCIAL_AUTH_GITHUB_SECRET = '' - 'SOCIAL_AUTH_FOURSQUARE_KEY': '', - 'SOCIAL_AUTH_FOURSQUARE_SECRET': '', +SOCIAL_AUTH_FOURSQUARE_KEY = '' +SOCIAL_AUTH_FOURSQUARE_SECRET = '' - 'SOCIAL_AUTH_INSTAGRAM_KEY': '', - 'SOCIAL_AUTH_INSTAGRAM_SECRET': '', +SOCIAL_AUTH_INSTAGRAM_KEY = '' +SOCIAL_AUTH_INSTAGRAM_SECRET = '' - 'SOCIAL_AUTH_LIVE_KEY': '', - 'SOCIAL_AUTH_LIVE_SECRET': '', +SOCIAL_AUTH_LIVE_KEY = '' +SOCIAL_AUTH_LIVE_SECRET = '' - 'SOCIAL_AUTH_VKONTAKTE_OAUTH2_KEY': '', - 'SOCIAL_AUTH_VKONTAKTE_OAUTH2_SECRET': '', +SOCIAL_AUTH_VKONTAKTE_OAUTH2_KEY = '' +SOCIAL_AUTH_VKONTAKTE_OAUTH2_SECRET = '' - 'SOCIAL_AUTH_DAILYMOTION_KEY': '', - 'SOCIAL_AUTH_DAILYMOTION_SECRET': '', +SOCIAL_AUTH_DAILYMOTION_KEY = '' +SOCIAL_AUTH_DAILYMOTION_SECRET = '' - 'SOCIAL_AUTH_DISQUS_KEY': '', - 'SOCIAL_AUTH_DISQUS_SECRET': '', +SOCIAL_AUTH_DISQUS_KEY = '' +SOCIAL_AUTH_DISQUS_SECRET = '' - 'SOCIAL_AUTH_DROPBOX_KEY': '', - 'SOCIAL_AUTH_DROPBOX_SECRET': '', +SOCIAL_AUTH_DROPBOX_KEY = '' +SOCIAL_AUTH_DROPBOX_SECRET = '' - 'SOCIAL_AUTH_EVERNOTE_SANDBOX_KEY': '', - 'SOCIAL_AUTH_EVERNOTE_SANDBOX_SECRET': '', +SOCIAL_AUTH_EVERNOTE_SANDBOX_KEY = '' +SOCIAL_AUTH_EVERNOTE_SANDBOX_SECRET = '' - 'SOCIAL_AUTH_FITBIT_KEY': '', - 'SOCIAL_AUTH_FITBIT_SECRET': '', +SOCIAL_AUTH_FITBIT_KEY = '' +SOCIAL_AUTH_FITBIT_SECRET = '' - 'SOCIAL_AUTH_FLICKR_KEY': '', - 'SOCIAL_AUTH_FLICKR_SECRET': '', +SOCIAL_AUTH_FLICKR_KEY = '' +SOCIAL_AUTH_FLICKR_SECRET = '' - 'SOCIAL_AUTH_SOUNDCLOUD_KEY': '', - 'SOCIAL_AUTH_SOUNDCLOUD_SECRET': '', +SOCIAL_AUTH_SOUNDCLOUD_KEY = '' +SOCIAL_AUTH_SOUNDCLOUD_SECRET = '' - 'SOCIAL_AUTH_STOCKTWITS_KEY': '', - 'SOCIAL_AUTH_STOCKTWITS_SECRET': '', +SOCIAL_AUTH_STOCKTWITS_KEY = '' +SOCIAL_AUTH_STOCKTWITS_SECRET = '' - 'SOCIAL_AUTH_TRIPIT_KEY': '', - 'SOCIAL_AUTH_TRIPIT_SECRET': '', +SOCIAL_AUTH_TRIPIT_KEY = '' +SOCIAL_AUTH_TRIPIT_SECRET = '' - 'SOCIAL_AUTH_TWILIO_KEY': '', - 'SOCIAL_AUTH_TWILIO_SECRET': '', +SOCIAL_AUTH_TWILIO_KEY = '' +SOCIAL_AUTH_TWILIO_SECRET = '' - 'SOCIAL_AUTH_XING_KEY': '', - 'SOCIAL_AUTH_XING_SECRET': '', +SOCIAL_AUTH_XING_KEY = '' +SOCIAL_AUTH_XING_SECRET = '' - 'SOCIAL_AUTH_YANDEX_OAUTH2_KEY': '', - 'SOCIAL_AUTH_YANDEX_OAUTH2_SECRET': '', - 'SOCIAL_AUTH_YANDEX_OAUTH2_API_URL': '', +SOCIAL_AUTH_YANDEX_OAUTH2_KEY = '' +SOCIAL_AUTH_YANDEX_OAUTH2_SECRET = '' +SOCIAL_AUTH_YANDEX_OAUTH2_API_URL = '' - 'SOCIAL_AUTH_REDDIT_KEY': '', - 'SOCIAL_AUTH_REDDIT_SECRET': '', - 'SOCIAL_AUTH_REDDIT_AUTH_EXTRA_ARGUMENTS': {}, -} +SOCIAL_AUTH_REDDIT_KEY = '' +SOCIAL_AUTH_REDDIT_SECRET = '' +SOCIAL_AUTH_REDDIT_AUTH_EXTRA_ARGUMENTS = {} def includeme(config): diff --git a/example-pyramid/example/models.py b/example-pyramid/example/models.py index 1856b3f..d781af0 100644 --- a/example-pyramid/example/models.py +++ b/example-pyramid/example/models.py @@ -1,21 +1,26 @@ -from sqlalchemy import Boolean, Column, Integer, String -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import scoped_session, sessionmaker +from typing import Optional + +from sqlalchemy import String +from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column from zope.sqlalchemy import register -DBSession = scoped_session(sessionmaker(expire_on_commit=False)) +DBSession = Session(expire_on_commit=False) register(DBSession) -Base = declarative_base() + + +class Base(DeclarativeBase): + pass class User(Base): __tablename__ = "users" - id = Column(Integer, primary_key=True) - username = Column(String(200)) - email = Column(String(200)) - password = Column(String(200), default="") - name = Column(String(100)) - active = Column(Boolean, default=True) + + id: Mapped[int] = mapped_column(primary_key=True) + username: Mapped[str] = mapped_column(String(200)) + email: Mapped[str] = mapped_column(String(200)) + password: Mapped[str] = mapped_column(String(200), default="") + name: Mapped[Optional[str]] = mapped_column(String(100)) + active: Mapped[bool] = mapped_column(default=True) def is_active(self): return self.active diff --git a/example-pyramid/example/scripts/initializedb.py b/example-pyramid/example/scripts/initializedb.py index 01ceddc..152c028 100644 --- a/example-pyramid/example/scripts/initializedb.py +++ b/example-pyramid/example/scripts/initializedb.py @@ -28,7 +28,7 @@ def main(argv=sys.argv): settings = get_appsettings(config_uri, options=options) init_social(get_settings(app_settings), Base, DBSession) engine = engine_from_config(settings, "sqlalchemy.") - DBSession.configure(bind=engine) + DBSession.bind = engine Base.metadata.create_all(engine) diff --git a/example-pyramid/example/views.py b/example-pyramid/example/views.py index 48b1bfc..88d8ce4 100644 --- a/example-pyramid/example/views.py +++ b/example-pyramid/example/views.py @@ -21,11 +21,13 @@ def done(request): request.registry.settings["SOCIAL_AUTH_AUTHENTICATION_BACKENDS"], load_strategy(request), user=get_user(request), - plus_id=request.registry.settings["SOCIAL_AUTH_GOOGLE_PLUS_KEY"], ) -@view_config(route_name="email_required", renderer="common:templates/home.jinja2") +@view_config( # fix: skip + route_name="email_required", # fix: skip + renderer="common:templates/home.jinja2", # fix: skip +) def email_required(request): strategy = load_strategy(request) partial_token = request.GET.get("partial_token") diff --git a/example-tornado/example/app.py b/example-tornado/example/app.py index d4f593f..38cc344 100644 --- a/example-tornado/example/app.py +++ b/example-tornado/example/app.py @@ -1,34 +1,38 @@ import os -import settings import tornado.options import tornado.web from common import filters from common.utils import common_context, url_for +from example import settings from jinja2 import Environment, FileSystemLoader from social_tornado.routes import SOCIAL_AUTH_ROUTES from social_tornado.utils import load_strategy from sqlalchemy import create_engine -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import DeclarativeBase, Session from tornado_jinja2 import Jinja2Loader BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -DATABASE_NAME = "sqlite:///{dbname}".format(dbname=os.path.join(BASE_DIR, "db.sqlite3")) +DATABASE_NAME = "sqlite:///{dbname}".format( # fix: skip + dbname=os.path.join(BASE_DIR, "db.sqlite3") +) engine = create_engine(DATABASE_NAME, echo=False) -session = scoped_session(sessionmaker(bind=engine)) -Base = declarative_base() +session = Session(engine) + + +class Base(DeclarativeBase): + pass class BaseHandler(tornado.web.RequestHandler): def render_home(self, **extra): - from models import User + from example.models import User user_id = self.get_secure_cookie("user_id") if user_id: - user = session.query(User).get(int(user_id)) + user = session.get(User, int(user_id)) else: user = None @@ -39,6 +43,7 @@ def render_home(self, **extra): plus_id=getattr(settings, "SOCIAL_AUTH_GOOGLE_PLUS_KEY", None), **extra ) + self.render("home.html", **context) diff --git a/example-tornado/example/local_settings.py.template b/example-tornado/example/local_settings.py.template new file mode 100644 index 0000000..a919630 --- /dev/null +++ b/example-tornado/example/local_settings.py.template @@ -0,0 +1,89 @@ +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' + +SOCIAL_AUTH_TWITTER_KEY = '' +SOCIAL_AUTH_TWITTER_SECRET = '' + +SOCIAL_AUTH_STRIPE_KEY = '' +SOCIAL_AUTH_STRIPE_SECRET = '' +SOCIAL_AUTH_STRIPE_SCOPE = [] + +SOCIAL_AUTH_FACEBOOK_KEY = '' +SOCIAL_AUTH_FACEBOOK_SECRET = '' + +SOCIAL_AUTH_FACEBOOK_APP_KEY = '' +SOCIAL_AUTH_FACEBOOK_APP_SECRET = '' +SOCIAL_AUTH_FACEBOOK_APP_NAMESPACE = '' + +SOCIAL_AUTH_YAHOO_OAUTH_KEY = '' +SOCIAL_AUTH_YAHOO_OAUTH_SECRET = '' + +SOCIAL_AUTH_ANGEL_KEY = '' +SOCIAL_AUTH_ANGEL_SECRET = '' + +SOCIAL_AUTH_BEHANCE_KEY = '' +SOCIAL_AUTH_BEHANCE_SECRET = '' +SOCIAL_AUTH_BEHANCE_SCOPE = [] + +SOCIAL_AUTH_BITBUCKET_KEY = '' +SOCIAL_AUTH_BITBUCKET_SECRET = '' + +SOCIAL_AUTH_LINKEDIN_KEY = '' +SOCIAL_AUTH_LINKEDIN_SECRET = '' +SOCIAL_AUTH_LINKEDIN_SCOPE = [] + +SOCIAL_AUTH_GITHUB_KEY = '' +SOCIAL_AUTH_GITHUB_SECRET = '' + +SOCIAL_AUTH_FOURSQUARE_KEY = '' +SOCIAL_AUTH_FOURSQUARE_SECRET = '' + +SOCIAL_AUTH_INSTAGRAM_KEY = '' +SOCIAL_AUTH_INSTAGRAM_SECRET = '' + +SOCIAL_AUTH_LIVE_KEY = '' +SOCIAL_AUTH_LIVE_SECRET = '' + +SOCIAL_AUTH_VKONTAKTE_OAUTH2_KEY = '' +SOCIAL_AUTH_VKONTAKTE_OAUTH2_SECRET = '' + +SOCIAL_AUTH_DAILYMOTION_KEY = '' +SOCIAL_AUTH_DAILYMOTION_SECRET = '' + +SOCIAL_AUTH_DISQUS_KEY = '' +SOCIAL_AUTH_DISQUS_SECRET = '' + +SOCIAL_AUTH_DROPBOX_KEY = '' +SOCIAL_AUTH_DROPBOX_SECRET = '' + +SOCIAL_AUTH_EVERNOTE_SANDBOX_KEY = '' +SOCIAL_AUTH_EVERNOTE_SANDBOX_SECRET = '' + +SOCIAL_AUTH_FITBIT_KEY = '' +SOCIAL_AUTH_FITBIT_SECRET = '' + +SOCIAL_AUTH_FLICKR_KEY = '' +SOCIAL_AUTH_FLICKR_SECRET = '' + +SOCIAL_AUTH_SOUNDCLOUD_KEY = '' +SOCIAL_AUTH_SOUNDCLOUD_SECRET = '' + +SOCIAL_AUTH_STOCKTWITS_KEY = '' +SOCIAL_AUTH_STOCKTWITS_SECRET = '' + +SOCIAL_AUTH_TRIPIT_KEY = '' +SOCIAL_AUTH_TRIPIT_SECRET = '' + +SOCIAL_AUTH_TWILIO_KEY = '' +SOCIAL_AUTH_TWILIO_SECRET = '' + +SOCIAL_AUTH_XING_KEY = '' +SOCIAL_AUTH_XING_SECRET = '' + +SOCIAL_AUTH_YANDEX_OAUTH2_KEY = '' +SOCIAL_AUTH_YANDEX_OAUTH2_SECRET = '' +SOCIAL_AUTH_YANDEX_OAUTH2_API_URL = '' + +SOCIAL_AUTH_REDDIT_KEY = '' +SOCIAL_AUTH_REDDIT_SECRET = '' +SOCIAL_AUTH_REDDIT_AUTH_EXTRA_ARGUMENTS = {} diff --git a/example-tornado/example/models.py b/example-tornado/example/models.py index e09f4a5..e074541 100644 --- a/example-tornado/example/models.py +++ b/example-tornado/example/models.py @@ -1,15 +1,17 @@ -from app import Base -from sqlalchemy import Column, Integer, String +from example.app import Base +from sqlalchemy import String +from sqlalchemy.orm import Mapped, mapped_column class User(Base): __tablename__ = "users" - id = Column(Integer, primary_key=True) - username = Column(String(30), nullable=False) - first_name = Column(String(30), nullable=True) - last_name = Column(String(30), nullable=True) - email = Column(String(75), nullable=False) - password = Column(String(128), nullable=True) + + id: Mapped[int] = mapped_column(primary_key=True) + username: Mapped[str] = mapped_column(String(30), nullable=False) + first_name: Mapped[str] = mapped_column(String(30), nullable=True) + last_name: Mapped[str] = mapped_column(String(30), nullable=True) + email: Mapped[str] = mapped_column(String(75), nullable=False) + password: Mapped[str] = mapped_column(String(128), nullable=True) def is_authenticated(self): return True diff --git a/example-tornado/example/settings.py b/example-tornado/example/settings.py index d6ae8ae..799a3ce 100644 --- a/example-tornado/example/settings.py +++ b/example-tornado/example/settings.py @@ -108,4 +108,4 @@ "social_core.pipeline.debug.debug", ) -from local_settings import * +from example.local_settings import * # noqa: F401,E402,F403 diff --git a/example-tornado/manage.py b/example-tornado/manage.py index ec5d45d..f0f9f94 100755 --- a/example-tornado/manage.py +++ b/example-tornado/manage.py @@ -9,7 +9,7 @@ if __name__ == "__main__": if len(sys.argv) > 1 and sys.argv[1] == "syncdb": - from example.models import User + from example.models import User # noqa: F401 init_social(Base, session, tornado_settings) Base.metadata.create_all(engine) diff --git a/example-webpy/app.py b/example-webpy/app.py index 80a1d5d..88f82f4 100644 --- a/example-webpy/app.py +++ b/example-webpy/app.py @@ -1,14 +1,14 @@ import os -import sys -import local_settings import web from common import filters from common.utils import common_context, url_for +from example import local_settings, settings from social_core.utils import setting_name +from social_webpy import app as social_app from social_webpy.utils import load_strategy from sqlalchemy import create_engine -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import Session from web.contrib.template import render_jinja BASE_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -16,107 +16,9 @@ web.config.debug = False web.config[setting_name("USER_MODEL")] = "models.User" web.config[setting_name("AUTHENTICATION_BACKENDS")] = ( - "social_core.backends.amazon.AmazonOAuth2", - "social_core.backends.angel.AngelOAuth2", - "social_core.backends.aol.AOLOpenId", - "social_core.backends.appsfuel.AppsfuelOAuth2", - "social_core.backends.beats.BeatsOAuth2", - "social_core.backends.behance.BehanceOAuth2", - "social_core.backends.belgiumeid.BelgiumEIDOpenId", - "social_core.backends.bitbucket.BitbucketOAuth", - "social_core.backends.box.BoxOAuth2", - "social_core.backends.clef.ClefOAuth2", - "social_core.backends.coinbase.CoinbaseOAuth2", - "social_core.backends.coursera.CourseraOAuth2", - "social_core.backends.dailymotion.DailymotionOAuth2", - "social_core.backends.deezer.DeezerOAuth2", - "social_core.backends.disqus.DisqusOAuth2", - "social_core.backends.douban.DoubanOAuth2", - "social_core.backends.dropbox.DropboxOAuth", - "social_core.backends.dropbox.DropboxOAuth2", - "social_core.backends.eveonline.EVEOnlineOAuth2", - "social_core.backends.evernote.EvernoteSandboxOAuth", - "social_core.backends.facebook.FacebookAppOAuth2", - "social_core.backends.facebook.FacebookOAuth2", - "social_core.backends.fedora.FedoraOpenId", - "social_core.backends.fitbit.FitbitOAuth2", - "social_core.backends.flickr.FlickrOAuth", - "social_core.backends.foursquare.FoursquareOAuth2", - "social_core.backends.github.GithubOAuth2", - "social_core.backends.google.GoogleOAuth", - "social_core.backends.google.GoogleOAuth2", - "social_core.backends.google.GoogleOpenId", - "social_core.backends.google.GooglePlusAuth", - "social_core.backends.google_openidconnect.GoogleOpenIdConnect", - "social_core.backends.instagram.InstagramOAuth2", - "social_core.backends.jawbone.JawboneOAuth2", - "social_core.backends.kakao.KakaoOAuth2", - "social_core.backends.linkedin.LinkedinOAuth", - "social_core.backends.linkedin.LinkedinOAuth2", - "social_core.backends.live.LiveOAuth2", - "social_core.backends.livejournal.LiveJournalOpenId", - "social_core.backends.mailru.MailruOAuth2", - "social_core.backends.mendeley.MendeleyOAuth", - "social_core.backends.mendeley.MendeleyOAuth2", - "social_core.backends.mineid.MineIDOAuth2", - "social_core.backends.mixcloud.MixcloudOAuth2", - "social_core.backends.nationbuilder.NationBuilderOAuth2", - "social_core.backends.odnoklassniki.OdnoklassnikiOAuth2", - "social_core.backends.open_id.OpenIdAuth", - "social_core.backends.openstreetmap.OpenStreetMapOAuth", - "social_core.backends.persona.PersonaAuth", - "social_core.backends.podio.PodioOAuth2", - "social_core.backends.rdio.RdioOAuth1", - "social_core.backends.rdio.RdioOAuth2", - "social_core.backends.readability.ReadabilityOAuth", - "social_core.backends.reddit.RedditOAuth2", - "social_core.backends.runkeeper.RunKeeperOAuth2", - "social_core.backends.sketchfab.SketchfabOAuth2", - "social_core.backends.skyrock.SkyrockOAuth", - "social_core.backends.soundcloud.SoundcloudOAuth2", - "social_core.backends.spotify.SpotifyOAuth2", - "social_core.backends.stackoverflow.StackoverflowOAuth2", - "social_core.backends.steam.SteamOpenId", - "social_core.backends.stocktwits.StocktwitsOAuth2", - "social_core.backends.stripe.StripeOAuth2", - "social_core.backends.suse.OpenSUSEOpenId", - "social_core.backends.thisismyjam.ThisIsMyJamOAuth1", - "social_core.backends.trello.TrelloOAuth", - "social_core.backends.tripit.TripItOAuth", - "social_core.backends.tumblr.TumblrOAuth", - "social_core.backends.twilio.TwilioAuth", - "social_core.backends.twitter.TwitterOAuth", - "social_core.backends.vk.VKOAuth2", - "social_core.backends.weibo.WeiboOAuth2", - "social_core.backends.wunderlist.WunderlistOAuth2", - "social_core.backends.xing.XingOAuth", - "social_core.backends.yahoo.YahooOAuth", - "social_core.backends.yahoo.YahooOpenId", - "social_core.backends.yammer.YammerOAuth2", - "social_core.backends.yandex.YandexOAuth2", - "social_core.backends.vimeo.VimeoOAuth1", - "social_core.backends.lastfm.LastFmAuth", - "social_core.backends.moves.MovesOAuth2", - "social_core.backends.vend.VendOAuth2", - "social_core.backends.email.EmailAuth", - "social_core.backends.username.UsernameAuth", - "social_core.backends.upwork.UpworkOAuth", -) -web.config[setting_name("PIPELINE")] = ( - "social_core.pipeline.social_auth.social_details", - "social_core.pipeline.social_auth.social_uid", - "social_core.pipeline.social_auth.auth_allowed", - "social_core.pipeline.social_auth.social_user", - "social_core.pipeline.user.get_username", - "common.pipeline.require_email", - "social_core.pipeline.mail.mail_validation", - "social_core.pipeline.user.create_user", - "social_core.pipeline.social_auth.associate_user", - "social_core.pipeline.debug.debug", - "social_core.pipeline.social_auth.load_extra_data", - "social_core.pipeline.user.user_details", - "social_core.pipeline.debug.debug", + settings.SOCIAL_AUTH_AUTHENTICATION_BACKENDS ) +web.config[setting_name("PIPELINE")] = settings.SOCIAL_AUTH_PIPELINE for name, value in local_settings.__dict__.items(): if name.startswith("SOCIAL_AUTH"): @@ -124,9 +26,6 @@ web.config[setting_name("LOGIN_REDIRECT_URL")] = "/done/" -from social_webpy import app as social_app -from social_webpy.utils import backends, psa - urls = ( "^/$", "main", @@ -160,7 +59,6 @@ def render_home(self, **extra): web.config[setting_name("AUTHENTICATION_BACKENDS")], load_strategy(), user=self.get_current_user(), - plus_id=web.config.get(setting_name("SOCIAL_AUTH_GOOGLE_PLUS_KEY")), **extra ) return render.home(**context) @@ -192,27 +90,24 @@ def GET(self): def load_sqla(handler): - web.ctx.orm = scoped_session(sessionmaker(bind=engine)) + web.ctx.orm = Session(engine) try: return handler() except web.HTTPError: web.ctx.orm.commit() raise - except: + except Exception: web.ctx.orm.rollback() raise finally: web.ctx.orm.commit() -Session = sessionmaker(bind=engine) -Session.configure(bind=engine) - app = web.application(urls, locals()) app.add_processor(load_sqla) session = web.session.Session( app, web.session.DiskStore(os.path.join(BASE_DIR, "sessions")) ) -web.db_session = Session() +web.db_session = Session(engine) web.web_session = session diff --git a/example-webpy/local_settings.py.template b/example-webpy/local_settings.py.template new file mode 100644 index 0000000..a919630 --- /dev/null +++ b/example-webpy/local_settings.py.template @@ -0,0 +1,89 @@ +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' + +SOCIAL_AUTH_TWITTER_KEY = '' +SOCIAL_AUTH_TWITTER_SECRET = '' + +SOCIAL_AUTH_STRIPE_KEY = '' +SOCIAL_AUTH_STRIPE_SECRET = '' +SOCIAL_AUTH_STRIPE_SCOPE = [] + +SOCIAL_AUTH_FACEBOOK_KEY = '' +SOCIAL_AUTH_FACEBOOK_SECRET = '' + +SOCIAL_AUTH_FACEBOOK_APP_KEY = '' +SOCIAL_AUTH_FACEBOOK_APP_SECRET = '' +SOCIAL_AUTH_FACEBOOK_APP_NAMESPACE = '' + +SOCIAL_AUTH_YAHOO_OAUTH_KEY = '' +SOCIAL_AUTH_YAHOO_OAUTH_SECRET = '' + +SOCIAL_AUTH_ANGEL_KEY = '' +SOCIAL_AUTH_ANGEL_SECRET = '' + +SOCIAL_AUTH_BEHANCE_KEY = '' +SOCIAL_AUTH_BEHANCE_SECRET = '' +SOCIAL_AUTH_BEHANCE_SCOPE = [] + +SOCIAL_AUTH_BITBUCKET_KEY = '' +SOCIAL_AUTH_BITBUCKET_SECRET = '' + +SOCIAL_AUTH_LINKEDIN_KEY = '' +SOCIAL_AUTH_LINKEDIN_SECRET = '' +SOCIAL_AUTH_LINKEDIN_SCOPE = [] + +SOCIAL_AUTH_GITHUB_KEY = '' +SOCIAL_AUTH_GITHUB_SECRET = '' + +SOCIAL_AUTH_FOURSQUARE_KEY = '' +SOCIAL_AUTH_FOURSQUARE_SECRET = '' + +SOCIAL_AUTH_INSTAGRAM_KEY = '' +SOCIAL_AUTH_INSTAGRAM_SECRET = '' + +SOCIAL_AUTH_LIVE_KEY = '' +SOCIAL_AUTH_LIVE_SECRET = '' + +SOCIAL_AUTH_VKONTAKTE_OAUTH2_KEY = '' +SOCIAL_AUTH_VKONTAKTE_OAUTH2_SECRET = '' + +SOCIAL_AUTH_DAILYMOTION_KEY = '' +SOCIAL_AUTH_DAILYMOTION_SECRET = '' + +SOCIAL_AUTH_DISQUS_KEY = '' +SOCIAL_AUTH_DISQUS_SECRET = '' + +SOCIAL_AUTH_DROPBOX_KEY = '' +SOCIAL_AUTH_DROPBOX_SECRET = '' + +SOCIAL_AUTH_EVERNOTE_SANDBOX_KEY = '' +SOCIAL_AUTH_EVERNOTE_SANDBOX_SECRET = '' + +SOCIAL_AUTH_FITBIT_KEY = '' +SOCIAL_AUTH_FITBIT_SECRET = '' + +SOCIAL_AUTH_FLICKR_KEY = '' +SOCIAL_AUTH_FLICKR_SECRET = '' + +SOCIAL_AUTH_SOUNDCLOUD_KEY = '' +SOCIAL_AUTH_SOUNDCLOUD_SECRET = '' + +SOCIAL_AUTH_STOCKTWITS_KEY = '' +SOCIAL_AUTH_STOCKTWITS_SECRET = '' + +SOCIAL_AUTH_TRIPIT_KEY = '' +SOCIAL_AUTH_TRIPIT_SECRET = '' + +SOCIAL_AUTH_TWILIO_KEY = '' +SOCIAL_AUTH_TWILIO_SECRET = '' + +SOCIAL_AUTH_XING_KEY = '' +SOCIAL_AUTH_XING_SECRET = '' + +SOCIAL_AUTH_YANDEX_OAUTH2_KEY = '' +SOCIAL_AUTH_YANDEX_OAUTH2_SECRET = '' +SOCIAL_AUTH_YANDEX_OAUTH2_API_URL = '' + +SOCIAL_AUTH_REDDIT_KEY = '' +SOCIAL_AUTH_REDDIT_SECRET = '' +SOCIAL_AUTH_REDDIT_AUTH_EXTRA_ARGUMENTS = {} diff --git a/example-webpy/models.py b/example-webpy/models.py index 4c0c0be..f56e995 100644 --- a/example-webpy/models.py +++ b/example-webpy/models.py @@ -1,17 +1,22 @@ -from sqlalchemy import Boolean, Column, Integer, String -from sqlalchemy.ext.declarative import declarative_base +from typing import Optional -Base = declarative_base() +from sqlalchemy import String +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + + +class Base(DeclarativeBase): + pass class User(Base): __tablename__ = "users" - id = Column(Integer, primary_key=True) - username = Column(String(200)) - password = Column(String(200), default="") - name = Column(String(100)) - email = Column(String(200)) - active = Column(Boolean, default=True) + + id: Mapped[int] = mapped_column(primary_key=True) + username: Mapped[str] = mapped_column(String(200)) + password: Mapped[str] = mapped_column(String(200), default="") + name: Mapped[Optional[str]] = mapped_column(String(100)) + email: Mapped[str] = mapped_column(String(200)) + active: Mapped[bool] = mapped_column(default=True) def is_active(self): return self.active diff --git a/example-webpy/settings.py b/example-webpy/settings.py new file mode 100644 index 0000000..f8e7da6 --- /dev/null +++ b/example-webpy/settings.py @@ -0,0 +1,103 @@ +SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( + "social_core.backends.amazon.AmazonOAuth2", + "social_core.backends.angel.AngelOAuth2", + "social_core.backends.aol.AOLOpenId", + "social_core.backends.appsfuel.AppsfuelOAuth2", + "social_core.backends.beats.BeatsOAuth2", + "social_core.backends.behance.BehanceOAuth2", + "social_core.backends.belgiumeid.BelgiumEIDOpenId", + "social_core.backends.bitbucket.BitbucketOAuth", + "social_core.backends.box.BoxOAuth2", + "social_core.backends.clef.ClefOAuth2", + "social_core.backends.coinbase.CoinbaseOAuth2", + "social_core.backends.coursera.CourseraOAuth2", + "social_core.backends.dailymotion.DailymotionOAuth2", + "social_core.backends.deezer.DeezerOAuth2", + "social_core.backends.disqus.DisqusOAuth2", + "social_core.backends.douban.DoubanOAuth2", + "social_core.backends.dropbox.DropboxOAuth", + "social_core.backends.dropbox.DropboxOAuth2", + "social_core.backends.eveonline.EVEOnlineOAuth2", + "social_core.backends.evernote.EvernoteSandboxOAuth", + "social_core.backends.facebook.FacebookAppOAuth2", + "social_core.backends.facebook.FacebookOAuth2", + "social_core.backends.fedora.FedoraOpenId", + "social_core.backends.fitbit.FitbitOAuth2", + "social_core.backends.flickr.FlickrOAuth", + "social_core.backends.foursquare.FoursquareOAuth2", + "social_core.backends.github.GithubOAuth2", + "social_core.backends.google.GoogleOAuth", + "social_core.backends.google.GoogleOAuth2", + "social_core.backends.google.GoogleOpenId", + "social_core.backends.google.GooglePlusAuth", + "social_core.backends.google_openidconnect.GoogleOpenIdConnect", + "social_core.backends.instagram.InstagramOAuth2", + "social_core.backends.jawbone.JawboneOAuth2", + "social_core.backends.kakao.KakaoOAuth2", + "social_core.backends.linkedin.LinkedinOAuth", + "social_core.backends.linkedin.LinkedinOAuth2", + "social_core.backends.live.LiveOAuth2", + "social_core.backends.livejournal.LiveJournalOpenId", + "social_core.backends.mailru.MailruOAuth2", + "social_core.backends.mendeley.MendeleyOAuth", + "social_core.backends.mendeley.MendeleyOAuth2", + "social_core.backends.mineid.MineIDOAuth2", + "social_core.backends.mixcloud.MixcloudOAuth2", + "social_core.backends.nationbuilder.NationBuilderOAuth2", + "social_core.backends.odnoklassniki.OdnoklassnikiOAuth2", + "social_core.backends.open_id.OpenIdAuth", + "social_core.backends.openstreetmap.OpenStreetMapOAuth", + "social_core.backends.persona.PersonaAuth", + "social_core.backends.podio.PodioOAuth2", + "social_core.backends.rdio.RdioOAuth1", + "social_core.backends.rdio.RdioOAuth2", + "social_core.backends.readability.ReadabilityOAuth", + "social_core.backends.reddit.RedditOAuth2", + "social_core.backends.runkeeper.RunKeeperOAuth2", + "social_core.backends.sketchfab.SketchfabOAuth2", + "social_core.backends.skyrock.SkyrockOAuth", + "social_core.backends.soundcloud.SoundcloudOAuth2", + "social_core.backends.spotify.SpotifyOAuth2", + "social_core.backends.stackoverflow.StackoverflowOAuth2", + "social_core.backends.steam.SteamOpenId", + "social_core.backends.stocktwits.StocktwitsOAuth2", + "social_core.backends.stripe.StripeOAuth2", + "social_core.backends.suse.OpenSUSEOpenId", + "social_core.backends.thisismyjam.ThisIsMyJamOAuth1", + "social_core.backends.trello.TrelloOAuth", + "social_core.backends.tripit.TripItOAuth", + "social_core.backends.tumblr.TumblrOAuth", + "social_core.backends.twilio.TwilioAuth", + "social_core.backends.twitter.TwitterOAuth", + "social_core.backends.vk.VKOAuth2", + "social_core.backends.weibo.WeiboOAuth2", + "social_core.backends.wunderlist.WunderlistOAuth2", + "social_core.backends.xing.XingOAuth", + "social_core.backends.yahoo.YahooOAuth", + "social_core.backends.yahoo.YahooOpenId", + "social_core.backends.yammer.YammerOAuth2", + "social_core.backends.yandex.YandexOAuth2", + "social_core.backends.vimeo.VimeoOAuth1", + "social_core.backends.lastfm.LastFmAuth", + "social_core.backends.moves.MovesOAuth2", + "social_core.backends.vend.VendOAuth2", + "social_core.backends.email.EmailAuth", + "social_core.backends.username.UsernameAuth", + "social_core.backends.upwork.UpworkOAuth", +) + +SOCIAL_AUTH_PIPELINE = ( + "social_core.pipeline.social_auth.social_details", + "social_core.pipeline.social_auth.social_uid", + "social_core.pipeline.social_auth.auth_allowed", + "social_core.pipeline.social_auth.social_user", + "social_core.pipeline.user.get_username", + "common.pipeline.require_email", + "social_core.pipeline.mail.mail_validation", + "social_core.pipeline.user.create_user", + "social_core.pipeline.social_auth.associate_user", + "social_core.pipeline.debug.debug", + "social_core.pipeline.social_auth.load_extra_data", + "social_core.pipeline.user.user_details", + "social_core.pipeline.debug.debug", +)