Skip to content

Commit

Permalink
Staging Changes (#855)
Browse files Browse the repository at this point in the history
* feat(client): dialog for when user logs out

* added auth cleanup and user addition to db

* lint

* changed ci

* Update auth.service.ts

* Feature: Changed dark mode settings toggle to icon button in sidebar (Sidebar Dark Mode Icon #850) (#850)

* adding redirect link to devsoc

* made dark mode button component

* removed dark mode toggle

* removed darkmode toggle from settings

* made sidebar footer icons padding consistent

* added prop type for dark mode button

* sync dark mode button updates

* fully implemented dark mode button

---------

Co-authored-by: ray <[email protected]>
Co-authored-by: Dylan Zhang <[email protected]>

* docs: added our latest 2024 subcom member

* renamed migrations

---------

Co-authored-by: hhuolu <[email protected]>
Co-authored-by: dlyn <[email protected]>
Co-authored-by: Dylan Zhang <[email protected]>
Co-authored-by: Shaam <[email protected]>
Co-authored-by: Jasmine Tran <[email protected]>
  • Loading branch information
6 people authored Jul 11, 2024
1 parent 543dbec commit c1b9c77
Show file tree
Hide file tree
Showing 15 changed files with 120 additions and 44 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
working-directory: ${{ matrix.component }}
- name: Generate Prisma Types from Schema
run: npx prisma generate
working-directory: ${{ matrix.component }}
working-directory: server
- name: Build
run: pnpm run build
working-directory: ${{ matrix.component }}
Expand All @@ -51,4 +51,4 @@ jobs:
cache: 'pip'
- name: Install dependencies
run: pip install -r requirements.txt
working-directory: auto_server
working-directory: auto_server
50 changes: 50 additions & 0 deletions client/src/components/sidebar/DarkModeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
NightsStay as DarkModeIcon,
LightMode as LightModeIcon,
} from '@mui/icons-material';
import { IconButton, Tooltip, Typography } from '@mui/material';
import { styled } from '@mui/system';
import React, { useContext } from 'react';

import { DarkModeButtonProps } from '../../interfaces/PropTypes';
import { AppContext } from '../../context/AppContext';

const ToggleDarkModeButton = styled(IconButton)`
display: flex;
border-radius: 8px;
justify-content: flex-between;
padding: 12px 12px 12px 12px;
`;

const IndividualComponentTypography = styled(Typography)<{ collapsed: boolean }>`
padding-left: ${(props) => (props.collapsed ? '0px' : '12px')};
font-size: 16px;
`;

const DarkModeButton: React.FC<DarkModeButtonProps> = ({
collapsed,
}) => {
const {
isDarkMode,
setIsDarkMode,
} = useContext(AppContext);

const toggleDarkMode = () => {
setIsDarkMode(!isDarkMode);
};

return (
<>
<Tooltip title={collapsed ? (isDarkMode ? "Dark Mode" : "Light Mode") : ''} placement="right">
<ToggleDarkModeButton color="inherit" onClick={toggleDarkMode}>
{isDarkMode ? (<LightModeIcon />) : (<DarkModeIcon />)}
<IndividualComponentTypography collapsed={collapsed}>
{collapsed ? '' : (isDarkMode ? "Change to Light Mode" : "Change to Dark Mode")}
</IndividualComponentTypography>
</ToggleDarkModeButton>
</Tooltip>
</>
);
};

export default DarkModeButton;
3 changes: 0 additions & 3 deletions client/src/components/sidebar/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ const SettingText = styled('div')`

const Settings: React.FC = () => {
const {
isDarkMode,
setIsDarkMode,
isSquareEdges,
setIsSquareEdges,
is12HourMode,
Expand All @@ -35,7 +33,6 @@ const Settings: React.FC = () => {
} = useContext(AppContext);

const settingsToggles: { state: boolean; setter: (mode: boolean) => void; desc: string }[] = [
{ state: isDarkMode, setter: setIsDarkMode, desc: 'Dark mode' },
{ state: isSquareEdges, setter: setIsSquareEdges, desc: 'Square corners on classes' },
{ state: is12HourMode, setter: setIs12HourMode, desc: '12-hour time' },
{ state: isShowOnlyOpenClasses, setter: setisShowOnlyOpenClasses, desc: 'Show only open classes' },
Expand Down
7 changes: 6 additions & 1 deletion client/src/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Group,
CalendarMonth,
} from '@mui/icons-material';
import { AppBar, Typography, AppBarProps, Divider, Button } from '@mui/material';
import { AppBar, Typography, AppBarProps, Divider } from '@mui/material';
import { styled } from '@mui/system';
import React, { useEffect, useRef, useState } from 'react';

Expand All @@ -21,6 +21,7 @@ import Settings from './Settings';
import TermSelect from './TermSelect';
import UserAccount from './UserAccount';
import { uniqueId } from 'lodash-es';
import DarkModeButton from './DarkModeButton';

const LogoImg = styled('img')`
height: 46px;
Expand Down Expand Up @@ -84,6 +85,7 @@ const SidebarFooter = styled('div')`
display: flex;
flex-direction: column;
padding: 10px 16px 20px 16px;
gap: 8px;
`;
const SidebarFooterText = styled('div')`
display: flex;
Expand Down Expand Up @@ -211,6 +213,9 @@ const Sidebar: React.FC = () => {
</NavComponentsContainer>
</SideBarContainer>
<SidebarFooter>
<DarkModeButton
collapsed={collapsed}
/>
{/* TODO: dummy logic - to be replaced */}
<UserAccount collapsed={collapsed} />
{!collapsed ? (
Expand Down
14 changes: 2 additions & 12 deletions client/src/components/sidebar/UserAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { AccountCircle, LoginRounded, LogoutRounded } from '@mui/icons-material';
import { Button, IconButton, Tooltip } from '@mui/material';
import { Button, Dialog, IconButton, Tooltip } from '@mui/material';
import { styled } from '@mui/system';
import { API_URL } from '../../api/config';
import StyledDialog from '../StyledDialog';
Expand Down Expand Up @@ -58,7 +58,6 @@ const UserAccount: React.FC<UserAccountProps> = ({ collapsed }) => {
credentials: 'include',
});
const userResponse = await response.text();
// const userResponse = await response.text();
if (userResponse !== '') {
setLogin(true);
setUser({ zid: JSON.parse(userResponse) });
Expand All @@ -70,10 +69,7 @@ const UserAccount: React.FC<UserAccountProps> = ({ collapsed }) => {
console.log(error);
}
}
// Execute the created function directly
runAsync();
// https://stackoverflow.com/a/55854902/1098564
// eslint-disable-next-line
}, []);
const loginCall = async () => {
setWindowLocation(window.location.href);
Expand All @@ -82,11 +78,10 @@ const UserAccount: React.FC<UserAccountProps> = ({ collapsed }) => {
} catch (error) {
console.log(error);
}
// window.location.replace(`${API_URL.server}/auth/login`);
};
const logoutCall = async () => {
try {
const _response = await fetch(`${API_URL.server}/auth/logout`, {
await fetch(`${API_URL.server}/auth/logout`, {
credentials: 'include',
});
} catch (error) {
Expand All @@ -95,11 +90,6 @@ const UserAccount: React.FC<UserAccountProps> = ({ collapsed }) => {
window.location.replace(windowLocation);
setUser({ zid: '' });
};
// https://stackoverflow.com/a/32108184/1098564
// const isEmpty = (obj: Object) => {
// return Object.keys(obj).length === 0 && obj.constructor === Object;
// };

if (!login) {
return collapsed ? (
<Tooltip title="Log in" placement="right">
Expand Down
4 changes: 4 additions & 0 deletions client/src/interfaces/PropTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export interface CourseContextProviderProps {
children: ReactNode;
}

export interface DarkModeButtonProps {
collapsed: boolean;
}

export interface CustomModalProps {
title: string;
toolTipTitle: string;
Expand Down
3 changes: 2 additions & 1 deletion client/team.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"Jordan Benjamin",
"Nikki Qin",
"Lucy Chhuo",
"Sohum Shah"
"Sohum Shah",
"Dylan Zhang"
]
}
19 changes: 13 additions & 6 deletions server/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ services:
container_name: notangles-server
image: notangles-server
restart: always
build:
context: .
dockerfile: Dockerfile
build: .
depends_on:
- database.notangles_db
- database
ports:
- '3001:3001'
networks:
- notangles_network
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?schema=public

database.notangles_db:
database:
container_name: notangles-database
hostname: notangles_database
container_name: notangles_database
restart: always
image: postgres:alpine
ports:
Expand All @@ -25,7 +27,12 @@ services:
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres:/var/lib/postgresql/data
networks:
- notangles_network

volumes:
postgres:
name: server
networks:
notangles_network:
driver: bridge
2 changes: 2 additions & 0 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { GroupModule } from './group/group.module';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { ConfigService } from '@nestjs/config';
import { join } from 'path';
import config from './config';
@Module({
imports: [
ConfigModule.forRoot({
load: [config],
isGlobal: true,
envFilePath: '../.env',
}),
Expand Down
20 changes: 16 additions & 4 deletions server/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import { Controller, Get, Request, Res, UseGuards } from '@nestjs/common';
import { Response } from 'express';

import { REDIRECT_LINK } from '../config';
import { AuthService } from './auth.service';
import { LoginGuard } from './login.guard';
import { UserService } from 'src/user/user.service';
import { ConfigService } from '@nestjs/config';

@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
constructor(
private authService: AuthService,
private userService: UserService,
private configService: ConfigService,
) {}

@UseGuards(LoginGuard)
@Get('/login')
login() {}

@Get('/user')
user(@Request() req, @Res() res: Response) {
async user(@Request() req, @Res() res: Response) {
if (req.user) {
const userID = req.user.userinfo.sub;
try {
await this.userService.getUserInfo(userID);
} catch (e) {
console.debug(`User ${userID} does not exist in db, adding them now!`);
await this.userService.setUserProfile(userID, '', '', '');
}
return res.json(req.user.userinfo.sub);
}

Expand All @@ -25,7 +37,7 @@ export class AuthController {
@UseGuards(LoginGuard)
@Get('/callback/csesoc')
loginCallback(@Res() res: Response) {
res.redirect(REDIRECT_LINK);
res.redirect(this.configService.get<string>('app.redirectLink'));
}

@Get('/logout')
Expand Down
10 changes: 9 additions & 1 deletion server/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { OidcStrategy, buildOpenIdClient } from './oidc.strategy';
import { SessionSerializer } from './session.serializer';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserService } from 'src/user/user.service';
import { PrismaService } from 'src/prisma/prisma.service';

const OidcStrategyFactory = {
provide: 'OidcStrategy',
Expand All @@ -19,6 +21,12 @@ const OidcStrategyFactory = {
PassportModule.register({ session: true, defaultStrategy: 'oidc' }),
],
controllers: [AuthController],
providers: [OidcStrategyFactory, SessionSerializer, AuthService],
providers: [
OidcStrategyFactory,
SessionSerializer,
AuthService,
UserService,
PrismaService,
],
})
export class AuthModule {}
5 changes: 3 additions & 2 deletions server/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Injectable, Request, Res } from '@nestjs/common';
import { Response } from 'express';
import { Issuer } from 'openid-client';
import { REDIRECT_LINK } from '../config';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AuthService {
constructor(private configService: ConfigService) {}
async logout(@Request() req, @Res() res: Response): Promise<void> {
const id_token = req.user ? req.user.id_token : undefined;

Expand All @@ -13,7 +14,7 @@ export class AuthService {
);

if (!id_token || !TrustIssuer) {
return res.redirect(REDIRECT_LINK);
return res.redirect(this.configService.get<string>('app.redirectLink'));
}

req.logout((err) => {
Expand Down
2 changes: 0 additions & 2 deletions server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@ export default registerAs('app', () => ({
client: `${process.env.CLIENT_HOST_NAME}:${process.env.CLIENT_HOST_PORT}`,
redirectLink: `${process.env.CLIENT_HOST_NAME}:${process.env.CLIENT_HOST_PORT}`,
}));

export const REDIRECT_LINK = 'https://notangles.devsoc.app/';
21 changes: 11 additions & 10 deletions server/src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export class UserService {
constructor(private readonly prisma: PrismaService) {}
async getUserInfo(_userId: string): Promise<UserDTO> {
try {
const { userId, timetable, ...userData } =
const { userID, timetable, ...userData } =
await this.prisma.user.findUniqueOrThrow({
where: { userId: _userId },
where: { userID: _userId },
include: {
timetable: {
include: {
Expand Down Expand Up @@ -54,8 +54,8 @@ export class UserService {
_lastName?: string,
): Promise<any> {
try {
const test = {
userId: _userId,
const userInfo = {
userID: _userId,
firstname: _firstName,
lastname: _lastName,
email: _email,
Expand All @@ -64,20 +64,21 @@ export class UserService {
return Promise.resolve(
this.prisma.user.upsert({
where: {
userId: _userId,
userID: _userId,
},
create: test,
update: test,
create: userInfo,
update: userInfo,
}),
);
} catch (e) {}
}

async getUserSettings(_userId: string): Promise<SettingsDto> {
try {
const { userId, ...settings } = await this.prisma.settings.findUniqueOrThrow({
where: { userId: _userId },
});
const { userId, ...settings } =
await this.prisma.settings.findUniqueOrThrow({
where: { userId: _userId },
});

return Promise.resolve(settings);
} catch (e) {
Expand Down

0 comments on commit c1b9c77

Please sign in to comment.