Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/accounts/canvas_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ def get_authorization_url(self, request: HttpRequest) -> str:

base_url = self._settings.CANVAS_BASE_URL.rstrip("/")
client_id = self._settings.CANVAS_CLIENT_ID
redirect_uri = request.build_absolute_uri(
reverse("accounts:canvas_callback")
)
redirect_uri = request.build_absolute_uri(reverse("accounts:canvas_callback"))
scopes = getattr(self._settings, "CANVAS_OAUTH_SCOPES", "")

params = (
Expand Down
36 changes: 25 additions & 11 deletions src/accounts/migrations/0004_add_canvas_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,39 @@


class Migration(migrations.Migration):

dependencies = [
('accounts', '0003_teacherassistant'),
("accounts", "0003_teacherassistant"),
]

operations = [
migrations.CreateModel(
name='CanvasProfile',
name="CanvasProfile",
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('canvas_user_id', models.CharField(max_length=64, unique=True)),
('access_token', models.CharField(blank=True, max_length=255)),
('refresh_token', models.CharField(blank=True, max_length=255)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='canvas_profile', to=settings.AUTH_USER_MODEL)),
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("canvas_user_id", models.CharField(max_length=64, unique=True)),
("access_token", models.CharField(blank=True, max_length=255)),
("refresh_token", models.CharField(blank=True, max_length=255)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="canvas_profile",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
'db_table': 'accounts_canvas_profile',
"db_table": "accounts_canvas_profile",
},
),
]
16 changes: 4 additions & 12 deletions src/accounts/tests/test_canvas_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ def test_creates_new_user_with_student_profile(self):
self.assertTrue(user.is_email_verified)
self.assertTrue(hasattr(user, "student_profile"))
self.assertTrue(
CanvasProfile.objects.filter(
canvas_user_id="100", user=user
).exists()
CanvasProfile.objects.filter(canvas_user_id="100", user=user).exists()
)

def test_returns_existing_user_by_canvas_user_id(self):
Expand All @@ -53,9 +51,7 @@ def test_returns_existing_user_by_canvas_user_id(self):
self.assertEqual(result.id, user.id)

def test_links_existing_user_by_email(self):
user = User.objects.create_user(
username="link@uw.edu", email="link@uw.edu"
)
user = User.objects.create_user(username="link@uw.edu", email="link@uw.edu")

info = CanvasUserInfo(
canvas_user_id="300", name="Link User", email="link@uw.edu"
Expand All @@ -64,9 +60,7 @@ def test_links_existing_user_by_email(self):
self.assertFalse(created)
self.assertEqual(result.id, user.id)
self.assertTrue(
CanvasProfile.objects.filter(
canvas_user_id="300", user=user
).exists()
CanvasProfile.objects.filter(canvas_user_id="300", user=user).exists()
)

def test_handles_missing_email_with_login_id(self):
Expand Down Expand Up @@ -221,9 +215,7 @@ def test_redirects_to_canvas_authorization_url(self):
self.assertIn("state=", response.url)
self.assertIn("redirect_uri=", response.url)
self.assertIn("scope=", response.url)
self.assertIn(
"url:GET%7C/api/v1/users/self", response.url
)
self.assertIn("url:GET%7C/api/v1/users/self", response.url)

def test_redirects_home_when_already_authenticated(self):
user = User.objects.create_user(username="test@uw.edu", password="pw123")
Expand Down
11 changes: 4 additions & 7 deletions src/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,8 @@ def get(self, request: HttpRequest) -> HttpResponse:

if not self._service._settings.CANVAS_CLIENT_ID:
messages.error(
request, "Canvas login is not configured. Please use email/password instead."
request,
"Canvas login is not configured. Please use email/password instead.",
)
return redirect("accounts:login")

Expand Down Expand Up @@ -502,13 +503,9 @@ def _process_callback(self, request: HttpRequest) -> CanvasCallbackResult:

if not self._service.verify_state(request, state):
logger.warning("Canvas OAuth2 state verification failed")
return CanvasCallbackError(
error="Authentication failed. Please try again."
)
return CanvasCallbackError(error="Authentication failed. Please try again.")

redirect_uri = request.build_absolute_uri(
reverse("accounts:canvas_callback")
)
redirect_uri = request.build_absolute_uri(reverse("accounts:canvas_callback"))

token_result = self._service.exchange_code(code, redirect_uri)
if not token_result.success:
Expand Down