Skip to content

Commit

Permalink
Merge branch 'development' of https://github.com/bounswe/bounswe2023g…
Browse files Browse the repository at this point in the history
…roup7 into feature/BE/321/follow-unfollow
  • Loading branch information
omersafakbebek committed Oct 30, 2023
2 parents 6a87bad + 134d100 commit ac4e6d9
Show file tree
Hide file tree
Showing 13 changed files with 282 additions and 90 deletions.
37 changes: 36 additions & 1 deletion ludos/backend/src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { Body, Controller, HttpCode, Post } from '@nestjs/common';
import {
Body,
Controller,
HttpCode,
Post,
Put,
Req,
UseGuards,
} from '@nestjs/common';
import {
ApiBadRequestResponse,
ApiBearerAuth,
ApiConflictResponse,
ApiOkResponse,
ApiOperation,
Expand All @@ -12,6 +21,10 @@ import { RegisterDto } from '../dtos/user/request/register.dto';
import { LoginResponseDto } from '../dtos/user/response/login-response.dto';
import { RegisterResponseDto } from '../dtos/user/response/register-response.dto';
import { UserService } from '../services/user.service';
import { ChangePasswordResponseDto } from '../dtos/user/response/change-password-response.dto';
import { ChangePasswordDto } from '../dtos/user/request/change-password.dto';
import { AuthGuard } from '../services/guards/auth.guard';
import { AuthorizedRequest } from '../interfaces/common/authorized-request.interface';

@ApiTags('user')
@Controller('user')
Expand Down Expand Up @@ -49,4 +62,26 @@ export class UserController {
public async login(@Body() input: LoginDto) {
return await this.userService.login(input);
}

@ApiOkResponse({
description: 'Password change has been succesful!',
type: ChangePasswordResponseDto,
})
@ApiUnauthorizedResponse({
description: 'Invalid Credentials',
})
@ApiBadRequestResponse({
description: 'Bad Request',
})
@HttpCode(200)
@ApiOperation({ summary: 'Change Password Endpoint' })
@ApiBearerAuth()
@UseGuards(AuthGuard)
@Put('/change-password')
public async changePassword(
@Req() req: AuthorizedRequest,
@Body() input: ChangePasswordDto,
) {
return await this.userService.changePassword(req.user.id, input);
}
}
18 changes: 18 additions & 0 deletions ludos/backend/src/dtos/user/request/change-password.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString, MinLength } from 'class-validator';
export class ChangePasswordDto {
@ApiProperty({
minLength: 8,
example: '12345678',
})
@IsString()
@IsNotEmpty()
oldPassword: string;
@ApiProperty({
minLength: 8,
example: '12345678',
})
@IsString()
@MinLength(8)
newPassword: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';

export class ChangePasswordResponseDto {
@ApiProperty()
isSuccess: boolean;
constructor(isSuccess: boolean) {
this.isSuccess = isSuccess;
}
}
32 changes: 28 additions & 4 deletions ludos/backend/src/services/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { RegisterDto } from '../dtos/user/request/register.dto';
import { UserRepository } from '../repositories/user.repository';
import { RegisterResponseDto } from '../dtos/user/response/register-response.dto';
import {
BadRequestException,
ConflictException,
Injectable,
InternalServerErrorException,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ChangePasswordDto } from '../dtos/user/request/change-password.dto';
import { LoginDto } from '../dtos/user/request/login.dto';
import { RegisterDto } from '../dtos/user/request/register.dto';
import { ChangePasswordResponseDto } from '../dtos/user/response/change-password-response.dto';
import { LoginResponseDto } from '../dtos/user/response/login-response.dto';
import { JwtService } from '@nestjs/jwt';
import { RegisterResponseDto } from '../dtos/user/response/register-response.dto';
import { Payload } from '../interfaces/user/payload.interface';
import { UserRepository } from '../repositories/user.repository';
@Injectable()
export class UserService {
constructor(
Expand Down Expand Up @@ -49,4 +53,24 @@ export class UserService {
accessToken,
};
}

public async changePassword(
userId: string,
changePasswordDto: ChangePasswordDto,
): Promise<ChangePasswordResponseDto> {
const user = await this.userRepository.findUserById(userId);
if (!user) {
throw new NotFoundException('User not found!');
}
if (!(await user.compareEncryptedPassword(changePasswordDto.oldPassword))) {
throw new UnauthorizedException('Wrong Password!');
}

if (changePasswordDto.oldPassword == changePasswordDto.newPassword) {
throw new BadRequestException('Old and new passwords can not be same!');
}
user.password = changePasswordDto.newPassword;
await this.userRepository.save(user);
return new ChangePasswordResponseDto(true);
}
}
7 changes: 6 additions & 1 deletion ludos/frontend/src/components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SettingsIcon from "@mui/icons-material/Settings";
import SearchIcon from "@mui/icons-material/Search";
import logo from "../assets/logo.png";
import { useNavigate } from "react-router-dom";
import { Link } from "react-router-dom";

const Header = ({ userLoggedIn, onSettingsClick }) => {
const [anchorEl, setAnchorEl] = useState(null);
Expand All @@ -31,6 +32,10 @@ const Header = ({ userLoggedIn, onSettingsClick }) => {
navigate("/signup");
};

function handleLogout() {
localStorage.removeItem("accessToken");
}

return (
<AppBar
position="static"
Expand Down Expand Up @@ -92,7 +97,7 @@ const Header = ({ userLoggedIn, onSettingsClick }) => {
<MenuItem onClick={() => onSettingsClick()}>
Go to Settings
</MenuItem>
<MenuItem onClick={() => onSettingsClick()}>Log out</MenuItem>
<MenuItem onClick={handleLogout} component={Link} to="/login">Log out</MenuItem>
</Menu>
</>
) : (
Expand Down
8 changes: 6 additions & 2 deletions ludos/frontend/src/components/sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ function Sidebar({ userLoggedIn }) {
setAnchorEl(null);
};

function handleLogout() {
localStorage.removeItem("accessToken");
}

return (
<div style={rootSx}>
<Drawer style={drawer} variant="permanent">
Expand Down Expand Up @@ -202,8 +206,8 @@ function Sidebar({ userLoggedIn }) {
</MenuItem>
<MenuItem
component={Link}
to="/log-out"
onClick={handleProfileClose}
to="/login"
onClick={handleLogout}
>
Log Out
</MenuItem>
Expand Down
6 changes: 3 additions & 3 deletions ludos/frontend/src/pages/LoginPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ export default function Login() {
helperText={passwordEmpty ? "Password cannot be empty." : ""}
/>
<Button
type="button"
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2, backgroundColor: "#F49A32" }}
Expand All @@ -216,12 +216,12 @@ export default function Login() {
xs
sx={{ display: "flex", alignItems: "flex-start" }}
>
<Link href="#" variant="body2" color={"#F49A32"}>
<Link href="#" variant="body2" color="#F49A32">
Forgot password?
</Link>
</Grid>
<Grid item sx={{ display: "flex", alignItems: "flex-end" }}>
<Link href="/signup" variant="body2" color={"#F49A32"}>
<Link href="/signup" variant="body2" color="#F49A32">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
Expand Down
6 changes: 4 additions & 2 deletions ludos/frontend/src/pages/SignupPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export default function SignUpForm() {

const handleSignup = (event) => {


event.preventDefault();

if (password.length < 8) {
setPasswordError(true);
return;
Expand All @@ -53,7 +56,6 @@ export default function SignUpForm() {
}


event.preventDefault();
axiosInstance.post('/user', { email, username, password })
.then((response) => {
const accessToken = response.data.token;
Expand Down Expand Up @@ -181,7 +183,7 @@ export default function SignUpForm() {
helperText={passwordsMatch ? 'Passwords must match.' : ''}
/>
<Button
type="button"
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2, backgroundColor: '#F49A32' }}
Expand Down
47 changes: 31 additions & 16 deletions ludos/mobile/lib/activation_for_password_reset.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'helper/colors.dart';
import 'reset_password.dart';

class EnterActivation extends StatefulWidget {
Expand All @@ -14,10 +15,12 @@ class _EnterActivationState extends State<EnterActivation> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF6b415e),
backgroundColor: const Color(0xFF101c2c),
appBar: AppBar(
backgroundColor: const Color(0xFF5f1a37),
title: const Text('Forgot Password'),
backgroundColor: const Color(0xFFf89c34),
title: const Text(
'Forgot Password',
),
),
body: SingleChildScrollView(
child: Padding(
Expand All @@ -26,16 +29,18 @@ class _EnterActivationState extends State<EnterActivation> {
mainAxisAlignment: MainAxisAlignment.center,
//crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const SizedBox(height: 20),
const Text(
'Please enter the activation code sent to your email address.',
style: TextStyle(
color: Colors.white60,
color: MyColors.red,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 20),
TextField(
style: const TextStyle(color: MyColors.white),
onChanged: (value) {
setState(() {
activationCode = value;
Expand All @@ -45,30 +50,34 @@ class _EnterActivationState extends State<EnterActivation> {
decoration: const InputDecoration(
labelText: 'Activation Code',
labelStyle: TextStyle(
fontStyle: FontStyle.italic,
fontSize: 15,
color: Color.fromARGB(255, 219, 184, 199),
fontWeight: FontWeight.bold),
color: MyColors.lightBlue, fontWeight: FontWeight.bold),
prefixIcon: Icon(Icons.code),
prefixIconColor: MyColors.lightBlue,
border: UnderlineInputBorder(
borderSide:
BorderSide(color: MyColors.lightBlue, width: 2.0)),
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Color(0xFF5f1a37), width: 2.0),
BorderSide(color: MyColors.lightBlue, width: 2.0),
),
),
cursorColor: const Color(0xFF5f1a37),
cursorColor: MyColors.lightBlue,
),
const SizedBox(height: 25),
Text(
responseForActivationCode,
style: const TextStyle(
color: Colors.white60,
color: MyColors.red,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 20),
const SizedBox(height: 40),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF5f1a37)),
backgroundColor: const Color(0xFFf89c34),
shape: const StadiumBorder()
),
onPressed: () {
// logic to compare activation code with the one sent to the email address
// also responseForActivationCode should be updated accordingly
Expand All @@ -78,16 +87,22 @@ class _EnterActivationState extends State<EnterActivation> {
builder: (context) => (const ResetPassword())));

},
child: const Text('Reset Password'),
child: const Text(
'Reset Password',
style: TextStyle(color: MyColors.darkBlue),
),
),
const SizedBox(height: 20),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF5f1a37)),
backgroundColor: const Color(0xFFf89c34),
shape: const StadiumBorder()
),
onPressed: () {
// logic to resend activation code to email address
},
child: const Text('Resend Verification Code'),
child: const Text('Resend Verification Code',
style: TextStyle(color: MyColors.darkBlue),),
),
],
),
Expand Down
Loading

0 comments on commit ac4e6d9

Please sign in to comment.