Skip to content

Commit

Permalink
Merge pull request #31 from MomHelpMe/feat/store-language-in-db
Browse files Browse the repository at this point in the history
Feat/store language in db
  • Loading branch information
seungwonme authored Aug 29, 2024
2 parents c4cf49e + 1e1fcf6 commit c132ddf
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 62 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# OS
.DS_Store

# Nginx
default.conf

# vite
node_modules/

Expand Down
2 changes: 1 addition & 1 deletion backend/transcendence/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

setup_logging(level=logging.INFO)
setup_logging(level=logging.DEBUG)
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

Expand Down
10 changes: 9 additions & 1 deletion backend/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@


class User(models.Model):
LANGUAGE_CHOICES = [
(0, "EN"),
(1, "KR"),
(2, "JP"),
]

user_id = models.IntegerField(primary_key=True)
nickname = models.CharField(max_length=255)
email = models.EmailField(max_length=255)
Expand All @@ -10,9 +16,10 @@ class User(models.Model):
is_online = models.BooleanField(default=False)
win = models.IntegerField(default=0)
lose = models.IntegerField(default=0)
language = models.IntegerField(choices=LANGUAGE_CHOICES, default=0)

def __str__(self):
return self.nickname + '#' + str(self.user_id)
return self.nickname + "#" + str(self.user_id)


class Friend(models.Model):
Expand All @@ -39,6 +46,7 @@ def __str__(self):
user2_name = self.user2.nickname if self.user2 else "Unknown"
return f"Game {self.game_id}: {user1_name} vs {user2_name}"


class Tournament(models.Model):
tournament_id = models.AutoField(primary_key=True)
game_id1 = models.ForeignKey(Game, null=True, on_delete=models.SET_NULL, related_name="tournaments_as_game1")
Expand Down
16 changes: 4 additions & 12 deletions backend/users/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ class Meta:
model = User
fields = ["user_id", "nickname", "img_url", "is_2FA", "is_online", "win", "lose"]

class LanguageSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["language"]

class FriendSerializer(serializers.ModelSerializer):
class Meta:
Expand All @@ -16,15 +20,3 @@ class Meta:

class FriendRequestSerializer(serializers.Serializer):
user_id = serializers.IntegerField()


class GameSerializer(serializers.ModelSerializer):
class Meta:
model = Game
fields = ["game_id", "game_type", "user1", "user2", "score1", "score2", "start_timestamp", "end_timestamp"]


class TournamentSerializer(serializers.ModelSerializer):
class Meta:
model = Tournament
fields = ["name", "date", "winner"]
2 changes: 2 additions & 0 deletions backend/users/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
from .views import (
UserDetailView,
FriendDetailView,
LanguageView,
get_user,
get_user_list,
)

urlpatterns = [
path('me/', UserDetailView.as_view()),
path('friends/', FriendDetailView.as_view()),
path('language/', LanguageView.as_view()),
path('user/', get_user_list),
path('user/<int:pk>/', get_user),
]
33 changes: 32 additions & 1 deletion backend/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import User, Friend, Game, Tournament
from .serializers import UserSerializer, FriendSerializer, FriendRequestSerializer, GameSerializer, TournamentSerializer
from .serializers import (
UserSerializer,
LanguageSerializer,
FriendSerializer,
FriendRequestSerializer,
)
from login.views import decode_jwt
from drf_yasg.utils import swagger_auto_schema

Expand Down Expand Up @@ -56,6 +61,32 @@ def delete(self, request):
return response


class LanguageView(APIView):
def get(self, request):
payload = decode_jwt(request)
if not payload:
return Response(status=status.HTTP_401_UNAUTHORIZED)

user = get_object_or_404(User, pk=payload.get("id"))
return Response({"language": user.language})

@swagger_auto_schema(request_body=LanguageSerializer, responses={200: LanguageSerializer()})
def put(self, request):
payload = decode_jwt(request)
if not payload:
return Response(status=status.HTTP_401_UNAUTHORIZED)

user = get_object_or_404(User, pk=payload.get("id"))
print(request.data.get("language"))
serializer = LanguageSerializer(user, data=request.data, partial=True)

if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class FriendDetailView(APIView):
def get(self, request):
payload = decode_jwt(request)
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ class App {
constructor() {
this.app = document.querySelector("#app");
this.lan = { value: 0 };
console.log("start!!");
console.log(this.lan);
}
}

Expand Down
20 changes: 18 additions & 2 deletions frontend/src/components/2FA.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,24 @@ export class TwoFA extends Component {
.then(data => {
if (data) {
if (data.success) {
console.log("code good!");
changeUrl('/main'); // 메인 페이지로 이동
// API!!! jwt가 있으면 해당 유저의 데이터베이스에서 언어 번호 (0 or 1 or 2) 얻어오기
fetch("https://localhost:443/api/language/", {
method: 'GET',
credentials: 'include', // 쿠키를 포함하여 요청 (사용자 인증 필요 시)
})
.then(response => {
if (!response.ok){
changeUrl("/");
return null;
}
return response.json();
})
.then(data => {
if (data){
this.props.lan.value = data.language;
changeUrl('/main'); // 메인 페이지로 이동
}
});
} else {
messageElement.textContent = "Invalid code. Please try again.";
messageElement.classList.remove('text-success');
Expand Down
51 changes: 39 additions & 12 deletions frontend/src/components/Main-Menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,14 @@ export class Menu extends Component {
0: {
gameMenuTexts: ["Local Game", "Multi Game", "Tournament"],
userMenuTexts: ["Friends", "Profile", "Logout"],
lanText: "Change Language"
},
1: {
gameMenuTexts: ["로컬 게임", "멀티 게임", "토너먼트"],
userMenuTexts: ["친구", "프로필", "로그아웃"],
lanText: "언어 변경"
},
2: {
gameMenuTexts: ["ローカルゲーム", "マルチゲーム", "トーナメント"],
userMenuTexts: ["友達", "プロフィール", "ログアウト"],
lanText: "言語を変更"
}
};

Expand All @@ -36,7 +33,9 @@ export class Menu extends Component {

return `
<div id="menuBox">
<div id="lanButton">${translations.lanText}</div>
<div id="enButton">English</div>
<div id="koButton">한국어</div>
<div id="jpButton">日本語</div>
<ul id="gameMenu"></ul>
<ul id="userMenu"></ul>
</div>
Expand All @@ -47,27 +46,55 @@ export class Menu extends Component {
new List(document.querySelector("ul#gameMenu"), { className: "gameMode", ids: ["LocalGame", "MultiGame", "Tournament"], contents: this.translations.gameMenuTexts});
new List(document.querySelector("ul#userMenu"), { className: "showInfo", ids: ["Friends", "Profile", "Logout"], contents: this.translations.userMenuTexts});
}

setEvent () {

this.addEvent('click', '#Friends', () => {
changeUrl("/main/friends");
});

this.addEvent('click', '#LocalGame', () => {
changeUrl(`/game/local/${this.uid}`);
});

this.addEvent('click', "#MultiGame", () => {
changeUrl("/main/matching");
});

this.addEvent('click', "#Tournament", () => {
changeUrl("/main/tournament");
});

this.addEvent('click', '#lanButton', () => {
this.props.lan.value = (this.props.lan.value + 1) % 3;
changeUrl("/main")

function storeLang(value) {
fetch("https://localhost:443/api/language/", {
method: 'PUT',
credentials: 'include', // 쿠키를 포함하여 요청 (사용자 인증 필요 시)
headers: {
'Content-Type': 'application/json' // JSON 데이터임을 명시
},
body: JSON.stringify({
language: value
})
})
.then(response => {
if (!response.ok) changeUrl("/");
})
changeUrl("/main");
}

this.addEvent('click', '#enButton', () => {
this.props.lan.value = 0;
storeLang(this.props.lan.value);
});

this.addEvent('click', '#koButton', () => {
this.props.lan.value = 1;
storeLang(this.props.lan.value);
});

this.addEvent('click', '#jpButton', () => {
this.props.lan.value = 2;
storeLang(this.props.lan.value);
});

this.addEvent('click', '#Profile', () => {
Expand Down
38 changes: 36 additions & 2 deletions frontend/src/core/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,25 @@ export async function parsePath(path) {
return changeUrl("/", false);
});
} else {
return changeUrl("/main", false);
// API!!! jwt가 있으면 해당 유저의 데이터베이스에서 언어 번호 (0 or 1 or 2) 얻어오기
fetch("https://localhost:443/api/language/", {
method: 'GET',
credentials: 'include', // 쿠키를 포함하여 요청 (사용자 인증 필요 시)
})
.then(response => {
if (!response.ok){
changeUrl("/");
return null;
}
return response.json();
})
.then(data => {
if (data){
console.log(data.language);
root.lan.value = data.language;
changeUrl('/main'); // 메인 페이지로 이동
}
});
}
}
else return changeUrl("/", false);
Expand Down Expand Up @@ -136,7 +154,23 @@ export const initializeRouter = () => {
window.addEventListener("popstate", async () => {
await parsePath(window.location.pathname);
});
parsePath(window.location.pathname);
fetch("https://localhost:443/api/language/", {
method: 'GET',
credentials: 'include', // 쿠키를 포함하여 요청 (사용자 인증 필요 시)
})
.then(response => {
if (!response.ok){
console.log("so bad");
return null;
}
return response.json();
})
.then(data => {
if (data){
root.lan.value = data.language;
}
parsePath(window.location.pathname);
});
};

async function checkAuth() {
Expand Down
57 changes: 54 additions & 3 deletions frontend/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,65 @@ div#menuBox {
justify-content: center;
}

div#lanButton {

div#enButton {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-weight: 400;
border-radius: 10px;
width: 100px;
height: 50px;
bottom: 30px;
right: 270px;
font-size: 17px;
border-radius: 50px;
color: white;
cursor: pointer;
background: #357ABD;
box-shadow: 0 0 0 rgba(0, 0, 0, 0); /* 기본 상태에서 그림자 없음 */
transition: box-shadow 0.3s ease, transform 0.3s ease;
}

div#enButton:hover {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); /* 호버 시 더 깊은 그림자 */
transform: translateY(-2px); /* 살짝 위로 이동 */
}

div#koButton {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-weight: 400;
border-radius: 10px;
width: 160px;
width: 100px;
height: 50px;
bottom: 30px;
right: 150px;
font-size: 17px;
border-radius: 50px;
color: white;
cursor: pointer;
background: #357ABD;
box-shadow: 0 0 0 rgba(0, 0, 0, 0); /* 기본 상태에서 그림자 없음 */
transition: box-shadow 0.3s ease, transform 0.3s ease;
}

div#koButton:hover {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); /* 호버 시 더 깊은 그림자 */
transform: translateY(-2px); /* 살짝 위로 이동 */
}

div#jpButton {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-weight: 400;
border-radius: 10px;
width: 100px;
height: 50px;
bottom: 30px;
right: 30px;
Expand All @@ -194,7 +245,7 @@ div#lanButton {
transition: box-shadow 0.3s ease, transform 0.3s ease;
}

div#lanButton:hover {
div#enButton:hover {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); /* 호버 시 더 깊은 그림자 */
transform: translateY(-2px); /* 살짝 위로 이동 */
}
Expand Down
Loading

0 comments on commit c132ddf

Please sign in to comment.