Changeset a26f6a1
- Timestamp:
- 08/09/22 16:09:32 (2 years ago)
- Branches:
- master
- Children:
- a569b7c
- Parents:
- 899b19d
- Files:
-
- 9 added
- 15 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/App.js
r899b19d ra26f6a1 6 6 import {Spin} from "antd"; 7 7 import React, {useEffect, useState} from "react"; 8 import {Login, Register} from "./ auth";8 import {Login, Register} from "./Auth/auth"; 9 9 import Dashboard from "./Dashboard"; 10 10 import Reservations from "./Dashboard/Reservations"; … … 13 13 import Menu from "./Dashboard/Menu"; 14 14 import Review from "./Dashboard/Review"; 15 import Confirm from "./Auth/Confirm"; 16 import SendConfirm from "./Auth/SendConfirm"; 17 import SendReset from "./Auth/SendReset"; 18 import Reset from "./Auth/Reset"; 15 19 16 20 17 21 function App() { 18 22 const [user, setUser] = useState(undefined) 19 const [loading, setLoading] = useState( false)23 const [loading, setLoading] = useState(true) 20 24 useEffect(()=>{ 21 25 getUser() … … 24 28 const getUser = () => { 25 29 setLoading(true) 26 axios.get(env.api+'Users/authed',{headers:{Authorization: sessionStorage.getItem('Auth')}}).then(res=>{27 console.log( !res.data)30 axios.get(env.api+'Users/authed',{headers:{Authorization:localStorage.getItem('Auth')}}).then(res=>{ 31 console.log(res.data) 28 32 setUser(res.data) 29 33 setLoading(false) … … 32 36 const logout = () => { 33 37 setUser(undefined); 34 sessionStorage.removeItem('Auth');38 localStorage.removeItem('Auth'); 35 39 window.location.replace('/') 36 40 } … … 48 52 <Route path="/login" element={loading ? <Spin /> : !user ? <Login setUser={setUser}/> : <Navigate to="/dashboard" replace={true} />}/> 49 53 <Route path="/register" element={loading ? <Spin /> : !user ? <Register setUser={setUser}/> : <Navigate to="/dashboard" replace={true} />}/> 54 <Route path="/reset-password" element={loading ? <Spin /> : <SendReset/>}/> 55 <Route path="/reset" element={loading ? <Spin /> : <Reset/>}/> 56 <Route path="/confirm" element={loading ? <Spin /> : <Confirm setUser={setUser} user={user}/>}/> 57 <Route path="/confirm-email" element={loading ? <Spin /> : <SendConfirm setUser={setUser} user={user}/>}/> 50 58 <Route path="/" element={<FrontPage user={user} logout={logout}/>}/> 51 59 </Routes> -
frontend/src/Auth/auth.js
r899b19d ra26f6a1 4 4 import { UserOutlined, LockOutlined } from '@ant-design/icons'; 5 5 import axios from "axios"; 6 import '. /App.css'7 import env from ". /env";6 import '../App.css' 7 import env from "../env"; 8 8 9 9 const setAuthCookie = (token) => { 10 sessionStorage.setItem('Auth','Bearer '+token)10 localStorage.setItem('Auth','Bearer '+token) 11 11 } 12 12 … … 103 103 setUser(res.data) 104 104 setLoading(false) 105 history( res.data.isAdmin ? '/dashboard' : '/')105 history('/confirm-email') 106 106 }) 107 107 } -
frontend/src/Dashboard.js
r899b19d ra26f6a1 11 11 const history = useNavigate() 12 12 const logout = () => { 13 sessionStorage.removeItem('Auth');13 localStorage.removeItem('Auth'); 14 14 setUser(false) 15 15 } -
frontend/src/Dashboard/Menu.js
r899b19d ra26f6a1 25 25 const addMenu = (data) => { 26 26 setLoadingSave(true); 27 axios.post(env.api + 'Menu/',{...data,price: parseInt(data.price)}, { headers: {Authorization: sessionStorage.getItem('Auth')}27 axios.post(env.api + 'Menu/',{...data,price: parseInt(data.price)}, { headers: {Authorization: localStorage.getItem('Auth')} 28 28 }).then(res => { 29 29 notification['success']({ … … 42 42 43 43 const deleteMenu = (id) => { 44 axios.delete(env.api + 'Menu/'+id, {headers: {Authorization: sessionStorage.getItem('Auth')}44 axios.delete(env.api + 'Menu/'+id, {headers: {Authorization: localStorage.getItem('Auth')} 45 45 }).then(res => { 46 46 notification['success']({ -
frontend/src/Dashboard/Reservations.js
r899b19d ra26f6a1 26 26 from: date[0].format('YYYY-MM-DDThh:mm:ss') + 'Z', 27 27 to: date[1].format('YYYY-MM-DDThh:mm:ss') + 'Z' 28 }, headers: {Authorization: sessionStorage.getItem('Auth')}28 }, headers: {Authorization: localStorage.getItem('Auth')} 29 29 }).then(res => { 30 30 axios.get(env.api + 'Reservations/new', { 31 headers: {Authorization: sessionStorage.getItem('Auth')}31 headers: {Authorization: localStorage.getItem('Auth')} 32 32 }).then(newres=>{ 33 33 setNewReservations(newres.data); … … 54 54 params: { 55 55 status: newStatus 56 }, headers: {Authorization: sessionStorage.getItem('Auth')}56 }, headers: {Authorization: localStorage.getItem('Auth')} 57 57 }).then(res => { 58 58 getReservations() … … 68 68 params: { 69 69 tableId: ev.target.value == '' ? 0 : ev.target.value 70 }, headers: {Authorization: sessionStorage.getItem('Auth')}70 }, headers: {Authorization: localStorage.getItem('Auth')} 71 71 }).then(res => { 72 72 console.log("success"); -
frontend/src/Dashboard/Restaurant.js
r899b19d ra26f6a1 37 37 const submitEdit = (form) => { 38 38 setLoadingSave(true); 39 axios.put(env.api + 'Restaurants/',{...form}, { headers: {Authorization: sessionStorage.getItem('Auth')}39 axios.put(env.api + 'Restaurants/',{...form}, { headers: {Authorization: localStorage.getItem('Auth')} 40 40 }).then(res => { 41 41 notification['success']({ -
frontend/src/Dashboard/Review.js
r899b19d ra26f6a1 1 1 import React, {useEffect, useState} from 'react' 2 import {Button, Card, Input, List, Rate, Spin, Tooltip} from "antd";2 import {Button, Card, Input, List, notification, Rate, Spin, Tooltip} from "antd"; 3 3 import axios from "axios"; 4 4 import env from "../env"; … … 12 12 setLoading(true); 13 13 getRestaurant() 14 console.log(props.user) 14 15 },[]) 15 16 useEffect(()=> { … … 36 37 {props.front ? 37 38 (props.user? 38 <Button style={{float:'right'}} type={'primary'} onClick={()=>props. setVisible(true)}>Внеси оценка</Button>39 <Button style={{float:'right'}} type={'primary'} onClick={()=>props.user.isConfirmed ? props.setVisible(true) : notification['error']({message: <p>Мора да го потврдите вашиот мејл за да оставите оценка. <a href={'/confirm-email'}>Потврдете го тука</a></p>})}>Внеси оценка</Button> 39 40 : <Tooltip title={'Мора да се најавите за да оставите оценка'}><Button style={{float:'right'}} disabled type={'primary'} onClick={()=>props.setVisible(true)}>Внеси оценка</Button></Tooltip>) 40 41 : '' -
frontend/src/FrontPage.js
r899b19d ra26f6a1 1 1 import React, {useState, useEffect} from 'react' 2 2 import {Header} from "./Header"; 3 import { useNavigate} from "react-router-dom";3 import {Link, useNavigate} from "react-router-dom"; 4 4 import {Button, Card, DatePicker, Form, Image, Input, Modal, notification, Rate, Spin} from "antd"; 5 5 import placeholderImage from '../src/Assets/placeholder.png' … … 26 26 },[]) 27 27 28 useEffect(()=>{ 29 if(user && !user.isConfirmed) { 30 notification['warning']({ 31 message: <p>Вашиот емаил не е потврден. <a href={'/confirm-email'}>Потврдете го тука</a></p> 32 }); 33 } 34 },[user]) 35 28 36 const saveNewReview = data =>{ 29 37 setSaveModalLoading(true) 30 axios.post(env.api + 'Reviews',data,{ headers: {Authorization: sessionStorage.getItem('Auth')}}).then(res=>{38 axios.post(env.api + 'Reviews',data,{ headers: {Authorization: localStorage.getItem('Auth')}}).then(res=>{ 31 39 setNewReviewModal(false) 32 40 setSaveModalLoading(false) -
frontend/src/index.js
r899b19d ra26f6a1 6 6 const root = ReactDOM.createRoot(document.getElementById('root')); 7 7 root.render( 8 <React.StrictMode>9 8 <App /> 10 </React.StrictMode>11 9 ); -
resTools_backend/backend/Controllers/UsersController.cs
r899b19d ra26f6a1 41 41 }catch (Exception ex){ return null; } 42 42 User user = await _userService.GetById(userId); 43 return new AuthenticateResponse() { Email=user.Email, Id = user.Id}; 43 return new AuthenticateResponse() { Email=user.Email, Id = user.Id, IsAdmin = user.IsAdmin, IsConfirmed = user.IsConfirmed}; 44 } 45 46 [HttpPost("confirm")] 47 public async Task ConfirmEmail() 48 { 49 int userId = 0; 50 try 51 { 52 userId = (int)this.HttpContext.Items["User"]; 53 } 54 catch (Exception ex) { return; } 55 User user = await _userService.GetById(userId); 56 await _userService.SendEmailConfirmation(user.Email); 57 } 58 59 [HttpPost("reset")] 60 public async Task ResetPassword(string email) 61 { 62 await _userService.SendPasswordReset(email); 63 } 64 65 [HttpPost("confirmed")] 66 public async Task ConfirmedEmail(string validityString) 67 { 68 int userId = 0; 69 try 70 { 71 userId = (int)this.HttpContext.Items["User"]; 72 } 73 catch (Exception ex) { return; } 74 User user = await _userService.GetById(userId); 75 await _userService.ConfirmEmail(user, validityString); 76 } 77 78 [HttpPost("reseted")] 79 public async Task ResetedPassword(string validityString, string newPassword) 80 { 81 await _userService.ResetPassword(validityString, newPassword); 44 82 } 45 83 -
resTools_backend/backend/DTOs/AuthenticateResponse.cs
r899b19d ra26f6a1 15 15 [JsonProperty] 16 16 public bool IsAdmin { get; set; } 17 [JsonProperty] 18 public bool IsConfirmed { get; set; } 17 19 } -
resTools_backend/backend/Entities/User.cs
r899b19d ra26f6a1 9 9 public string Password { get; set; } 10 10 public bool IsAdmin { get; set; } 11 public bool IsConfirmed { get; set; } 12 public string? ConfirmationURL { get; set; } 13 public DateTime? ConfirmationValidTo { get; set; } 14 public string? PasswordResetURL { get; set; } 15 public DateTime? PasswordResetValidTo { get; set; } 11 16 public virtual Restaurant Restaurant { get; set; } 12 17 } -
resTools_backend/backend/Migrations/DataContextModelSnapshot.cs
r899b19d ra26f6a1 176 176 NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); 177 177 178 b.Property<string>("ConfirmationURL") 179 .HasColumnType("text"); 180 181 b.Property<DateTime?>("ConfirmationValidTo") 182 .HasColumnType("timestamp with time zone"); 183 178 184 b.Property<string>("Email") 179 185 .IsRequired() … … 183 189 .HasColumnType("boolean"); 184 190 191 b.Property<bool>("IsConfirmed") 192 .HasColumnType("boolean"); 193 185 194 b.Property<string>("Password") 186 195 .IsRequired() 187 196 .HasColumnType("text"); 197 198 b.Property<string>("PasswordResetURL") 199 .HasColumnType("text"); 200 201 b.Property<DateTime?>("PasswordResetValidTo") 202 .HasColumnType("timestamp with time zone"); 188 203 189 204 b.HasKey("Id"); -
resTools_backend/backend/Program.cs
r899b19d ra26f6a1 1 1 using backend.Data; 2 using backend.Email; 2 3 using backend.Helpers; 3 4 using backend.Services; … … 50 51 builder.Services.AddScoped<ISmsService, SmsService>(); 51 52 53 builder.Services.AddTransient<IEmailSender, EmailSender>(); 54 52 55 builder.Services.AddDbContext<DataContext>(p => p.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); 53 56 -
resTools_backend/backend/Services/UserService.cs
r899b19d ra26f6a1 1 namespace backend.Services;1 namespace backend.Services; 2 2 3 3 using backend.Data; 4 4 using backend.DTOs; 5 using backend.Email; 5 6 using backend.Entities; 6 7 using backend.Helpers; … … 11 12 using System.IdentityModel.Tokens.Jwt; 12 13 using System.Security.Claims; 14 using System.Security.Cryptography; 15 using System.Text; 13 16 14 17 public interface IUserService … … 17 20 Task<AuthenticateResponse> Register(CreateUserRequest req, bool isFirst); 18 21 Task<User> GetById(int id); 22 Task SendEmailConfirmation(string email); 23 Task SendPasswordReset(string email); 24 Task ConfirmEmail(User user, string checkValid); 25 Task ResetPassword(string checkValid, string password); 19 26 } 20 27 … … 23 30 private readonly AppSettings _appSettings; 24 31 private readonly DataContext _context = null; 32 private readonly IEmailSender _emailSender; 25 33 26 public UserService(IOptions<AppSettings> appSettings, DataContext context )34 public UserService(IOptions<AppSettings> appSettings, DataContext context, IEmailSender emailSender) 27 35 { 28 36 _appSettings = appSettings.Value; 29 37 _context = context; 38 _emailSender = emailSender; 30 39 } 31 40 … … 40 49 var token = generateJwtToken(user); 41 50 42 return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin}; 51 return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin, IsConfirmed = user.IsConfirmed}; 52 } 53 54 public async Task ConfirmEmail(User user, string checkValid) 55 { 56 if(user.ConfirmationURL != checkValid) 57 { 58 throw new Exception("Invalid check"); 59 } 60 if(user.ConfirmationValidTo < DateTime.UtcNow) 61 { 62 throw new Exception("Link expired"); 63 } 64 65 user.IsConfirmed = true; 66 _context.Users.Update(user); 67 await _context.SaveChangesAsync(); 43 68 } 44 69 … … 50 75 public async Task<AuthenticateResponse> Register(CreateUserRequest req, bool isFirst) 51 76 { 52 User user = new User() { Email = req.Email, Password = req.Password, IsAdmin = isFirst };77 User user = new User() { Email = req.Email, Password = req.Password, IsAdmin = isFirst, IsConfirmed = false }; 53 78 await _context.Users.AddAsync(user); 54 79 await _context.SaveChangesAsync(); 55 80 var token = generateJwtToken(user); 56 return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin }; 81 return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin, IsConfirmed = false }; 82 } 83 84 public async Task ResetPassword(string checkValid, string password) 85 { 86 var user = await _context.Users.Where(x => x.PasswordResetURL == checkValid).FirstOrDefaultAsync(); 87 if (user == null) 88 { 89 throw new Exception("Invalid check"); 90 } 91 if (user.PasswordResetValidTo < DateTime.UtcNow) 92 { 93 throw new Exception("Link expired"); 94 } 95 96 user.Password = password; 97 _context.Users.Update(user); 98 await _context.SaveChangesAsync(); 99 } 100 101 public async Task SendEmailConfirmation(string email) 102 { 103 User user = await _context.Users.FirstOrDefaultAsync(x => x.Email == email); 104 user.ConfirmationURL = Guid.NewGuid().ToString(); 105 user.ConfirmationValidTo = DateTime.UtcNow.AddHours(24); 106 _context.Users.Update(user); 107 await _context.SaveChangesAsync(); 108 await _emailSender.SendEmailAsync( 109 "Потврдете го вашиот емаил", 110 "Ве молиме кликнете на следниот линк за да го потврдите вашиот емаил: http://localhost:3000/confirm?id=" + user.ConfirmationURL, 111 email); 112 } 113 114 public async Task SendPasswordReset(string email) 115 { 116 User user = await _context.Users.FirstOrDefaultAsync(x => x.Email == email); 117 user.PasswordResetURL = Guid.NewGuid().ToString(); 118 user.PasswordResetValidTo = DateTime.UtcNow.AddHours(24); 119 _context.Users.Update(user); 120 await _context.SaveChangesAsync(); 121 await _emailSender.SendEmailAsync( 122 "Ресетирајте ја лозинката", 123 "Ве молиме кликнете на следниот линк за да ја ресетирате лозинката: http://localhost:3000/reset?id=" + user.PasswordResetURL, 124 email); 57 125 } 58 126 … … 71 139 return tokenHandler.WriteToken(token); 72 140 } 141 142 private string sha256Hash(String value) 143 { 144 using (SHA256 hash = SHA256.Create()) 145 { 146 return String.Concat(hash 147 .ComputeHash(Encoding.UTF8.GetBytes(value)) 148 .Select(item => item.ToString("x2"))); 149 } 150 } 73 151 } -
resTools_backend/backend/backend.csproj
r899b19d ra26f6a1 1 <Project Sdk="Microsoft.NET.Sdk.Web">1 <Project Sdk="Microsoft.NET.Sdk.Web"> 2 2 3 3 <PropertyGroup> … … 22 22 <PackageReference Include="Npgsql" Version="6.0.3" /> 23 23 <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3" /> 24 <PackageReference Include="SendGrid" Version="9.28.0" /> 24 25 <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> 25 26 <PackageReference Include="Swashbuckle.Core" Version="5.6.0" />
Note:
See TracChangeset
for help on using the changeset viewer.