Skip to content
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

Dev #293

Merged
merged 9 commits into from
Mar 3, 2024
Merged

Dev #293

Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ The game must be responsive :white_check_mark:
- *Major module*: Implement Two-Factor Authentication (2FA) and JWT :white_check_mark:
- **Devops**
- *Major module*: Infrastructure Setup for Log Management :x:
- *Minor module*: Monitoring system :x:
- *Minor module*: Monitoring system :white_check_mark:
- *Major module*: Designing the Backend as Microservices :x:
- **Graphics**
- *Major module*: Use advanced 3D techniques :white_check_mark:
Expand Down
4 changes: 2 additions & 2 deletions backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
# SESSION_COOKIE_SAMESITE = None
# SESSION_COOKIE_SECURE = False
SESSION_COOKIE_SAMESITE = None
SESSION_COOKIE_SECURE = True
# SESSION_COOKIE_SAMESITE = 'Lax'

REST_FRAMEWORK = {
Expand Down
83 changes: 26 additions & 57 deletions backend/user_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
from django_otp import match_token
from email.mime.image import MIMEImage

from django.core.files.storage import default_storage
from django.core.files.images import ImageFile

from .authentication import account_activation_token, is_authenticated
from .serializers import UserRegisterSerializer, UserLoginSerializer, UserSerializer
from .validations import user_registration, is_valid_email, is_valid_password
Expand All @@ -39,6 +42,8 @@
import os
import qrcode
import logging
from io import BytesIO
from PIL import Image

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -157,12 +162,15 @@ class updateProfile(APIView):
def post(self, request):
if request.user.is_authenticated:
data = request.data
if data.get('profile_picture'):
request.user.profile_picture = data.get('profile_picture')
if 'profile_picture' in request.FILES:
if default_storage.exists(request.user.profile_picture.path):
default_storage.delete(request.user.profile_picture.path)
image = ImageFile(request.FILES['profile_picture'])
request.user.profile_picture.save(image.name, image, save=True)
if data.get('email'):
request.user.email = data.get('email')
if data.get('username'):
request.user.username = data.get('username')
request.user.vusername = data.get('username')
if data.get('title'):
request.user.title = data.get('title')
if data.get('AboutMe'):
Expand Down Expand Up @@ -227,15 +235,20 @@ def get(self, request):

username = user_response.json()["login"]
email = user_response.json()["email"]

profile_picture_url = user_response.json()["image"]["versions"]["medium"]
response = requests.get(profile_picture_url)
img = Image.open(BytesIO(response.content))
image_name = os.path.basename(profile_picture_url)
directory = 'profile_pictures/'
save_path = os.path.join(directory, image_name)
img.save(save_path)

intra_lvl = user_response.json()["cursus_users"][1]["level"]
school = user_response.json()["campus"][0]["name"]
ft_url = user_response.json()["url"],
ft_user = True

# with open('output.json', 'w') as f:
# json.dump(user_response.json(), f, indent=4)

titles = user_response.json().get("titles", [])
title = ""
if titles:
Expand All @@ -249,7 +262,7 @@ def get(self, request):
'username': username,
'email': email,
'title': title,
'profile_picture': profile_picture_url,
'profile_picture': save_path.replace('/app/backend/media', ''),
'intra_level': intra_lvl,
'school': school,
'ft_url': ft_url,
Expand Down Expand Up @@ -308,53 +321,6 @@ def post(self, request):
return response


class updateProfile(APIView):
permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (BlacklistCheckJWTAuthentication,)
##
def post(self, request):
if request.user.is_authenticated:
data = request.data
if data.get('profile_picture'):
request.user.profile_picture = data.get('profile_picture')
if data.get('email'):
request.user.email = data.get('email')
if data.get('username'):
request.user.username = data.get('username')
if data.get('title'):
request.user.title = data.get('title')
if data.get('AboutMe'):
request.user.AboutMe = data.get('AboutMe')
if data.get('school'):
request.user.school = data.get('school')
if data.get('wins'):
request.user.wins = data.get('wins')
if data.get('losses'):
request.user.losses = data.get('losses')
if data.get('win_rate'):
if request.user.total_matches == 0:
request.user.win_rate = 0
else:
request.user.win_rate = request.user.wins / request.user.total_matches
if data.get('total_matches'):
request.user.total_matches = data.get('total_matches')
if data.get('match_history'):
history = request.user.match_history
if history is None:
history = []
history.append(data.get('match_history'))
request.user.match_history = history
if data.get('TwoFA'):
request.user.TwoFA = data.get('TwoFA')
if data.get('password'):
request.user.set_password(data.get('password'))
request.user.save()

return Response({"detail": "Profile updated"}, status=status.HTTP_200_OK)
else:
return Response({"detail": "No active user session"}, status=status.HTTP_400_BAD_REQUEST)


class activateTwoFa(APIView):
permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (BlacklistCheckJWTAuthentication,)
Expand Down Expand Up @@ -407,21 +373,24 @@ def post(self, request):
device = request.user.totpdevice_set.create(confirmed=True)
current_site = get_current_site(request)

# Generate QR code
img = qrcode.make(device.config_url)
# img.save("qrcode.png")

mail_subject = 'DJANGO OTP DEMO'
byte_stream = BytesIO()
img.save(byte_stream, format='PNG')
byte_stream.seek(0)

mail_subject = 'Iiinteernaaal Pooiinteeer Vaariaaablee'
message = f"Hello {request.user},\n\nYour QR Code is: <img src='cid:image1'>"
to_email = request.user.email
email = EmailMessage(
mail_subject, message, to=[to_email]
)

# Attach image
fp = open('qrcode.png', 'rb')
msg_image = MIMEImage(fp.read())
fp.close()
msg_image = MIMEImage(byte_stream.getvalue())
msg_image.add_header('Content-ID', '<image1>')
email.attach(msg_image)

Expand Down
2 changes: 2 additions & 0 deletions docker/frontend/frontend.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ RUN npm install -g serve

RUN npm install

RUN npm ci

COPY . .

EXPOSE 3000
Expand Down
4 changes: 4 additions & 0 deletions docker/nginx/config/backend.conf
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ server {
add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
}

location /media/ {
alias /app/backend/media/;
}

location ~ ^/static/js/main\.[a-f0-9]+\.js$ {
autoindex on;
alias /app/frontend/build/static/js/;
Expand Down
177 changes: 177 additions & 0 deletions frontend/src/components/API.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import axios from "axios";
import Cookies from "js-cookie";

export const fetchUserDetails = async (
setUserDetails,
setUsername,
setImageUrl,
redirectUri
) => {
const response = await getUserDetails({ redirectUri });
setUserDetails(response.data.user);
setUsername(response.data.user.username);
if (response.data.user.profile_picture) {
let url = response.data.user.profile_picture;
setImageUrl(url);
}
};

export const getUserDetails = async ({ redirectUri }) => {
let response = {};
try {
const token = Cookies.get("access");
response = await axios.get(`${redirectUri}/api/profile`, {
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
});
} catch (error) {
console.log(error);
}
return response;
};

export const changeUsername = async ({ redirectUri, username }) => {
let response = {};
try {
const token = Cookies.get("access");
response = await axios.post(
`${redirectUri}/api/updateProfile`,
{ username: username },
{
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
}
);
} catch (error) {
console.log(error);
}
return response;
};

export const changeAbout = async ({ redirectUri, about }) => {
let response = {};
try {
const token = Cookies.get("access");
response = await axios.post(
`${redirectUri}/api/updateProfile`,
{ AboutMe: about },
{
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
}
);
} catch (error) {
console.log(error);
}
return response;
};

export const changePassword = async ({ redirectUri, password }) => {
let response = {};
try {
const token = Cookies.get('access');
response = await axios.post(
`${redirectUri}/api/updateProfile`,
{ password: password },
{
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
}
);
} catch (error) {
console.log(error);
}
return response;
};

export const changeAvatar = async ({ redirectUri, file }) => {
let response = {};
try {
const token = Cookies.get('access');
const formData = new FormData();
formData.append('profile_picture', file);

response = await axios.post(
`${redirectUri}/api/updateProfile`,
formData,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'multipart/form-data',
},
withCredentials: true,
}
);
} catch (error) {
console.log(error);
}
return response;
};

export const activate2FA = async ({ redirectUri }) => {
let response = {};
try {
const token = Cookies.get("access");
response = await axios.post(
`${redirectUri}/api/activateTwoFa`,
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
}
);
} catch (error) {
console.log(error);
}
return response;
};

export const deactivate2FA = async ({ redirectUri }) => {
let response = {};
try {
const token = Cookies.get("access");
response = await axios.post(
`${redirectUri}/api/deactivateTwoFa`,
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
}
);
} catch (error) {
console.log(error);
}
return response;
};

export const deleteAccount = async ({ redirectUri }) => {
let response = {};
try {
const token = Cookies.get("access");
response = await axios.post(
`${redirectUri}/api/accountDeletion`,
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
}
);
} catch (error) {
console.log(error);
}
return response;
};
2 changes: 1 addition & 1 deletion frontend/src/components/home/Readme.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ function Readme() {
<Major /> Infrastructure Setup for Log Management ❌
</li>
<li>
<Minor /> Monitoring system
<Minor /> Monitoring system <GreenCheck />
</li>
<li>
<Major /> Designing the Backend as Microservices ❌
Expand Down
Loading