Skip to content

Commit

Permalink
Merge pull request #62 from GTZ-STUDIO/develop
Browse files Browse the repository at this point in the history
Develop to master for Sprint_2
  • Loading branch information
xinnie-ca committed Feb 28, 2024
2 parents cd046d6 + 3c20a84 commit a0ce714
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 46 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ReactTesting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Set up Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
Expand Down
8 changes: 6 additions & 2 deletions lvlgg_backend/account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def create_superuser(

class Client(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=50, unique=True, null=True)
email = models.EmailField()
email = models.EmailField(unique=True)
firstname = models.CharField(max_length=30)
lastname = models.CharField(max_length=30)
is_active = models.BooleanField(default=True)
Expand All @@ -67,4 +67,8 @@ class Client(AbstractBaseUser, PermissionsMixin):
REQUIRED_FIELDS = ["firstname", "lastname", "email", "password"]

def __str__(self):
return self.username
return self.username

def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
1 change: 0 additions & 1 deletion lvlgg_backend/account/serializer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# serializers.py
from rest_framework import serializers

from .models import Client
Expand Down
21 changes: 21 additions & 0 deletions lvlgg_backend/account/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def test_sign_up(self):
self.assertEqual(response.status_code, 400)
payload["lastname"] = "tom"

payload["email"] = "wrong_format"
response = self.client.post(url, payload, content_type="application/json")
self.assertEqual(response.status_code, 400)

def test_delete_user(self):
payload = {
"username": "user1",
Expand Down Expand Up @@ -182,6 +186,23 @@ def test_sign_in(self):
response = self.client.post(url, payload, content_type="application/json")
self.assertEqual(response.status_code, 400)

def test_sign_out(self):

# User Sign in
payload = {
"username": "user1",
"password": "12345",
}
url = "/account/signin/"
response = self.client.post(url, payload, content_type="application/json")
self.assertEqual(response.status_code, 200)

self.assertEqual(response.wsgi_request.user.is_authenticated, True)
url = reverse("sign_out")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.wsgi_request.user.is_authenticated, False)


class ClientListTestCase(TestCase):
def setUp(self):
Expand Down
1 change: 1 addition & 0 deletions lvlgg_backend/account/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .views import ClientDetailView, ClientListView, SignInView

urlpatterns = [
path("signout/", ClientDetailView.as_view(), name="sign_out"),
path("", ClientListView.as_view(), name="user_list"),
path("delete/<int:pk>/", ClientDetailView.as_view()),
path("<int:pk>/", ClientDetailView.as_view()),
Expand Down
79 changes: 45 additions & 34 deletions lvlgg_backend/account/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import json

from django.contrib.auth import authenticate, login
from django.contrib.auth import authenticate, login, logout
from django.core.exceptions import ValidationError
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
Expand All @@ -14,7 +12,6 @@


class ClientDetailView(APIView):
# TODO: update user info
def post(self, request):
"""User sign up
Expand All @@ -34,34 +31,40 @@ def post(self, request):
firstname = data.get("firstname")
lastname = data.get("lastname")
email = data.get("email")
# Sign up required fieldss
if firstname and lastname and username and password and email:

# User or email exist in the db already, refuse registration
if (
Client.objects.filter(username=username).exists()
or Client.objects.filter(email=email).exists()
):
try:
# Sign up required fieldss
if firstname and lastname and username and password and email:

# User or email exist in the db already, refuse registration
if (
Client.objects.filter(username=username).exists()
or Client.objects.filter(email=email).exists()
):
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"Error": "Username or email already exist"},
)

Client.objects.create_user(
email=email,
username=username,
password=password,
firstname=firstname,
lastname=lastname,
)
return Response(
status=status.HTTP_200_OK,
data={"success": f"client {username} created"},
)
else:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"Error": "Username or email already exist"},
data={"Error": "Missing required field for createing account"},
)

Client.objects.create_user(
email=email,
username=username,
password=password,
firstname=firstname,
lastname=lastname,
)
return Response(
status=status.HTTP_200_OK,
data={"success": f"client {username} created"},
)
else:
except ValidationError:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"Error": "Missing required field for createing account"},
data={"Error": "Invalid Email Format"},
)

def delete(self, request, pk):
Expand All @@ -83,20 +86,28 @@ def delete(self, request, pk):
data={"Message": f"Client {pk} is deleted successfully"},
)

def get(self, request, pk):
def get(self, request, pk=None):
"""
retrieve a user based on pk
retrieve a client based on pk
or if pk is not provided, it is a log out request
Args:
request (_type_): http request with pk in url
pk (_type_): primary key
Returns:
DRF response, 200 for success or 404 for client does not exist
"""
client = get_object_or_404(Client, pk=pk)
serializer = ClientSerializer(client)
return Response(serializer.data)
# use pk to retrieve a client
if pk != None:
client = get_object_or_404(Client, pk=pk)
serializer = ClientSerializer(client)
return Response(serializer.data)
else:
logout(request=request)
return Response(
status=status.HTTP_200_OK, data={"message": "Log out successfully"}
)


def put(self, request, pk):
data = request.data
Expand Down
5 changes: 5 additions & 0 deletions lvlgg_backend/lvlgg_backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,8 @@
CORS_ALLOWED_ORIGINS = [
'http://localhost:3000',
]

CORS_ORIGIN_WHITELIST = [
'http://localhost:3000',
]

23 changes: 18 additions & 5 deletions lvlgg_frontend/src/Components/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Link} from 'react-router-dom';
import './Navbar.css';
import { Button } from './Button';
import { AuthContext } from '../Contexts/AuthContext';
import axios from 'axios';

function Navbar() {
const [click, setClick] = useState(false)
Expand All @@ -20,12 +21,24 @@ const closeDropdown = () => {
setIsDropdownOpen(false);
};

const handleSignOut = () => {
//localStorage.removeItem('token');
setIsSignedIn(false);
closeDropdown();
const handleSignOut = () => {
axios.get("http://localhost:8000/account/signout/")
.then(response => {
if (response.status === 200) {
console.log('Successful logout:', response.data);
alert(JSON.stringify(response.data));
setIsSignedIn(false);
closeDropdown();
} else {
// Handle error
console.error(response.data.message);
}
})
.catch(error => {
// Handle error
console.error(error);
});
};

return (
<>
<nav className='navbar'>
Expand Down
2 changes: 1 addition & 1 deletion lvlgg_frontend/src/Components/Pages/SignIn.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const SignIn = () => {
}
})
.catch(error => {
if (error.response.status === 401) {
if (error.response && (error.response.status === 401 || error.response.status === 400)) {
console.error('error:', error.response.data);
alert(JSON.stringify(error.response.data));
}
Expand Down
20 changes: 19 additions & 1 deletion lvlgg_frontend/src/Components/__tests__/SignIn.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,28 @@ import '@testing-library/jest-dom/extend-expect';
import { BrowserRouter as Router } from 'react-router-dom';
import SignIn from '../../Components/Pages/SignIn';
import axios from 'axios';
import { AuthProvider } from '../../Contexts/AuthContext';
import { AuthContext, AuthProvider } from '../../Contexts/AuthContext.js';

jest.mock('axios');

test('renders SignIn component', () => {
const mockContextValue = { setIsSignedIn: jest.fn() };

render(
<Router> {/* Wrap your component with BrowserRouter */}
<AuthContext.Provider value={mockContextValue}>
<SignIn />
</AuthContext.Provider>
</Router>
);

const usernameInput = screen.getByLabelText('Username:');
const passwordInput = screen.getByLabelText('Password:');

expect(usernameInput).toBeInTheDocument();
expect(passwordInput).toBeInTheDocument();
});

test('allows user to sign in', async () => {
render(
<Router> {/* Wrap your component tree with Router */}
Expand Down

0 comments on commit a0ce714

Please sign in to comment.