Skip to content

Image validation and size optimization for Profile image upload from both front-end and back-end #513

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
24 changes: 23 additions & 1 deletion csm_web/csm_web/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from factory.django import DjangoModelFactory
from rest_framework.serializers import ModelSerializer, Serializer
from sentry_sdk.integrations.django import DjangoIntegration
from storages.backends.s3boto3 import S3Boto3Storage

# Analogous to RAILS_ENV, is one of {prod, staging, dev}. Defaults to dev. This default can
# be dangerous, but is worth it to avoid the hassle for developers setting the local ENV var
Expand Down Expand Up @@ -67,6 +68,7 @@
"frontend",
"django_extensions",
"django.contrib.postgres",
"storages",
]

SHELL_PLUS_SUBCLASSES_IMPORT = [ModelSerializer, Serializer, DjangoModelFactory]
Expand Down Expand Up @@ -172,7 +174,7 @@
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
AWS_S3_VERIFY = True
AWS_QUERYSTRING_AUTH = False # public bucket
AWS_QUERYSTRING_AUTH = True

STORAGES = {
"default": {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"},
Expand All @@ -186,6 +188,24 @@

STATIC_URL = "/static/"


class ProfileImageStorage(S3Boto3Storage):
bucket_name = "csm-web-profile-pictures"
file_overwrite = True # should be true so that we replace one profile for user

def get_accessed_time(self, name):
# Implement logic to get the last accessed time
raise NotImplementedError("This backend does not support this method.")

def get_created_time(self, name):
# Implement logic to get the creation time
raise NotImplementedError("This backend does not support this method.")
Comment on lines +196 to +202
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to be an issue? Not sure when these methods are called.


def path(self, name):
# S3 does not support file paths
raise NotImplementedError("This backend does not support absolute paths.")


if DJANGO_ENV in (PRODUCTION, STAGING):
# Enables compression and caching
STORAGES["staticfiles"] = {
Expand Down Expand Up @@ -239,6 +259,8 @@
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
"DEFAULT_PARSER_CLASSES": [
"djangorestframework_camel_case.parser.CamelCaseJSONParser",
"rest_framework.parsers.FormParser",
"rest_framework.parsers.MultiPartParser",
],
}

Expand Down
13 changes: 12 additions & 1 deletion csm_web/frontend/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { emptyRoles, Roles } from "../utils/user";
import CourseMenu from "./CourseMenu";
import Home from "./Home";
import Policies from "./Policies";
import UserProfile from "./UserProfile";
import { DataExport } from "./data_export/DataExport";
import { EnrollmentMatcher } from "./enrollment_automation/EnrollmentMatcher";
import { Resources } from "./resource_aggregation/Resources";
Expand Down Expand Up @@ -42,6 +43,13 @@ const App = () => {
<Route path="matcher/*" element={<EnrollmentMatcher />} />
<Route path="policies/*" element={<Policies />} />
<Route path="export/*" element={<DataExport />} />
{
// TODO: add route for profiles (/profile/:id/* element = {UserProfile})
// TODO: add route for your own profile /profile/*
// reference Section
}
Comment on lines +46 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODOs leftover that should be deleted

<Route path="profile/*" element={<UserProfile />} />
<Route path="profile/:id/*" element={<UserProfile />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
Expand Down Expand Up @@ -80,7 +88,7 @@ function Header(): React.ReactElement {
};

/**
* Helper function to determine class name for the home NavLInk component;
* Helper function to determine class name for the home NavLnk component;
* is always active unless we're in another tab.
*/
const homeNavlinkClass = () => {
Expand Down Expand Up @@ -141,6 +149,9 @@ function Header(): React.ReactElement {
<NavLink to="/policies" className={navlinkClassSubtitle}>
<h3 className="site-subtitle">Policies</h3>
</NavLink>
<NavLink to="/profile" className={navlinkClassSubtitle}>
<h3 className="site-subtitle">Profile</h3>
</NavLink>
<a id="logout-btn" href="#" onClick={logout} title="Log out">
<LogOutIcon className="icon" />
</a>
Expand Down
2 changes: 1 addition & 1 deletion csm_web/frontend/src/components/CourseMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import React, { useEffect, useState } from "react";
import { Link, Route, Routes } from "react-router-dom";

import { DEFAULT_LONG_LOCALE_OPTIONS, DEFAULT_TIMEZONE } from "../utils/datetime";
import { useUserInfo } from "../utils/queries/base";
import { useCourses } from "../utils/queries/courses";
import { useUserInfo } from "../utils/queries/profiles";
import { Course as CourseType, UserInfo } from "../utils/types";
import LoadingSpinner from "./LoadingSpinner";
import Course from "./course/Course";
Expand Down
Loading
Loading