mirror of
https://github.com/tjsga/studyguides.git
synced 2025-04-05 03:40:16 -04:00
ion oauth
This commit is contained in:
parent
b1aea97fc3
commit
3c225f0014
|
@ -0,0 +1 @@
|
|||
default_app_config = "studyguides.apps.auth.apps.AuthConfig"
|
|
@ -1,3 +0,0 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
|
@ -1,3 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
|
@ -1,40 +1,36 @@
|
|||
from typing import Any, Dict, List
|
||||
|
||||
from social_core.backends.oauth import BaseOAuth2
|
||||
from social_core.pipeline.user import get_username as social_get_username
|
||||
|
||||
|
||||
def get_username(strategy, details, user = None, *args, **kwargs):
|
||||
result = social_get_username(strategy, details, user = user, *args, **kwargs)
|
||||
def get_username(strategy, details, *args, user=None, **kwargs):
|
||||
result = social_get_username(strategy, details, user=user, *args, **kwargs)
|
||||
return result
|
||||
|
||||
|
||||
class IonOauth2(BaseOAuth2):
|
||||
name = 'ion'
|
||||
AUTHORIZATION_URL = 'https://ion.tjhsst.edu/oauth/authorize'
|
||||
ACCESS_TOKEN_URL = 'https://ion.tjhsst.edu/oauth/token'
|
||||
ACCESS_TOKEN_METHOD = 'POST'
|
||||
EXTRA_DATA = [
|
||||
('refresh_token', 'refresh_token', True),
|
||||
('expires_in', 'expires')
|
||||
]
|
||||
name = "ion"
|
||||
AUTHORIZATION_URL = "https://ion.tjhsst.edu/oauth/authorize"
|
||||
ACCESS_TOKEN_URL = "https://ion.tjhsst.edu/oauth/token"
|
||||
ACCESS_TOKEN_METHOD = "POST"
|
||||
EXTRA_DATA = [("refresh_token", "refresh_token", True), ("expires_in", "expires")]
|
||||
|
||||
def get_scope(self):
|
||||
def get_scope(self) -> List[str]:
|
||||
return ["read"]
|
||||
|
||||
def get_user_details(self, response):
|
||||
def get_user_details(self, response: Dict[str, Any]) -> Dict[str, Any]:
|
||||
profile = self.get_json(
|
||||
'https://ion.tjhsst.edu/api/profile',
|
||||
params = {'access_token': response['access_token']},
|
||||
"https://ion.tjhsst.edu/api/profile", params={"access_token": response["access_token"]},
|
||||
)
|
||||
# fields used to populate/update User model
|
||||
return {
|
||||
'id': profile['id'],
|
||||
'username': profile['ion_username'],
|
||||
'first_name': profile['first_name'],
|
||||
'last_name': profile['last_name'],
|
||||
'full_name': profile['full_name'],
|
||||
'email': profile['tj_email'],
|
||||
data = {
|
||||
key: profile[key]
|
||||
for key in ("first_name", "last_name", "id", "is_student", "is_teacher")
|
||||
}
|
||||
data["username"] = profile["ion_username"]
|
||||
data["email"] = profile["tj_email"]
|
||||
return data
|
||||
|
||||
def get_user_id(self, details, response):
|
||||
def get_user_id(self, details: Dict[str, Any], response: Any) -> int:
|
||||
return details["id"]
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from . import views
|
|||
app_name = "auth"
|
||||
|
||||
urlpatterns = [
|
||||
path("login", views.login, name = "login"),
|
||||
path("logout", views.logout, name = "logout"),
|
||||
path("", views.index, name="index"),
|
||||
path("login/", views.login, name="login"),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from django.shortcuts import render
|
||||
from django.contrib.auth.views import LogoutView
|
||||
from django.shortcuts import redirect, render
|
||||
|
||||
# Create your views here.
|
||||
def index(request):
|
||||
if request.user.is_authenticated:
|
||||
return redirect("home:index")
|
||||
else:
|
||||
return redirect("auth:login")
|
||||
|
||||
def login(request):
|
||||
return render(request, "auth/login.html")
|
||||
|
||||
logout = LogoutView.as_view()
|
||||
|
||||
return render(request, "login.html")
|
||||
|
|
|
@ -5,7 +5,7 @@ from . import views
|
|||
app_name = "courses"
|
||||
|
||||
urlpatterns = [
|
||||
path("<str:subject_url>/", views.subject_view),
|
||||
path("subject/<str:subject_url>/", views.subject_view),
|
||||
path("tag/<str:tag>/", views.tag_view, name="tag"),
|
||||
path("<str:subject_url>/<str:course_url>/", views.course_view),
|
||||
path("course/<str:subject_url>/<str:course_url>/", views.course_view),
|
||||
]
|
||||
|
|
|
@ -2,16 +2,17 @@ import random
|
|||
|
||||
from django import http
|
||||
from django.shortcuts import render, redirect, reverse, get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from .models import Subject, Course, Guide, Tag
|
||||
|
||||
|
||||
@login_required
|
||||
def subject_view(request, subject_url):
|
||||
subject = get_object_or_404(Subject, url=subject_url)
|
||||
return render(request, "subject.html", {"subject": subject,
|
||||
"courses": subject.courses.all()})
|
||||
|
||||
|
||||
@login_required
|
||||
def course_view(request, subject_url, course_url):
|
||||
subject = get_object_or_404(Subject, url=subject_url)
|
||||
course = get_object_or_404(Course, url=course_url)
|
||||
|
@ -19,6 +20,7 @@ def course_view(request, subject_url, course_url):
|
|||
"course": course,
|
||||
"guides": [[g, g.tags.all()] for g in Guide.objects.filter(course=course)]})
|
||||
|
||||
@login_required
|
||||
def tag_view(request, tag):
|
||||
tag = get_object_or_404(Tag, name=tag)
|
||||
return render(request, "tag.html", {"tag": tag, "guides": [[g, g.tags.all()] for g in tag.guide.all()]})
|
|
@ -4,6 +4,6 @@ from . import views
|
|||
app_name = "home"
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.index_view, name = "index"),
|
||||
path("all/", views.index_view, name="index"),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from django.shortcuts import render, redirect
|
||||
from django.http import HttpResponse
|
||||
from django.apps import apps
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
Subject = apps.get_model("courses", "Subject")
|
||||
Course = apps.get_model("courses", "Course")
|
||||
|
||||
|
||||
@login_required
|
||||
def index_view(request):
|
||||
return render(request, "home.html", {"subjects": [(subject, Course.objects.filter(subject=subject)) for subject in Subject.objects.all()]})
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from .models import User
|
||||
|
||||
from .models import Group, User
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
admin.site.register(User)
|
||||
admin.site.register(Group)
|
||||
|
|
50
studyguides/apps/users/migrations/0001_initial.py
Normal file
50
studyguides/apps/users/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Generated by Django 3.0.6 on 2020-10-27 14:01
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import studyguides.apps.users.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('username', models.CharField(max_length=32, unique=True)),
|
||||
('first_name', models.CharField(max_length=35)),
|
||||
('last_name', models.CharField(max_length=70)),
|
||||
('email', models.EmailField(max_length=50)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('is_service', models.BooleanField(default=False)),
|
||||
('is_student', models.BooleanField(default=False)),
|
||||
('is_teacher', models.BooleanField(default=False)),
|
||||
('is_superuser', models.BooleanField(default=False)),
|
||||
('_is_staff', models.BooleanField(default=False)),
|
||||
('date_joined', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', studyguides.apps.users.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Group',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('is_service', models.BooleanField(default=False)),
|
||||
('name', models.CharField(max_length=32)),
|
||||
('users', models.ManyToManyField(related_name='unix_groups', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -1,48 +1,82 @@
|
|||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
from social_django.utils import load_strategy
|
||||
|
||||
import requests
|
||||
import logging
|
||||
|
||||
from django.contrib.auth.models import AbstractBaseUser
|
||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||
from django.db import models
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Create your models here.
|
||||
class User(AbstractUser):
|
||||
id = models.AutoField(primary_key = True)
|
||||
full_name = models.CharField(max_length = 105)
|
||||
|
||||
class UserManager(DjangoUserManager):
|
||||
pass
|
||||
|
||||
|
||||
class User(AbstractBaseUser):
|
||||
objects = UserManager()
|
||||
|
||||
USERNAME_FIELD = "username"
|
||||
EMAIL_FIELD = "email"
|
||||
REQUIRED_FIELDS = ["first_name", "last_name", "email", "is_teacher"]
|
||||
|
||||
id = models.AutoField(primary_key=True)
|
||||
|
||||
username = models.CharField(unique=True, max_length=32, null=False, blank=False)
|
||||
first_name = models.CharField(max_length=35, null=False, blank=False)
|
||||
last_name = models.CharField(max_length=70, null=False, blank=False)
|
||||
email = models.EmailField(max_length=50, null=False, blank=False)
|
||||
|
||||
is_active = models.BooleanField(default=True, null=False)
|
||||
is_service = models.BooleanField(default=False, null=False)
|
||||
is_student = models.BooleanField(default=False, null=False)
|
||||
is_teacher = models.BooleanField(default=False, null=False)
|
||||
is_superuser = models.BooleanField(default=False, null=False)
|
||||
_is_staff = models.BooleanField(default=False, null=False)
|
||||
|
||||
date_joined = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def has_perm(self, perm, obj=None) -> bool: # pylint: disable=unused-argument
|
||||
return self.is_superuser
|
||||
|
||||
def has_module_perms(self, app_label) -> bool: # pylint: disable=unused-argument
|
||||
return self.is_superuser
|
||||
|
||||
@property
|
||||
def short_name(self):
|
||||
return self.username
|
||||
def __str__(self):
|
||||
def is_staff(self) -> bool:
|
||||
return self._is_staff or self.is_superuser
|
||||
|
||||
@is_staff.setter
|
||||
def is_staff(self, staff: bool) -> None:
|
||||
self._is_staff = staff
|
||||
|
||||
@property
|
||||
def full_name(self) -> str:
|
||||
return self.first_name + " " + self.last_name
|
||||
|
||||
@property
|
||||
def short_name(self) -> str:
|
||||
return self.first_name
|
||||
|
||||
def get_full_name(self) -> str:
|
||||
return self.full_name
|
||||
def empty_fields(self):
|
||||
list = []
|
||||
for field in User._meta.fields:
|
||||
list.append((field.value_from_object(self),field))
|
||||
return list
|
||||
def api_request(self, url, params={}, refresh=True):
|
||||
s = self.get_social_auth()
|
||||
params.update({"format": "json"})
|
||||
params.update({"access_token": s.access_token})
|
||||
r = requests.get(
|
||||
"https://ion.tjhsst.edu/api/{}".format(url),
|
||||
params = params,
|
||||
)
|
||||
if r.status_code == 401:
|
||||
if refresh:
|
||||
try:
|
||||
self.get_social_auth().refresh_token(load_strategy())
|
||||
except BaseException as e:
|
||||
logger.exception(str(e))
|
||||
return self.api_request(url, params, False)
|
||||
else:
|
||||
logger.error(
|
||||
"Ion API Request Failure: {} {}".format(r.status_code,
|
||||
r.json()))
|
||||
return r.json()
|
||||
|
||||
def get_short_name(self) -> str:
|
||||
return self.short_name
|
||||
|
||||
def get_social_auth(self):
|
||||
return self.social_auth.get(provider = "ion")
|
||||
return self.social_auth.get(provider="ion")
|
||||
|
||||
def __str__(self):
|
||||
return self.username
|
||||
|
||||
def __repr__(self):
|
||||
return "<User: {} ({})>".format(self.username, self.id)
|
||||
|
||||
|
||||
class Group(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
is_service = models.BooleanField(default=False)
|
||||
name = models.CharField(max_length=32)
|
||||
users = models.ManyToManyField(User, related_name="unix_groups")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -1,10 +0,0 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "users"
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
]
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
from django.shortcuts import render, redirect
|
||||
from django import http
|
||||
from .models import User
|
||||
from django.forms import formset_factory
|
||||
# Create your views here.
|
||||
|
|
@ -42,9 +42,9 @@ INSTALLED_APPS = [
|
|||
'django.contrib.staticfiles',
|
||||
'social_django',
|
||||
'studyguides.apps.courses',
|
||||
'studyguides.apps.home',
|
||||
'studyguides.apps.auth',
|
||||
'studyguides.apps.users',
|
||||
'studyguides.apps.auth.apps.AuthConfig',
|
||||
'studyguides.apps.home',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
@ -72,8 +72,6 @@ TEMPLATES = [
|
|||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'social_django.context_processors.backends',
|
||||
'social_django.context_processors.login_redirect',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -111,12 +109,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||
},
|
||||
]
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'studyguides.apps.auth.oauth.IonOauth2',
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
)
|
||||
AUTHENTICATION_BACKENDS = ('studyguides.apps.auth.oauth.IonOauth2',)
|
||||
|
||||
SOCIAL_AUTH_USER_FIELDS = ['username', 'full_name', 'first_name', 'last_name', 'email', 'id']
|
||||
SOCIAL_AUTH_USER_FIELDS = ['username', 'first_name', 'last_name', 'email', 'id', "is_teacher", "is_student",]
|
||||
|
||||
SOCIAL_AUTH_URL_NAMESPACE = 'social'
|
||||
|
||||
|
@ -134,8 +129,6 @@ SOCIAL_AUTH_PIPELINE = (
|
|||
|
||||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
SOCIAL_AUTH_ALWAYS_ASSOCIATE = True
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/2.2/topics/i18n/
|
||||
|
||||
|
@ -150,10 +143,12 @@ USE_L10N = True
|
|||
USE_TZ = True
|
||||
|
||||
LOGIN_URL = "auth:login"
|
||||
LOGIN_REDIRECT_URL = "users:index"
|
||||
LOGOUT_REDIRECT_URL = "home:index"
|
||||
LOGIN_REDIRECT_URL = "auth:index"
|
||||
|
||||
SOCIAL_AUTH_LOGIN_ERROR_URL = '/'
|
||||
SESSION_SAVE_EVERY_REQUEST = True
|
||||
|
||||
SOCIAL_AUTH_ALWAYS_ASSOCIATE = True
|
||||
SOCIAL_AUTH_LOGIN_ERROR_URL = "/"
|
||||
SOCIAL_AUTH_RAISE_EXCEPTIONS = False
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
|
|
43
studyguides/static/login.css
Normal file
43
studyguides/static/login.css
Normal file
|
@ -0,0 +1,43 @@
|
|||
.btn.btn-ion {
|
||||
text-decoration: none;
|
||||
color: #484848;
|
||||
display: inline-block;
|
||||
line-height: 18px;
|
||||
padding: 7px 10px;
|
||||
margin: 2px 0;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,.9);
|
||||
white-space: nowrap;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background: #f7f7f4;
|
||||
background: -moz-linear-gradient(top,#f7f7f4 0%,#eaeaea 100%);
|
||||
background: -webkit-linear-gradient(top,#f7f7f4 0%,#eaeaea 100%);
|
||||
background: linear-gradient(to bottom,#f7f7f4 0%,#eaeaea 100%);
|
||||
border: 1px solid #ddd;
|
||||
border-bottom-color: #c5c5c5;
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,.05);
|
||||
-moz-box-shadow: 0 1px 3px rgba(0,0,0,.05);
|
||||
-pie-box-shadow: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,.05);
|
||||
vertical-align: middle;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
-o-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.login-box {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
border: 1px solid rgb(24, 82, 103);
|
||||
margin: 15px auto;
|
||||
max-width: 438px;
|
||||
}
|
17
studyguides/templates/login.html
Normal file
17
studyguides/templates/login.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block head %}
|
||||
<link rel='stylesheet' href="{% static 'login.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<main>
|
||||
<h1 class='header_title'>Study Guides</h1>
|
||||
<div class='login-box'>
|
||||
<p><b>Login in with your Intranet account</b> to access the Study Guide website.</p>
|
||||
<a href="{% url 'social:begin' 'ion' %}{% if request.GET.next %}?next={{ request.GET.next|urlencode }}{% endif %}" class='btn btn-ion'>Log in with Ion</a>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -20,11 +20,10 @@ from django.conf.urls.static import static
|
|||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
|
||||
path('auth/', include('studyguides.apps.auth.urls', namespace='auth')),
|
||||
path('', include('social_django.urls', namespace='social')),
|
||||
path('', include('studyguides.apps.auth.urls', namespace='auth')),
|
||||
path('', include('studyguides.apps.courses.urls', namespace='courses')),
|
||||
path('', include('studyguides.apps.home.urls', namespace='home')),
|
||||
path('', include('social_django.urls', namespace='social')),
|
||||
|
||||
]
|
||||
if settings.DEBUG:
|
||||
|
|
Loading…
Reference in New Issue
Block a user